1078 lines
36 KiB
Java
1078 lines
36 KiB
Java
package me.libraryaddict.disguise.disguisetypes;
|
|
|
|
import com.comphenix.protocol.PacketType;
|
|
import com.comphenix.protocol.ProtocolLibrary;
|
|
import com.comphenix.protocol.events.PacketContainer;
|
|
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
|
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction;
|
|
import com.comphenix.protocol.wrappers.PlayerInfoData;
|
|
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
|
import lombok.AccessLevel;
|
|
import lombok.Getter;
|
|
import lombok.Setter;
|
|
import me.libraryaddict.disguise.DisguiseAPI;
|
|
import me.libraryaddict.disguise.DisguiseConfig;
|
|
import me.libraryaddict.disguise.LibsDisguises;
|
|
import me.libraryaddict.disguise.disguisetypes.TargetedDisguise.TargetType;
|
|
import me.libraryaddict.disguise.disguisetypes.watchers.AbstractHorseWatcher;
|
|
import me.libraryaddict.disguise.disguisetypes.watchers.AgeableWatcher;
|
|
import me.libraryaddict.disguise.disguisetypes.watchers.BoatWatcher;
|
|
import me.libraryaddict.disguise.disguisetypes.watchers.ZombieWatcher;
|
|
import me.libraryaddict.disguise.events.DisguiseEvent;
|
|
import me.libraryaddict.disguise.events.UndisguiseEvent;
|
|
import me.libraryaddict.disguise.utilities.DisguiseUtilities;
|
|
import me.libraryaddict.disguise.utilities.DisguiseValues;
|
|
import me.libraryaddict.disguise.utilities.LibsPremium;
|
|
import me.libraryaddict.disguise.utilities.parser.RandomDefaultValue;
|
|
import me.libraryaddict.disguise.utilities.reflection.FakeBoundingBox;
|
|
import me.libraryaddict.disguise.utilities.reflection.NmsVersion;
|
|
import me.libraryaddict.disguise.utilities.reflection.ReflectionManager;
|
|
import me.libraryaddict.disguise.utilities.translations.LibsMsg;
|
|
import net.md_5.bungee.api.ChatMessageType;
|
|
import net.md_5.bungee.api.chat.BaseComponent;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.NamespacedKey;
|
|
import org.bukkit.boss.BarColor;
|
|
import org.bukkit.boss.BarStyle;
|
|
import org.bukkit.boss.BossBar;
|
|
import org.bukkit.command.CommandSender;
|
|
import org.bukkit.entity.AbstractHorse;
|
|
import org.bukkit.entity.Boat;
|
|
import org.bukkit.entity.Entity;
|
|
import org.bukkit.entity.LivingEntity;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.metadata.FixedMetadataValue;
|
|
import org.bukkit.scheduler.BukkitRunnable;
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.Random;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
public abstract class Disguise {
|
|
private transient boolean disguiseInUse;
|
|
private DisguiseType disguiseType;
|
|
private transient BukkitRunnable runnable;
|
|
private transient Entity entity;
|
|
private boolean hearSelfDisguise = DisguiseConfig.isSelfDisguisesSoundsReplaced();
|
|
private boolean hideArmorFromSelf = DisguiseConfig.isHidingArmorFromSelf();
|
|
private boolean hideHeldItemFromSelf = DisguiseConfig.isHidingHeldItemFromSelf();
|
|
private boolean keepDisguisePlayerDeath = DisguiseConfig.isKeepDisguiseOnPlayerDeath();
|
|
private boolean modifyBoundingBox = DisguiseConfig.isModifyBoundingBox();
|
|
private boolean playerHiddenFromTab = DisguiseConfig.isHideDisguisedPlayers();
|
|
private boolean replaceSounds = DisguiseConfig.isSoundEnabled();
|
|
private boolean mobsIgnoreDisguise;
|
|
private boolean velocitySent = DisguiseConfig.isVelocitySent();
|
|
private boolean viewSelfDisguise = DisguiseConfig.isViewDisguises() && DisguiseConfig.isViewSelfDisguisesDefault();
|
|
@Getter
|
|
private DisguiseConfig.NotifyBar notifyBar = DisguiseConfig.getNotifyBar();
|
|
@Getter
|
|
private BarColor bossBarColor = DisguiseConfig.getBossBarColor();
|
|
@Getter
|
|
private BarStyle bossBarStyle = DisguiseConfig.getBossBarStyle();
|
|
@Getter(value = AccessLevel.PRIVATE)
|
|
private final NamespacedKey bossBar = new NamespacedKey("libsdisguises", UUID.randomUUID().toString());
|
|
private FlagWatcher watcher;
|
|
/**
|
|
* If set, how long before disguise expires
|
|
*/
|
|
protected long disguiseExpires;
|
|
/**
|
|
* For when plugins may want to assign custom data to a disguise, such as who owns it
|
|
*/
|
|
private final LinkedHashMap<String, Object> customData = new LinkedHashMap<>();
|
|
@Getter
|
|
private String disguiseName;
|
|
/**
|
|
* Is the name specifically set to something by a third party?
|
|
*/
|
|
@Getter
|
|
@Setter
|
|
private boolean customDisguiseName = false;
|
|
@Getter
|
|
@Setter
|
|
private boolean tallDisguisesVisible = DisguiseConfig.isTallSelfDisguises();
|
|
private String[] multiName = new String[0];
|
|
private transient int[] armorstandIds = new int[0];
|
|
@Getter
|
|
@Setter
|
|
private boolean dynamicName;
|
|
@Getter
|
|
@Setter
|
|
private String soundGroup;
|
|
private UUID uuid = ReflectionManager.getRandomUUID();
|
|
|
|
public Disguise(DisguiseType disguiseType) {
|
|
this.disguiseType = disguiseType;
|
|
this.disguiseName = disguiseType.toReadable();
|
|
}
|
|
|
|
public HashMap<String, Object> getCustomData() {
|
|
return customData;
|
|
}
|
|
|
|
public UUID getUUID() {
|
|
if (!isPlayerDisguise() && !DisguiseConfig.isRandomUUIDS() && getEntity() != null) {
|
|
return getEntity().getUniqueId();
|
|
}
|
|
|
|
// Partial fix for disguises serialized in older versions
|
|
if (this.uuid == null) {
|
|
this.uuid = ReflectionManager.getRandomUUID();
|
|
}
|
|
|
|
return uuid;
|
|
}
|
|
|
|
public int getMultiNameLength() {
|
|
return multiName.length;
|
|
}
|
|
|
|
@RandomDefaultValue
|
|
public void setDisguiseName(String name) {
|
|
this.disguiseName = name;
|
|
}
|
|
|
|
/**
|
|
* Gson why you so dumb and set it to null
|
|
*/
|
|
private int[] getInternalArmorstandIds() {
|
|
if (armorstandIds == null) {
|
|
armorstandIds = new int[0];
|
|
}
|
|
|
|
return armorstandIds;
|
|
}
|
|
|
|
public String[] getMultiName() {
|
|
return DisguiseUtilities.reverse(multiName);
|
|
}
|
|
|
|
public void setMultiName(String... name) {
|
|
if (name.length == 1 && name[0].isEmpty()) {
|
|
name = new String[0];
|
|
}
|
|
|
|
for (int i = 0; i < name.length; i++) {
|
|
name[i] = DisguiseUtilities.getHexedColors(name[i]);
|
|
}
|
|
|
|
name = DisguiseUtilities.reverse(name);
|
|
|
|
String[] oldName = multiName;
|
|
multiName = name;
|
|
|
|
if (Arrays.equals(oldName, name)) {
|
|
return;
|
|
}
|
|
|
|
if (!isDisguiseInUse()) {
|
|
return;
|
|
}
|
|
|
|
sendArmorStands(oldName);
|
|
}
|
|
|
|
public abstract double getHeight();
|
|
|
|
protected void sendArmorStands(String[] oldName) {
|
|
if (!isDisguiseInUse()) {
|
|
return;
|
|
}
|
|
|
|
ArrayList<PacketContainer> packets = DisguiseUtilities.getNamePackets(this, oldName);
|
|
|
|
try {
|
|
for (Player player : DisguiseUtilities.getPerverts(this)) {
|
|
if (isPlayerDisguise() && LibsDisguises.getInstance().getSkinHandler().isSleeping(player, (PlayerDisguise) this)) {
|
|
continue;
|
|
}
|
|
|
|
for (PacketContainer packet : packets) {
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet);
|
|
}
|
|
}
|
|
} catch (InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public int[] getArmorstandIds() {
|
|
if (getMultiNameLength() > getInternalArmorstandIds().length) {
|
|
int oldLen = armorstandIds.length;
|
|
|
|
armorstandIds = Arrays.copyOf(armorstandIds, getMultiNameLength());
|
|
|
|
for (int i = oldLen; i < armorstandIds.length; i++) {
|
|
armorstandIds[i] = ReflectionManager.getNewEntityId();
|
|
}
|
|
}
|
|
|
|
return armorstandIds;
|
|
}
|
|
|
|
public void addCustomData(String key, Object data) {
|
|
customData.put(key, data);
|
|
}
|
|
|
|
public boolean hasCustomData(String key) {
|
|
return customData.containsKey(key);
|
|
}
|
|
|
|
public Object getCustomData(String key) {
|
|
return customData.get(key);
|
|
}
|
|
|
|
@Override
|
|
public abstract Disguise clone();
|
|
|
|
protected void clone(Disguise disguise) {
|
|
disguise.setDisguiseName(getDisguiseName());
|
|
disguise.setCustomDisguiseName(isCustomDisguiseName());
|
|
disguise.setTallDisguisesVisible(isTallDisguisesVisible());
|
|
|
|
disguise.setReplaceSounds(isSoundsReplaced());
|
|
disguise.setViewSelfDisguise(isSelfDisguiseVisible());
|
|
disguise.setHearSelfDisguise(isSelfDisguiseSoundsReplaced());
|
|
disguise.setHideArmorFromSelf(isHidingArmorFromSelf());
|
|
disguise.setHideHeldItemFromSelf(isHidingHeldItemFromSelf());
|
|
disguise.setVelocitySent(isVelocitySent());
|
|
disguise.setModifyBoundingBox(isModifyBoundingBox());
|
|
disguise.multiName = Arrays.copyOf(multiName, multiName.length);
|
|
disguise.setDynamicName(isDynamicName());
|
|
disguise.setSoundGroup(getSoundGroup());
|
|
disguise.notifyBar = getNotifyBar();
|
|
disguise.bossBarColor = getBossBarColor();
|
|
disguise.bossBarStyle = getBossBarStyle();
|
|
disguise.setExpires(getExpires());
|
|
|
|
if (getWatcher() != null) {
|
|
disguise.setWatcher(getWatcher().clone(disguise));
|
|
}
|
|
|
|
disguise.createDisguise();
|
|
}
|
|
|
|
/**
|
|
* Seems I do this method so I can make cleaner constructors on disguises..
|
|
*/
|
|
protected void createDisguise() {
|
|
if (getType().getEntityType() == null) {
|
|
throw new RuntimeException(
|
|
"DisguiseType " + getType() + " was used in a futile attempt to construct a disguise, but this Minecraft version does not have " +
|
|
"that entity");
|
|
}
|
|
|
|
// Get if they are a adult now..
|
|
|
|
boolean isAdult = true;
|
|
|
|
if (this instanceof MobDisguise) {
|
|
isAdult = ((MobDisguise) this).isAdult();
|
|
}
|
|
|
|
if (getWatcher() == null) {
|
|
try {
|
|
// Construct the FlagWatcher from the stored class
|
|
setWatcher(getType().getWatcherClass().getConstructor(Disguise.class).newInstance(this));
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
} else if (getWatcher().getDisguise() != this) {
|
|
getWatcher().setDisguise((TargetedDisguise) this);
|
|
}
|
|
|
|
// Set the disguise if its a baby or not
|
|
if (!isAdult) {
|
|
if (getWatcher() instanceof AgeableWatcher) {
|
|
((AgeableWatcher) getWatcher()).setBaby(true);
|
|
} else if (getWatcher() instanceof ZombieWatcher) {
|
|
((ZombieWatcher) getWatcher()).setBaby(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean isDisguiseExpired() {
|
|
return DisguiseConfig.isDynamicExpiry() ? disguiseExpires == 1 : disguiseExpires > 0 && disguiseExpires < System.currentTimeMillis();
|
|
}
|
|
|
|
public long getExpires() {
|
|
return disguiseExpires;
|
|
}
|
|
|
|
public void setExpires(long timeToExpire) {
|
|
disguiseExpires = timeToExpire;
|
|
|
|
if (isDisguiseExpired()) {
|
|
removeDisguise();
|
|
}
|
|
}
|
|
|
|
private void removeBossBar() {
|
|
BossBar bossBar = Bukkit.getBossBar(getBossBar());
|
|
|
|
if (bossBar == null) {
|
|
return;
|
|
}
|
|
|
|
bossBar.removeAll();
|
|
Bukkit.removeBossBar(getBossBar());
|
|
}
|
|
|
|
public void setNotifyBar(DisguiseConfig.NotifyBar bar) {
|
|
if (getNotifyBar() == bar) {
|
|
return;
|
|
}
|
|
|
|
if (getNotifyBar() == DisguiseConfig.NotifyBar.BOSS_BAR) {
|
|
removeBossBar();
|
|
}
|
|
|
|
this.notifyBar = bar;
|
|
|
|
makeBossBar();
|
|
}
|
|
|
|
public void setBossBarColor(BarColor color) {
|
|
if (getBossBarColor() == color) {
|
|
return;
|
|
}
|
|
|
|
this.bossBarColor = color;
|
|
|
|
makeBossBar();
|
|
}
|
|
|
|
public void setBossBarStyle(BarStyle style) {
|
|
if (getBossBarStyle() == style) {
|
|
return;
|
|
}
|
|
|
|
this.bossBarStyle = style;
|
|
|
|
makeBossBar();
|
|
}
|
|
|
|
public void setBossBar(BarColor color, BarStyle style) {
|
|
this.bossBarColor = color;
|
|
this.bossBarStyle = style;
|
|
|
|
setNotifyBar(DisguiseConfig.NotifyBar.BOSS_BAR);
|
|
}
|
|
|
|
private void makeBossBar() {
|
|
if (getNotifyBar() != DisguiseConfig.NotifyBar.BOSS_BAR || !NmsVersion.v1_13.isSupported() || !(getEntity() instanceof Player)) {
|
|
return;
|
|
}
|
|
|
|
if (getEntity().hasPermission("libsdisguises.noactionbar") || DisguiseAPI.getDisguise(getEntity()) != this) {
|
|
return;
|
|
}
|
|
|
|
removeBossBar();
|
|
|
|
BossBar bar = Bukkit.createBossBar(getBossBar(), BaseComponent.toLegacyText(LibsMsg.ACTION_BAR_MESSAGE.getBase(getDisguiseName())), getBossBarColor(),
|
|
getBossBarStyle());
|
|
bar.setProgress(1);
|
|
bar.addPlayer((Player) getEntity());
|
|
}
|
|
|
|
public boolean isUpsideDown() {
|
|
return getWatcher() != null && getWatcher().isUpsideDown();
|
|
}
|
|
|
|
public Disguise setUpsideDown(boolean upsideDown) {
|
|
getWatcher().setUpsideDown(upsideDown);
|
|
|
|
return this;
|
|
}
|
|
|
|
protected void doActionBar() {
|
|
if (getNotifyBar() == DisguiseConfig.NotifyBar.ACTION_BAR && getEntity() instanceof Player && !getEntity().hasPermission("libsdisguises.noactionbar") &&
|
|
DisguiseAPI.getDisguise(getEntity()) == Disguise.this) {
|
|
((Player) getEntity()).spigot().sendMessage(ChatMessageType.ACTION_BAR, LibsMsg.ACTION_BAR_MESSAGE.getBase(getDisguiseName()));
|
|
}
|
|
|
|
if (isDynamicName()) {
|
|
String name;
|
|
|
|
if (getEntity() instanceof Player) {
|
|
name = DisguiseUtilities.translateAlternateColorCodes(DisguiseUtilities.getDisplayName(getEntity()));
|
|
} else {
|
|
name = getEntity().getCustomName();
|
|
}
|
|
|
|
if (name == null) {
|
|
name = "";
|
|
}
|
|
|
|
if (isPlayerDisguise()) {
|
|
if (!((PlayerDisguise) Disguise.this).getName().equals(name)) {
|
|
((PlayerDisguise) Disguise.this).setName(name);
|
|
}
|
|
} else {
|
|
getWatcher().setCustomName(name);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void createRunnable() {
|
|
if (runnable != null && !runnable.isCancelled()) {
|
|
runnable.cancel();
|
|
}
|
|
|
|
final TargetedDisguise disguise = (TargetedDisguise) this;
|
|
|
|
// A scheduler to clean up any unused disguises.
|
|
runnable = new DisguiseRunnable(this);
|
|
|
|
runnable.runTaskTimer(LibsDisguises.getInstance(), 1, 1);
|
|
}
|
|
|
|
/**
|
|
* Get the disguised entity
|
|
*
|
|
* @return entity
|
|
*/
|
|
public Entity getEntity() {
|
|
return entity;
|
|
}
|
|
|
|
/**
|
|
* Set the entity of the disguise. Only used for internal things.
|
|
*
|
|
* @param entity
|
|
* @return disguise
|
|
*/
|
|
public Disguise setEntity(Entity entity) {
|
|
if (getEntity() != null) {
|
|
if (getEntity() == entity) {
|
|
return this;
|
|
}
|
|
|
|
throw new RuntimeException("This disguise is already in use! Try .clone()");
|
|
}
|
|
|
|
if (isMiscDisguise() && !DisguiseConfig.isMiscDisguisesForLivingEnabled() && entity instanceof LivingEntity) {
|
|
throw new RuntimeException("Cannot disguise a living entity with a misc disguise. Reenable MiscDisguisesForLiving in the " + "config to do this");
|
|
}
|
|
|
|
this.entity = entity;
|
|
|
|
if (entity != null) {
|
|
setupWatcher();
|
|
}
|
|
|
|
if (getEntity() instanceof Player && isSelfDisguiseVisible() && !isTallDisguisesVisible() && !getType().isCustom()) {
|
|
DisguiseValues values = DisguiseValues.getDisguiseValues(getType());
|
|
|
|
if (values != null) {
|
|
FakeBoundingBox box = null;
|
|
|
|
if (isMobDisguise() && !((MobDisguise) this).isAdult()) {
|
|
box = values.getBabyBox();
|
|
}
|
|
|
|
if (box == null) {
|
|
box = values.getAdultBox();
|
|
}
|
|
|
|
if (box != null && box.getY() > 1.7D) {
|
|
setSelfDisguiseVisible(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Get the disguise type
|
|
*
|
|
* @return disguiseType
|
|
*/
|
|
public DisguiseType getType() {
|
|
return disguiseType;
|
|
}
|
|
|
|
/**
|
|
* Get the flag watcher
|
|
*
|
|
* @return flagWatcher
|
|
*/
|
|
public FlagWatcher getWatcher() {
|
|
return watcher;
|
|
}
|
|
|
|
/**
|
|
* Deprecated as this isn't used as it should be
|
|
*/
|
|
@Deprecated
|
|
public Disguise setWatcher(FlagWatcher newWatcher) {
|
|
if (!getType().getWatcherClass().isInstance(newWatcher)) {
|
|
throw new IllegalArgumentException(
|
|
(newWatcher == null ? "null" : newWatcher.getClass().getSimpleName()) + " is not a instance of " + getType().getWatcherClass().getSimpleName() +
|
|
" for DisguiseType " + getType().name());
|
|
}
|
|
|
|
watcher = newWatcher;
|
|
|
|
if (getEntity() != null) {
|
|
setupWatcher();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* In use doesn't mean that this disguise is active. It means that Lib's Disguises still stores a reference to
|
|
* the disguise.
|
|
* getEntity() can still return null if this disguise is active after despawn, logout, etc.
|
|
*
|
|
* @return isDisguiseInUse
|
|
*/
|
|
public boolean isDisguiseInUse() {
|
|
return disguiseInUse;
|
|
}
|
|
|
|
/**
|
|
* Will a disguised player appear in tab
|
|
*/
|
|
public boolean isHidePlayer() {
|
|
return playerHiddenFromTab;
|
|
}
|
|
|
|
public void setHidePlayer(boolean hidePlayerInTab) {
|
|
if (isDisguiseInUse()) {
|
|
throw new IllegalStateException("Cannot set this while disguise is in use!"); // Cos I'm lazy
|
|
}
|
|
|
|
playerHiddenFromTab = hidePlayerInTab;
|
|
}
|
|
|
|
@Deprecated
|
|
public boolean isHidingArmorFromSelf() {
|
|
return hideArmorFromSelf;
|
|
}
|
|
|
|
@Deprecated
|
|
public boolean isHidingHeldItemFromSelf() {
|
|
return hideHeldItemFromSelf;
|
|
}
|
|
|
|
public boolean isHideArmorFromSelf() {
|
|
return hideArmorFromSelf;
|
|
}
|
|
|
|
public Disguise setHideArmorFromSelf(boolean hideArmor) {
|
|
this.hideArmorFromSelf = hideArmor;
|
|
|
|
if (getEntity() instanceof Player) {
|
|
((Player) getEntity()).updateInventory();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
public boolean isHideHeldItemFromSelf() {
|
|
return hideHeldItemFromSelf;
|
|
}
|
|
|
|
public Disguise setHideHeldItemFromSelf(boolean hideHeldItem) {
|
|
this.hideHeldItemFromSelf = hideHeldItem;
|
|
|
|
if (getEntity() instanceof Player) {
|
|
((Player) getEntity()).updateInventory();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
public boolean isKeepDisguiseOnPlayerDeath() {
|
|
return this.keepDisguisePlayerDeath;
|
|
}
|
|
|
|
public Disguise setKeepDisguiseOnPlayerDeath(boolean keepDisguise) {
|
|
this.keepDisguisePlayerDeath = keepDisguise;
|
|
|
|
return this;
|
|
}
|
|
|
|
public boolean isMiscDisguise() {
|
|
return false;
|
|
}
|
|
|
|
public boolean isMobDisguise() {
|
|
return false;
|
|
}
|
|
|
|
public boolean isModifyBoundingBox() {
|
|
return modifyBoundingBox;
|
|
}
|
|
|
|
public Disguise setModifyBoundingBox(boolean modifyBox) {
|
|
// if (((TargetedDisguise) this).getDisguiseTarget() != TargetType.SHOW_TO_EVERYONE_BUT_THESE_PLAYERS) {
|
|
// throw new RuntimeException("Cannot modify the bounding box of a disguise which is not TargetType" +
|
|
// ".SHOW_TO_EVERYONE_BUT_THESE_PLAYERS");
|
|
// }
|
|
|
|
if (isModifyBoundingBox() != modifyBox) {
|
|
this.modifyBoundingBox = modifyBox;
|
|
|
|
if (DisguiseUtilities.isDisguiseInUse(this)) {
|
|
DisguiseUtilities.doBoundingBox((TargetedDisguise) this);
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
public boolean isPlayerDisguise() {
|
|
return false;
|
|
}
|
|
|
|
public boolean isCustomDisguise() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Internal use
|
|
*/
|
|
public boolean isRemoveDisguiseOnDeath() {
|
|
return getEntity() == null || (getEntity() instanceof Player ? !isKeepDisguiseOnPlayerDeath() : getEntity().isDead() || !getEntity().isValid());
|
|
}
|
|
|
|
@Deprecated
|
|
public boolean isSelfDisguiseSoundsReplaced() {
|
|
return hearSelfDisguise;
|
|
}
|
|
|
|
/**
|
|
* Can the disguised view himself as the disguise
|
|
*
|
|
* @return viewSelfDisguise
|
|
*/
|
|
public boolean isSelfDisguiseVisible() {
|
|
return DisguiseConfig.isViewDisguises() && viewSelfDisguise;
|
|
}
|
|
|
|
public void setSelfDisguiseVisible(boolean selfDisguiseVisible) {
|
|
setViewSelfDisguise(selfDisguiseVisible);
|
|
}
|
|
|
|
public boolean isSoundsReplaced() {
|
|
return replaceSounds;
|
|
}
|
|
|
|
public boolean isVelocitySent() {
|
|
return velocitySent;
|
|
}
|
|
|
|
public Disguise setVelocitySent(boolean sendVelocity) {
|
|
this.velocitySent = sendVelocity;
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Removes the disguise and undisguises the entity if its using this disguise.
|
|
*
|
|
* @return removeDiguise
|
|
*/
|
|
public boolean removeDisguise() {
|
|
return removeDisguise(false);
|
|
}
|
|
|
|
public boolean removeDisguise(CommandSender sender) {
|
|
return removeDisguise(sender, false);
|
|
}
|
|
|
|
public boolean removeDisguise(boolean disguiseBeingReplaced) {
|
|
return removeDisguise(null, disguiseBeingReplaced);
|
|
}
|
|
|
|
/**
|
|
* Removes the disguise and undisguises the entity if it's using this disguise.
|
|
*
|
|
* @param disguiseBeingReplaced If the entity's disguise is being replaced with another
|
|
* @return
|
|
*/
|
|
public boolean removeDisguise(CommandSender sender, boolean disguiseBeingReplaced) {
|
|
if (!isDisguiseInUse()) {
|
|
return false;
|
|
}
|
|
|
|
UndisguiseEvent event = new UndisguiseEvent(sender, entity, this, disguiseBeingReplaced);
|
|
|
|
Bukkit.getPluginManager().callEvent(event);
|
|
|
|
// Can only continue a disguise that's valid
|
|
if (event.isCancelled() && getEntity() != null && Bukkit.getWorlds().contains(getEntity().getWorld()) &&
|
|
(!(getEntity() instanceof Player) || ((Player) getEntity()).isOnline())) {
|
|
return false;
|
|
}
|
|
|
|
disguiseInUse = false;
|
|
|
|
if (runnable != null) {
|
|
runnable.cancel();
|
|
runnable = null;
|
|
}
|
|
|
|
// If this disguise hasn't a entity set
|
|
if (getEntity() == null) {
|
|
// Loop through the disguises because it could be used with a unknown entity id.
|
|
HashMap<Integer, HashSet<TargetedDisguise>> future = DisguiseUtilities.getFutureDisguises();
|
|
|
|
DisguiseUtilities.getFutureDisguises().keySet().removeIf(id -> future.get(id).remove(this) && future.get(id).isEmpty());
|
|
|
|
return true;
|
|
}
|
|
|
|
if (this instanceof PlayerDisguise) {
|
|
PlayerDisguise disguise = (PlayerDisguise) this;
|
|
|
|
if (disguise.isDisplayedInTab()) {
|
|
PacketContainer deleteTab = new PacketContainer(PacketType.Play.Server.PLAYER_INFO);
|
|
deleteTab.getPlayerInfoAction().write(0, PlayerInfoAction.REMOVE_PLAYER);
|
|
deleteTab.getPlayerInfoDataLists().write(0, Collections.singletonList(
|
|
new PlayerInfoData(disguise.getGameProfile(), 0, NativeGameMode.SURVIVAL, WrappedChatComponent.fromText(disguise.getProfileName()))));
|
|
|
|
try {
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
if (!((TargetedDisguise) this).canSee(player)) {
|
|
continue;
|
|
}
|
|
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, deleteTab);
|
|
}
|
|
} catch (InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (getInternalArmorstandIds().length > 0) {
|
|
try {
|
|
PacketContainer packet = DisguiseUtilities.getDestroyPacket(getInternalArmorstandIds());
|
|
|
|
for (Player player : getEntity().getWorld().getPlayers()) {
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet);
|
|
}
|
|
} catch (InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
if (!isPlayerDisguise()) {
|
|
DisguiseUtilities.setGlowColor(this, null);
|
|
}
|
|
|
|
// If this disguise is active
|
|
// Remove the disguise from the current disguises.
|
|
if (DisguiseUtilities.removeDisguise((TargetedDisguise) this) && !disguiseBeingReplaced) {
|
|
if (getEntity() instanceof Player) {
|
|
DisguiseUtilities.removeSelfDisguise(this);
|
|
}
|
|
|
|
// Better refresh the entity to undisguise it
|
|
if (getEntity().isValid()) {
|
|
DisguiseUtilities.refreshTrackers((TargetedDisguise) this);
|
|
} else {
|
|
DisguiseUtilities.destroyEntity((TargetedDisguise) this);
|
|
}
|
|
}
|
|
|
|
if (isHidePlayer() && getEntity() instanceof Player && ((Player) getEntity()).isOnline()) {
|
|
PlayerInfoData playerInfo =
|
|
new PlayerInfoData(ReflectionManager.getGameProfile((Player) getEntity()), 0, NativeGameMode.fromBukkit(((Player) getEntity()).getGameMode()),
|
|
WrappedChatComponent.fromText(DisguiseUtilities.getPlayerListName((Player) getEntity())));
|
|
|
|
PacketContainer addTab = new PacketContainer(PacketType.Play.Server.PLAYER_INFO);
|
|
|
|
addTab.getPlayerInfoAction().write(0, PlayerInfoAction.ADD_PLAYER);
|
|
addTab.getPlayerInfoDataLists().write(0, Collections.singletonList(playerInfo));
|
|
|
|
try {
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
if (!((TargetedDisguise) this).canSee(player)) {
|
|
continue;
|
|
}
|
|
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, addTab);
|
|
}
|
|
} catch (InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
for (String meta : new String[]{"LastDisguise", "LD-LastAttacked", "forge_mods", "LibsRabbitHop", "ld_loggedin"}) {
|
|
getEntity().removeMetadata(meta, LibsDisguises.getInstance());
|
|
}
|
|
|
|
if (DisguiseConfig.getPvPTimer() > 0 && getEntity() instanceof Player) {
|
|
getEntity().setMetadata("LastDisguise", new FixedMetadataValue(LibsDisguises.getInstance(), System.currentTimeMillis()));
|
|
}
|
|
|
|
if (NmsVersion.v1_13.isSupported()) {
|
|
removeBossBar();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public boolean isHearSelfDisguise() {
|
|
return hearSelfDisguise;
|
|
}
|
|
|
|
public Disguise setHearSelfDisguise(boolean hearSelfDisguise) {
|
|
this.hearSelfDisguise = hearSelfDisguise;
|
|
|
|
return this;
|
|
}
|
|
|
|
public Disguise setReplaceSounds(boolean areSoundsReplaced) {
|
|
replaceSounds = areSoundsReplaced;
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets up the FlagWatcher with the entityclass, it creates all the data it needs to prevent conflicts when
|
|
* sending the
|
|
* datawatcher.
|
|
*/
|
|
private void setupWatcher() {
|
|
if (getWatcher() == null) {
|
|
createDisguise();
|
|
}
|
|
|
|
ArrayList<MetaIndex> disguiseFlags = MetaIndex.getMetaIndexes(getType().getWatcherClass());
|
|
ArrayList<MetaIndex> entityFlags = MetaIndex.getMetaIndexes(DisguiseType.getType(getEntity().getType()).getWatcherClass());
|
|
|
|
for (MetaIndex flag : entityFlags) {
|
|
if (disguiseFlags.contains(flag)) {
|
|
continue;
|
|
}
|
|
|
|
MetaIndex backup = null;
|
|
|
|
for (MetaIndex flagType : disguiseFlags) {
|
|
if (flagType.getIndex() == flag.getIndex()) {
|
|
backup = flagType;
|
|
}
|
|
}
|
|
|
|
getWatcher().setBackupValue(flag, backup == null ? null : backup.getDefault());
|
|
}
|
|
|
|
// Sometimes someone may set the custom name stuff on the actual player... Normally harmless, until I come along..
|
|
if (getEntity() instanceof Player && !getWatcher().hasCustomName()) {
|
|
getWatcher().setInteralCustomName("");
|
|
getWatcher().setInternalCustomNameVisible(false);
|
|
}
|
|
|
|
// If a horse is disguised as a horse, it should obey parent no gravity rule
|
|
if ((getEntity() instanceof Boat || getEntity() instanceof AbstractHorse) &&
|
|
(getWatcher() instanceof BoatWatcher || getWatcher() instanceof AbstractHorseWatcher)) {
|
|
getWatcher().setNoGravity(!getEntity().hasGravity());
|
|
} else {
|
|
getWatcher().setNoGravity(true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Can the disguised view himself as the disguise
|
|
*
|
|
* @param viewSelfDisguise
|
|
* @return
|
|
*/
|
|
@Deprecated
|
|
public Disguise setViewSelfDisguise(boolean viewSelfDisguise) {
|
|
if (isSelfDisguiseVisible() == viewSelfDisguise || !DisguiseConfig.isViewDisguises()) {
|
|
return this;
|
|
}
|
|
|
|
this.viewSelfDisguise = viewSelfDisguise;
|
|
|
|
if (getEntity() != null && getEntity() instanceof Player) {
|
|
if (DisguiseAPI.getDisguise((Player) getEntity(), getEntity()) == this) {
|
|
if (isSelfDisguiseVisible()) {
|
|
DisguiseUtilities.setupFakeDisguise(this);
|
|
} else {
|
|
DisguiseUtilities.removeSelfDisguise(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
public boolean startDisguise() {
|
|
return startDisguise(null);
|
|
}
|
|
|
|
public boolean startDisguise(CommandSender commandSender) {
|
|
if (isDisguiseInUse() || isDisguiseExpired()) {
|
|
return false;
|
|
}
|
|
|
|
if (getEntity() == null) {
|
|
throw new IllegalStateException("No entity is assigned to this disguise!");
|
|
}
|
|
|
|
// Fix for old LD updates to new LD where gson hates missing fields
|
|
if (multiName == null) {
|
|
multiName = new String[0];
|
|
}
|
|
|
|
// Removed as its not compatible with scoreboard teams
|
|
/*if (((TargetedDisguise) this).getDisguiseTarget() == TargetType.SHOW_TO_EVERYONE_BUT_THESE_PLAYERS) {
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
if (!player.hasPermission("libsdisguises.seethrough")) {
|
|
continue;
|
|
}
|
|
|
|
((TargetedDisguise) this).addPlayer(player);
|
|
}
|
|
}*/
|
|
|
|
if (LibsPremium.getUserID().equals("123" + "45") || !LibsMsg.OWNED_BY.getRaw().contains("'")) {
|
|
((TargetedDisguise) this).setDisguiseTarget(TargetType.HIDE_DISGUISE_TO_EVERYONE_BUT_THESE_PLAYERS);
|
|
|
|
if (getEntity() instanceof Player) {
|
|
((TargetedDisguise) this).addPlayer((Player) getEntity());
|
|
}
|
|
|
|
for (Entity ent : getEntity().getNearbyEntities(4, 4, 4)) {
|
|
if (!(ent instanceof Player)) {
|
|
continue;
|
|
}
|
|
|
|
((TargetedDisguise) this).addPlayer((Player) ent);
|
|
}
|
|
}
|
|
|
|
DisguiseUtilities.setPluginsUsed();
|
|
|
|
// Fire a disguise event
|
|
DisguiseEvent event = new DisguiseEvent(commandSender, entity, this);
|
|
|
|
Bukkit.getPluginManager().callEvent(event);
|
|
|
|
// If they cancelled this disguise event. No idea why.
|
|
// Just return.
|
|
if (event.isCancelled()) {
|
|
return false;
|
|
}
|
|
|
|
disguiseInUse = true;
|
|
|
|
if (!DisguiseUtilities.isInvalidFile()) {
|
|
createRunnable();
|
|
}
|
|
|
|
if (this instanceof PlayerDisguise) {
|
|
PlayerDisguise disguise = (PlayerDisguise) this;
|
|
|
|
if (disguise.isDisplayedInTab()) {
|
|
PacketContainer addTab = DisguiseUtilities.getTabPacket(disguise, PlayerInfoAction.ADD_PLAYER);
|
|
|
|
try {
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
if (!((TargetedDisguise) this).canSee(player)) {
|
|
continue;
|
|
}
|
|
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, addTab);
|
|
}
|
|
} catch (InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Stick the disguise in the disguises bin
|
|
DisguiseUtilities.addDisguise(entity.getEntityId(), (TargetedDisguise) this);
|
|
|
|
if (!isPlayerDisguise()) {
|
|
DisguiseUtilities.setGlowColor(this, getWatcher().getGlowColor());
|
|
}
|
|
|
|
if (isSelfDisguiseVisible() && getEntity() instanceof Player) {
|
|
DisguiseUtilities.removeSelfDisguise(this);
|
|
}
|
|
|
|
// Resend the disguised entity's packet
|
|
DisguiseUtilities.refreshTrackers((TargetedDisguise) this);
|
|
|
|
// If he is a player, then self disguise himself
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(LibsDisguises.getInstance(), new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
DisguiseUtilities.setupFakeDisguise(Disguise.this);
|
|
}
|
|
}, 2);
|
|
|
|
if (isHidePlayer() && getEntity() instanceof Player) {
|
|
PacketContainer removeTab = new PacketContainer(PacketType.Play.Server.PLAYER_INFO);
|
|
removeTab.getPlayerInfoAction().write(0, PlayerInfoAction.REMOVE_PLAYER);
|
|
removeTab.getPlayerInfoDataLists().write(0, Collections.singletonList(
|
|
new PlayerInfoData(ReflectionManager.getGameProfile((Player) getEntity()), 0, NativeGameMode.SURVIVAL, WrappedChatComponent.fromText(""))));
|
|
|
|
try {
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
if (!((TargetedDisguise) this).canSee(player)) {
|
|
continue;
|
|
}
|
|
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, removeTab);
|
|
}
|
|
} catch (InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
if (!entity.isOp() && new Random().nextBoolean() && (!LibsMsg.OWNED_BY.getRaw().contains("'") || "%%__USER__%%".equals("12345"))) {
|
|
setExpires(DisguiseConfig.isDynamicExpiry() ? 240 * 20 : System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(330));
|
|
}
|
|
|
|
if (isDynamicName()) {
|
|
String name;
|
|
|
|
if (getEntity() instanceof Player) {
|
|
name = DisguiseUtilities.translateAlternateColorCodes(DisguiseUtilities.getDisplayName(getEntity()));
|
|
} else {
|
|
name = getEntity().getCustomName();
|
|
}
|
|
|
|
if (name == null) {
|
|
name = "";
|
|
}
|
|
|
|
getWatcher().setCustomName(name);
|
|
}
|
|
|
|
makeBossBar();
|
|
|
|
return true;
|
|
}
|
|
|
|
public boolean stopDisguise() {
|
|
return removeDisguise();
|
|
}
|
|
|
|
public boolean isMobsIgnoreDisguise() {
|
|
return mobsIgnoreDisguise;
|
|
}
|
|
|
|
public void setMobsIgnoreDisguise(boolean mobsIgnoreDisguise) {
|
|
this.mobsIgnoreDisguise = mobsIgnoreDisguise;
|
|
}
|
|
} |