diff --git a/src/me/libraryaddict/disguise/disguisetypes/Disguise.java b/src/me/libraryaddict/disguise/disguisetypes/Disguise.java index 9766c0af..e0dcb520 100644 --- a/src/me/libraryaddict/disguise/disguisetypes/Disguise.java +++ b/src/me/libraryaddict/disguise/disguisetypes/Disguise.java @@ -179,27 +179,35 @@ public abstract class Disguise { final TargetedDisguise disguise = (TargetedDisguise) this; // A scheduler to clean up any unused disguises. velocityRunnable = new BukkitRunnable() { + private int deadTicks = 0; private int refreshDisguise = 0; public void run() { // If entity is no longer valid. Remove it. if (!getEntity().isValid()) { + // If it has been dead for 30+ ticks + // This is to ensure that this disguise isn't removed while clients think its the real entity + // The delay is because if it sends the destroy entity packets straight away, then it means no death animation + // This is probably still a problem for wither and enderdragon deaths. + if (deadTicks++ > 30) { - if (getEntity() instanceof Player ? + if (getEntity() instanceof Player ? - (Bukkit.getPlayerExact(((Player) getEntity()).getName()) == null ? !isKeepDisguiseOnPlayerLogout() - : !isKeepDisguiseOnPlayerDeath()) + (Bukkit.getPlayerExact(((Player) getEntity()).getName()) == null ? !isKeepDisguiseOnPlayerLogout() + : !isKeepDisguiseOnPlayerDeath()) - : + : - (!isKeepDisguiseOnEntityDespawn() || getEntity().isDead())) { - removeDisguise(); - } else { - entity = null; - watcher = getWatcher().clone(disguise); - cancel(); + (!isKeepDisguiseOnEntityDespawn() || getEntity().isDead())) { + removeDisguise(); + } else { + entity = null; + watcher = getWatcher().clone(disguise); + cancel(); + } } } else { + deadTicks = 0; // If the disguise type is tnt, we need to resend the entity packet else it will turn invisible if (getType() == DisguiseType.PRIMED_TNT || getType() == DisguiseType.FIREWORK) { refreshDisguise++; @@ -400,7 +408,11 @@ public abstract class Disguise { } // Better refresh the entity to undisguise it - DisguiseUtilities.refreshTrackers((TargetedDisguise) this); + if (getEntity().isValid()) { + DisguiseUtilities.refreshTrackers((TargetedDisguise) this); + } else { + DisguiseUtilities.destroyEntity((TargetedDisguise) this); + } } } else { // Loop through the disguises because it could be used with a unknown entity id. diff --git a/src/me/libraryaddict/disguise/utilities/DisguiseUtilities.java b/src/me/libraryaddict/disguise/utilities/DisguiseUtilities.java index b97be734..c9923ca8 100644 --- a/src/me/libraryaddict/disguise/utilities/DisguiseUtilities.java +++ b/src/me/libraryaddict/disguise/utilities/DisguiseUtilities.java @@ -142,6 +142,35 @@ public class DisguiseUtilities { } } + /** + * @param Sends + * entity removal packets, as this disguise was removed + */ + public static void destroyEntity(TargetedDisguise disguise) { + try { + Object world = ReflectionManager.getWorld(disguise.getEntity().getWorld()); + Object tracker = world.getClass().getField("tracker").get(world); + Object trackedEntities = tracker.getClass().getField("trackedEntities").get(tracker); + Object entityTrackerEntry = trackedEntities.getClass().getMethod("get", int.class) + .invoke(trackedEntities, disguise.getEntity().getEntityId()); + if (entityTrackerEntry != null) { + HashSet trackedPlayers = (HashSet) entityTrackerEntry.getClass().getField("trackedPlayers") + .get(entityTrackerEntry); + HashSet cloned = (HashSet) trackedPlayers.clone(); + PacketContainer destroyPacket = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY); + destroyPacket.getIntegerArrays().write(0, new int[] { disguise.getEntity().getEntityId() }); + for (Object p : cloned) { + Player player = (Player) ReflectionManager.getBukkitEntity(p); + if (disguise.canSee(player.getName())) { + ProtocolLibrary.getProtocolManager().sendServerPacket(player, destroyPacket); + } + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + public static void doBoundingBox(TargetedDisguise disguise) { // TODO Slimes Entity entity = disguise.getEntity();