diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/Disguise.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/Disguise.java index 52fe589e..140fa0d3 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/Disguise.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/Disguise.java @@ -116,6 +116,8 @@ public abstract class Disguise { return DisguiseUtilities.reverse(multiName); } + public abstract double getHeight(); + public void setMultiName(String... name) { if (name.length == 1 && name[0].isEmpty()) { name = new String[0]; diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/FlagWatcher.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/FlagWatcher.java index 8904dff5..5f885964 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/FlagWatcher.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/FlagWatcher.java @@ -47,10 +47,12 @@ public class FlagWatcher { private HashMap entityValues = new HashMap<>(); private LibsEquipment equipment; private boolean hasDied; + @Getter private boolean[] modifiedEntityAnimations = new boolean[8]; private transient List watchableObjects; private boolean sleeping; private boolean swimming; + private transient boolean previouslySneaking; public FlagWatcher(Disguise disguise) { this.disguise = (TargetedDisguise) disguise; @@ -150,8 +152,10 @@ public class FlagWatcher { } if (value != null) { - if (isEntityAnimationsAdded() && id == 0) { + if (isEntityAnimationsAdded() && id == MetaIndex.ENTITY_META.getIndex()) { value = addEntityAnimations((byte) value, (byte) watch.getValue()); + + doSneakCheck((Byte) value); } boolean isDirty = watch.getDirtyState(); @@ -175,6 +179,10 @@ public class FlagWatcher { if (!isDirty) { watch.setDirtyState(false); } + + if (id == MetaIndex.ENTITY_META.getIndex()) { + doSneakCheck((Byte) watch.getValue()); + } } newList.add(watch); @@ -207,7 +215,7 @@ public class FlagWatcher { getDisguise().getEntity() instanceof Player) { for (WrappedWatchableObject watch : newList) { // Its a health packet - if (watch.getIndex() == 6) { + if (watch.getIndex() == MetaIndex.LIVING_HEALTH.getIndex()) { Object value = watch.getValue(); if (value instanceof Float) { @@ -236,6 +244,21 @@ public class FlagWatcher { return newList; } + private void doSneakCheck(byte value) { + if (getModifiedEntityAnimations()[1] || !getDisguise().isPlayerDisguise()) { + return; + } + + boolean sneak = (value & 1 << 1) != 0; + + if (sneak == previouslySneaking) { + return; + } + + previouslySneaking = sneak; + updateNameHeight(); + } + @NmsAddedIn(val = NmsVersion.v1_14) public EntityPose getEntityPose() { return getData(MetaIndex.ENTITY_POSE); @@ -255,6 +278,55 @@ public class FlagWatcher { getEquipment().setArmorContents(items); } + protected void updateNameHeight() { + if (!getDisguise().isDisguiseInUse()) { + return; + } + + if (!DisguiseConfig.isArmorstandsName()) { + return; + } + + if (!getDisguise().isPlayerDisguise() && !DisguiseConfig.isOverrideCustomNames()) { + return; + } + + if (getDisguise().getEntity() == null) { + return; + } + + // Not using this as it's "Smooth" and looks a bit weirder + /*int[] ids = getDisguise().getArmorstandIds(); + + ArrayList packets = new ArrayList<>(); + Location loc = getDisguise().getEntity().getLocation(); + + for (int i = 0; i < getDisguise().getMultiNameLength(); i++) { + PacketContainer packet = new PacketContainer(Server.ENTITY_TELEPORT); + packet.getIntegers().write(0, ids[i]); + + StructureModifier doubles = packet.getDoubles(); + doubles.write(0, loc.getX()); + doubles.write(1, loc.getY() + getDisguise().getHeight() + (0.28 * i)); + doubles.write(2, loc.getZ()); + + packets.add(packet); + }*/ + + ArrayList packets = DisguiseUtilities.getNamePackets(getDisguise(), new String[0]); + + try { + for (Player player : DisguiseUtilities.getPerverts(getDisguise())) { + for (PacketContainer packet : packets) { + ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet); + } + } + } + catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + public String getCustomName() { if (!getDisguise().isPlayerDisguise() && DisguiseConfig.isOverrideCustomNames() && DisguiseConfig.isArmorstandsName()) { @@ -266,6 +338,10 @@ public class FlagWatcher { } if (!NmsVersion.v1_13.isSupported()) { + if (!hasValue(MetaIndex.ENTITY_CUSTOM_NAME_OLD)) { + return null; + } + return getData(MetaIndex.ENTITY_CUSTOM_NAME_OLD); } @@ -470,6 +546,10 @@ public class FlagWatcher { setEntityFlag(1, setSneaking); sendData(MetaIndex.ENTITY_META); + if (getDisguise().isPlayerDisguise()) { + updateNameHeight(); + } + if (NmsVersion.v1_14.isSupported()) { updatePose(); } diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/MiscDisguise.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/MiscDisguise.java index b1638856..2b22916d 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/MiscDisguise.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/MiscDisguise.java @@ -4,6 +4,7 @@ import me.libraryaddict.disguise.disguisetypes.watchers.DroppedItemWatcher; import me.libraryaddict.disguise.disguisetypes.watchers.FallingBlockWatcher; import me.libraryaddict.disguise.disguisetypes.watchers.PaintingWatcher; import me.libraryaddict.disguise.disguisetypes.watchers.SplashPotionWatcher; +import me.libraryaddict.disguise.utilities.DisguiseValues; import org.bukkit.Art; import org.bukkit.Material; import org.bukkit.entity.Entity; @@ -63,6 +64,17 @@ public class MiscDisguise extends TargetedDisguise { apply(id, new ItemStack(Material.STONE)); } + @Override + public double getHeight() { + DisguiseValues values = DisguiseValues.getDisguiseValues(getType()); + + if (values == null || values.getAdultBox() == null) { + return 0; + } + + return values.getAdultBox().getY(); + } + private void apply(int id, ItemStack itemStack) { createDisguise(); diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/MobDisguise.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/MobDisguise.java index f8a6f83e..e7931fa4 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/MobDisguise.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/MobDisguise.java @@ -1,8 +1,7 @@ package me.libraryaddict.disguise.disguisetypes; -import me.libraryaddict.disguise.disguisetypes.watchers.AgeableWatcher; -import me.libraryaddict.disguise.disguisetypes.watchers.LivingWatcher; -import me.libraryaddict.disguise.disguisetypes.watchers.ZombieWatcher; +import me.libraryaddict.disguise.disguisetypes.watchers.*; +import me.libraryaddict.disguise.utilities.DisguiseValues; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -30,6 +29,30 @@ public class MobDisguise extends TargetedDisguise { createDisguise(); } + @Override + public double getHeight() { + DisguiseValues values = DisguiseValues.getDisguiseValues(getType()); + + if (values == null || values.getAdultBox() == null) { + return 0; + } + + if (!isAdult() && values.getBabyBox() != null) { + return values.getBabyBox().getY(); + } + + if (getWatcher() != null) { + if (getType() == DisguiseType.ARMOR_STAND) { + return (((ArmorStandWatcher) getWatcher()).isSmall() ? values.getBabyBox() : values.getAdultBox()) + .getY(); + } else if (getType() == DisguiseType.SLIME || getType() == DisguiseType.MAGMA_CUBE) { + return 0.51 * (0.255 * ((SlimeWatcher) getWatcher()).getSize()); + } + } + + return values.getAdultBox().getY(); + } + @Override public MobDisguise addPlayer(Player player) { return (MobDisguise) super.addPlayer(player); diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/ModdedDisguise.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/ModdedDisguise.java index db2fa455..c1065980 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/ModdedDisguise.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/ModdedDisguise.java @@ -38,6 +38,11 @@ public class ModdedDisguise extends TargetedDisguise { createDisguise(); } + @Override + public double getHeight() { + return 0; + } + @Override public boolean isCustomDisguise() { return true; diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java index 89a81df0..9158c29c 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java @@ -83,6 +83,19 @@ public class PlayerDisguise extends TargetedDisguise { createDisguise(); } + @Override + public double getHeight() { + if (getWatcher() == null) { + return 1.8; + } + + if (getEntity() == null || getWatcher().getModifiedEntityAnimations()[1]) { + return getWatcher().isSneaking() ? 1.5 : 1.8; + } + + return getEntity() instanceof Player && ((Player) getEntity()).isSneaking() ? 1.5 : 1.8; + } + @Deprecated public DisguiseUtilities.DScoreTeam getScoreboardName() { if (!DisguiseConfig.isScoreboardNames()) { diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/SlimeWatcher.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/SlimeWatcher.java index e16d3000..06a2a120 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/SlimeWatcher.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/SlimeWatcher.java @@ -25,7 +25,13 @@ public class SlimeWatcher extends InsentientWatcher { size = 50; } + if (hasValue(MetaIndex.SLIME_SIZE) && getData(MetaIndex.SLIME_SIZE) == size) { + return; + } + setData(MetaIndex.SLIME_SIZE, size); sendData(MetaIndex.SLIME_SIZE); + + updateNameHeight(); } } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java b/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java index b5d0474e..f5285726 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java @@ -22,7 +22,7 @@ import me.libraryaddict.disguise.LibsDisguises; import me.libraryaddict.disguise.disguisetypes.*; import me.libraryaddict.disguise.disguisetypes.TargetedDisguise.TargetType; import me.libraryaddict.disguise.disguisetypes.watchers.AgeableWatcher; -import me.libraryaddict.disguise.disguisetypes.watchers.LivingWatcher; +import me.libraryaddict.disguise.disguisetypes.watchers.ArmorStandWatcher; import me.libraryaddict.disguise.disguisetypes.watchers.ZombieWatcher; import me.libraryaddict.disguise.utilities.json.*; import me.libraryaddict.disguise.utilities.mineskin.MineSkinAPI; @@ -2323,6 +2323,8 @@ public class DisguiseUtilities { destroyIds = Arrays.copyOfRange(standIds, newNames.length, internalOldNames.length); } + double height = disguise.getHeight(); + for (int i = 0; i < newNames.length; i++) { if (i < internalOldNames.length) { if (newNames[i].equals(internalOldNames[i]) || newNames[i].isEmpty()) { @@ -2358,19 +2360,19 @@ public class DisguiseUtilities { Location loc = disguise.getEntity().getLocation(); packet.getDoubles().write(0, loc.getX()); - packet.getDoubles().write(1, loc.getY() + -0.175 + (0.28 * i)); + packet.getDoubles().write(1, loc.getY() + height + (0.28 * i)); packet.getDoubles().write(2, loc.getZ()); packets.add(packet); WrappedDataWatcher watcher = new WrappedDataWatcher(); - for (MetaIndex index : MetaIndex.getMetaIndexes(LivingWatcher.class)) { + for (MetaIndex index : MetaIndex.getMetaIndexes(ArmorStandWatcher.class)) { Object val = index.getDefault(); if (index == MetaIndex.ENTITY_META) { val = (byte) 32; } else if (index == MetaIndex.ARMORSTAND_META) { - val = (byte) 17; + val = (byte) 19; } else if (index == MetaIndex.ENTITY_CUSTOM_NAME) { val = Optional.of(WrappedChatComponent.fromText(newNames[i])); } else if (index == MetaIndex.ENTITY_CUSTOM_NAME_OLD) { @@ -2387,7 +2389,7 @@ public class DisguiseUtilities { if (NmsVersion.v1_15.isSupported()) { PacketContainer metaPacket = ProtocolLibrary.getProtocolManager() - .createPacketConstructor(PacketType.Play.Server.ENTITY_METADATA, 0, watcher, true) + .createPacketConstructor(PacketType.Play.Server.ENTITY_METADATA, standIds[i], watcher, true) .createPacket(standIds[i], watcher, true); packets.add(metaPacket); diff --git a/src/main/java/me/libraryaddict/disguise/utilities/DisguiseValues.java b/src/main/java/me/libraryaddict/disguise/utilities/DisguiseValues.java index 8d9bf771..03cd11eb 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/DisguiseValues.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/DisguiseValues.java @@ -15,19 +15,12 @@ public class DisguiseValues { return values.get(type); } - public static Class getNmsEntityClass(DisguiseType type) { - return getDisguiseValues(type).getNmsEntityClass(); - } - private FakeBoundingBox adultBox; private FakeBoundingBox babyBox; - private float[] entitySize; - private double maxHealth; - private Class nmsEntityClass; + private final double maxHealth; - public DisguiseValues(DisguiseType type, Class classType, double maxHealth) { + public DisguiseValues(DisguiseType type, double maxHealth) { values.put(type, this); - nmsEntityClass = classType; this.maxHealth = maxHealth; } @@ -50,8 +43,4 @@ public class DisguiseValues { public double getMaxHealth() { return maxHealth; } - - public Class getNmsEntityClass() { - return nmsEntityClass; - } } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerMovement.java b/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerMovement.java index 4d272367..0aaae52f 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerMovement.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerMovement.java @@ -49,6 +49,7 @@ public class PacketHandlerMovement implements IPacketHandler { } ArrayList toAdd = new ArrayList<>(); + double height = disguise.getHeight(); for (PacketContainer packet : packets.getPackets()) { for (int i = 0; i < len; i++) { @@ -57,7 +58,7 @@ public class PacketHandlerMovement implements IPacketHandler { packet2.getIntegers().write(0, standId); if (packet2.getType() == PacketType.Play.Server.ENTITY_TELEPORT) { - packet2.getDoubles().write(1, packet2.getDoubles().read(1) + -0.175 + (0.28 * i)); + packet2.getDoubles().write(1, packet2.getDoubles().read(1) + height + (0.28 * i)); } toAdd.add(packet2); diff --git a/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java b/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java index ce10f09d..a4e487b2 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java @@ -48,8 +48,10 @@ public class DisguiseParser { disguise = new MiscDisguise(type); } else if (type.isMob()) { disguise = new MobDisguise(type); - } else { + } else if (type.isPlayer()) { disguise = new PlayerDisguise("Foobar"); + } else { + continue; } FlagWatcher watcher = type.getWatcherClass().getConstructor(Disguise.class).newInstance(disguise); @@ -217,15 +219,14 @@ public class DisguiseParser { } private static void addWatcherDefault(Method setMethod, Method getMethod, Object object) { - if (defaultWatcherValues.containsKey(setMethod)) { Object dObj = defaultWatcherValues.get(setMethod).getValue(); if (!Objects.deepEquals(dObj, object)) { throw new IllegalStateException(String.format( "%s has conflicting values! This means it expected the same value again but received a " + - "different value on a different disguise! %s is not the same as %s!", setMethod.getName(), object, - dObj)); + "different value on a different disguise! %s is not the same as %s!", + setMethod.getName(), object, dObj)); } return; diff --git a/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java b/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java index 963c5538..a6185bd8 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java @@ -1722,7 +1722,7 @@ public class ReflectionManager { try { if (disguiseType == DisguiseType.UNKNOWN || disguiseType.isCustom()) { - DisguiseValues disguiseValues = new DisguiseValues(disguiseType, null, 0); + DisguiseValues disguiseValues = new DisguiseValues(disguiseType, 0); disguiseValues.setAdultBox(new FakeBoundingBox(0, 0, 0)); @@ -1763,7 +1763,7 @@ public class ReflectionManager { } } - DisguiseValues disguiseValues = new DisguiseValues(disguiseType, nmsEntity.getClass(), + DisguiseValues disguiseValues = new DisguiseValues(disguiseType, bukkitEntity instanceof Damageable ? ((Damageable) bukkitEntity).getMaxHealth() : 0); WrappedDataWatcher watcher = WrappedDataWatcher.getEntityWatcher(bukkitEntity); @@ -1841,9 +1841,11 @@ public class ReflectionManager { ((Zombie) bukkitEntity).setBaby(true); disguiseValues.setBabyBox(ReflectionManager.getBoundingBox(bukkitEntity)); - } + } else if (bukkitEntity instanceof ArmorStand) { + ((ArmorStand) bukkitEntity).setSmall(true); - //disguiseValues.setEntitySize(ReflectionManager.getSize(bukkitEntity)); + disguiseValues.setBabyBox(ReflectionManager.getBoundingBox(bukkitEntity)); + } } catch (SecurityException | IllegalArgumentException | IllegalAccessException | FieldAccessException ex) { DisguiseUtilities.getLogger() diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 51d63e2f..ff6aed87 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -72,8 +72,10 @@ SaveDisguises: # EXTENDED - Names are limited to 48 chars but can't be changed without resending disguise # ARMORSTANDS - Names are limited to 256 chars, uses a mix of armorstands and teams to do this. Slightly hacky. # Downside of armorstand names is that there's a chance of it becoming desynced from the player disguise +# And names will always display even if the entity is invisible using potion effects PlayerNames: TEAMS -# If doing armorstands, should CustomNames be overridden to use armorstands too? +# If doing ARMORSTANDS in the above option, should CustomNames be overridden to use armorstands too? +# This allows multiline names OverrideCustomNames: true # How many ticks before tab packet is sent to remove from tablist. This shouldn't need to be touched