diff --git a/pom.xml b/pom.xml index 6a2b9100..76ab85ce 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 2.5.0 - 7.2.4 + 7.2.4-SNAPSHOT diff --git a/src/me/libraryaddict/disguise/DisguiseAPI.java b/src/me/libraryaddict/disguise/DisguiseAPI.java index 1306fab4..1cd095f9 100644 --- a/src/me/libraryaddict/disguise/DisguiseAPI.java +++ b/src/me/libraryaddict/disguise/DisguiseAPI.java @@ -52,9 +52,15 @@ public class DisguiseAPI { return hearSelfDisguise; } + /** + * Disguise the next entity to spawn with this disguise. This may not work however if the entity doesn't actually spawn. + */ public static void disguiseNextEntity(Disguise disguise) { if (disguise == null) return; + if (disguise.getEntity() != null || disguises.containsValue(disguise)) { + disguise = disguise.clone(); + } try { Field field = net.minecraft.server.v1_6_R2.Entity.class.getDeclaredField("entityCount"); field.setAccessible(true); @@ -66,10 +72,7 @@ public class DisguiseAPI { } /** - * @param Player - * - The player to disguise - * @param Disguise - * - The disguise to wear + * Disguise this entity with this disguise */ public static void disguiseToAll(Entity entity, Disguise disguise) { // If they are trying to disguise a null entity or use a null disguise @@ -83,12 +86,7 @@ public class DisguiseAPI { // Just return. if (event.isCancelled()) return; - // The event wasn't cancelled. Got to discard the old disguise - Disguise oldDisguise = getDisguise(entity); - // If there was a old disguise - if (oldDisguise != null) { - oldDisguise.getScheduler().cancel(); - } + // The event wasn't cancelled. // If the disguise entity isn't the same as the one we are disguising if (disguise.getEntity() != entity) { // If the disguise entity actually exists @@ -98,13 +96,17 @@ public class DisguiseAPI { } // Set the disguise's entity disguise.setEntity(entity); - } + } // If there was a old disguise + Disguise oldDisguise = getDisguise(entity); // Stick the disguise in the disguises bin disguises.put(entity.getEntityId(), disguise); // Resend the disguised entity's packet refreshTrackers(entity); // If he is a player, then self disguise himself setupPlayerFakeDisguise(disguise); + // Discard the disguise + if (oldDisguise != null) + oldDisguise.discard(); } /** @@ -113,7 +115,9 @@ public class DisguiseAPI { public static Disguise getDisguise(Entity disguiser) { if (disguiser == null) return null; - return disguises.get(disguiser.getEntityId()); + if (disguises.containsKey(disguiser.getEntityId())) + return disguises.get(disguiser.getEntityId()); + return null; } /** @@ -130,17 +134,22 @@ public class DisguiseAPI { } /** - * @param Disguiser - * @return boolean - If the disguiser is disguised + * Is this entity disguised */ public static boolean isDisguised(Entity disguiser) { return getDisguise(disguiser) != null; } + /** + * Is the sound packets caught and modified + */ public static boolean isSoundEnabled() { return PacketsManager.isHearDisguisesEnabled(); } + /** + * Is the velocity packets sent + */ public static boolean isVelocitySent() { return sendVelocity; } @@ -170,7 +179,7 @@ public class DisguiseAPI { } } - private static void removeVisibleDisguise(Player player) { + private static void removeSelfDisguise(Player player) { if (selfDisguisesIds.containsKey(player.getEntityId())) { // Send a packet to destroy the fake entity PacketContainer packet = new PacketContainer(Packets.Server.DESTROY_ENTITY); @@ -203,12 +212,18 @@ public class DisguiseAPI { } } + /** + * Can players hear their own disguises + */ public static void setHearSelfDisguise(boolean replaceSound) { if (hearSelfDisguise != replaceSound) { hearSelfDisguise = replaceSound; } } + /** + * Set if the disguises play sounds when hurt + */ public static void setSoundsEnabled(boolean isSoundsEnabled) { PacketsManager.setHearDisguisesListener(isSoundsEnabled); } @@ -222,7 +237,7 @@ public class DisguiseAPI { return; Player player = (Player) disguise.getEntity(); // Remove the old disguise, else we have weird disguises around the place - removeVisibleDisguise(player); + removeSelfDisguise(player); // If the disguised player can't see himself. Return if (!disguise.viewSelfDisguise()) return; @@ -342,7 +357,8 @@ public class DisguiseAPI { } /** - * Undisguise the entity + * Undisguise the entity. This doesn't let you cancel the UndisguiseEvent if the entity is no longer valid. Aka removed from + * the world. */ public static void undisguiseToAll(Entity entity) { Disguise disguise = getDisguise(entity); @@ -350,14 +366,20 @@ public class DisguiseAPI { return; UndisguiseEvent event = new UndisguiseEvent(entity, disguise); Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled() && ((CraftEntity) entity).getHandle().valid) + if (event.isCancelled()) return; - disguise.getScheduler().cancel(); - disguises.remove(entity.getEntityId()); - if (((CraftEntity) entity).getHandle().valid) { - if (entity instanceof Player) - removeVisibleDisguise((Player) entity); - refreshTrackers(entity); - } + disguise.discard(); + } + + public HashMap getDisguises() { + return disguises; + } + + public void refreshWatchingPlayers(Entity entity) { + refreshTrackers(entity); + } + + public void removeVisibleDisguise(Player player) { + removeSelfDisguise(player); } } \ No newline at end of file diff --git a/src/me/libraryaddict/disguise/DisguiseTypes/Disguise.java b/src/me/libraryaddict/disguise/DisguiseTypes/Disguise.java index f5beee0a..f1f72b95 100644 --- a/src/me/libraryaddict/disguise/DisguiseTypes/Disguise.java +++ b/src/me/libraryaddict/disguise/DisguiseTypes/Disguise.java @@ -3,6 +3,7 @@ package me.libraryaddict.disguise.DisguiseTypes; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import me.libraryaddict.disguise.DisguiseAPI; import me.libraryaddict.disguise.DisguiseTypes.Watchers.AgeableWatcher; @@ -28,6 +29,7 @@ import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.reflect.StructureModifier; public class Disguise { + private static DisguiseAPI disguiseAPI = new DisguiseAPI(); private static JavaPlugin plugin; private DisguiseType disguiseType; private org.bukkit.entity.Entity entity; @@ -71,108 +73,6 @@ public class Disguise { // Ok.. So it aint a horse } } - } - - public boolean canHearSelfDisguise() { - return hearSelfDisguise; - } - - public Disguise clone() { - Disguise disguise = new Disguise(getType(), replaceSounds()); - disguise.setViewSelfDisguise(viewSelfDisguise()); - return disguise; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Disguise other = (Disguise) obj; - if (disguiseType != other.disguiseType) - return false; - if (hearSelfDisguise != other.hearSelfDisguise) - return false; - if (replaceSounds != other.replaceSounds) - return false; - if (velocitySent != other.velocitySent) - return false; - if (viewSelfDisguise != other.viewSelfDisguise) - return false; - if (!watcher.equals(other.watcher)) - return false; - return true; - } - - /** - * Get the disguised entity - */ - public org.bukkit.entity.Entity getEntity() { - return entity; - } - - /** - * Get all EntityPlayers who have this entity in their Entity Tracker - */ - protected EntityPlayer[] getPerverts() { - EntityTrackerEntry entry = (EntityTrackerEntry) ((WorldServer) ((CraftEntity) entity).getHandle().world).tracker.trackedEntities - .get(entity.getEntityId()); - if (entry != null) { - EntityPlayer[] players = (EntityPlayer[]) entry.trackedPlayers.toArray(new EntityPlayer[entry.trackedPlayers.size()]); - return players; - } - return new EntityPlayer[0]; - } - - public BukkitRunnable getScheduler() { - return runnable; - } - - /** - * Get the disguise type - */ - public DisguiseType getType() { - return disguiseType; - } - - /** - * Get the flag watcher - */ - public FlagWatcher getWatcher() { - return watcher; - } - - public boolean isMiscDisguise() { - return this instanceof MiscDisguise; - } - - public boolean isMobDisguise() { - return this instanceof MobDisguise; - } - - public boolean isPlayerDisguise() { - return this instanceof PlayerDisguise; - } - - public boolean isVelocitySent() { - return velocitySent; - } - - public boolean replaceSounds() { - return replaceSounds; - } - - /** - * Set the entity of the disguise. Only used for internal things. - */ - public void setEntity(final org.bukkit.entity.Entity entity) { - if (this.entity != null) - throw new RuntimeException("This disguise is already in use! Try .clone()"); - this.entity = entity; - setupWatcher(); double fallSpeed = 0.0050; boolean movement = false; switch (getType()) { @@ -292,6 +192,147 @@ public class Disguise { } } }; + } + + public boolean canHearSelfDisguise() { + return hearSelfDisguise; + } + + public Disguise clone() { + Disguise disguise = new Disguise(getType(), replaceSounds()); + disguise.setViewSelfDisguise(viewSelfDisguise()); + return disguise; + } + + /** + * Destroys the disguise and undisguises the entity if its using this disguise. This doesn't fire a UndisguiseEvent + */ + public void discard() { + // If the runnable is null. Just return. Its been discarded already. + if (runnable == null) + return; + // Why the hell can't I safely check if its running?!?! + try { + runnable.cancel(); + } catch (Exception ex) { + } + runnable = null; + HashMap disguises = disguiseAPI.getDisguises(); + // If this disguise has a entity set + if (getEntity() != null) { + // If the entity is valid + if (((CraftEntity) getEntity()).getHandle().valid) { + // If this disguise is active + if (disguises.containsKey(getEntity().getEntityId()) && disguises.get(getEntity().getEntityId()) == this) { + // Gotta do reflection, copy code or open up calls. + // Reflection is the cleanest? + if (entity instanceof Player) { + disguiseAPI.removeVisibleDisguise((Player) entity); + } + // Better refresh the entity to undisguise it + disguiseAPI.refreshWatchingPlayers(getEntity()); + // Now remove the disguise from the current disguises. + disguises.remove(getEntity().getEntityId()); + } + } + } else { + // Loop through the disguises because it could be used with a unknown entity id. + Iterator itel = disguises.keySet().iterator(); + while (itel.hasNext()) { + int id = itel.next(); + if (disguises.get(id) == this) { + itel.remove(); + } + } + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Disguise other = (Disguise) obj; + if (disguiseType != other.disguiseType) + return false; + if (hearSelfDisguise != other.hearSelfDisguise) + return false; + if (replaceSounds != other.replaceSounds) + return false; + if (velocitySent != other.velocitySent) + return false; + if (viewSelfDisguise != other.viewSelfDisguise) + return false; + if (!watcher.equals(other.watcher)) + return false; + return true; + } + + /** + * Get the disguised entity + */ + public org.bukkit.entity.Entity getEntity() { + return entity; + } + + /** + * Get all EntityPlayers who have this entity in their Entity Tracker + */ + protected EntityPlayer[] getPerverts() { + EntityTrackerEntry entry = (EntityTrackerEntry) ((WorldServer) ((CraftEntity) entity).getHandle().world).tracker.trackedEntities + .get(entity.getEntityId()); + if (entry != null) { + EntityPlayer[] players = (EntityPlayer[]) entry.trackedPlayers.toArray(new EntityPlayer[entry.trackedPlayers.size()]); + return players; + } + return new EntityPlayer[0]; + } + + /** + * Get the disguise type + */ + public DisguiseType getType() { + return disguiseType; + } + + /** + * Get the flag watcher + */ + public FlagWatcher getWatcher() { + return watcher; + } + + public boolean isMiscDisguise() { + return this instanceof MiscDisguise; + } + + public boolean isMobDisguise() { + return this instanceof MobDisguise; + } + + public boolean isPlayerDisguise() { + return this instanceof PlayerDisguise; + } + + public boolean isVelocitySent() { + return velocitySent; + } + + public boolean replaceSounds() { + return replaceSounds; + } + + /** + * Set the entity of the disguise. Only used for internal things. + */ + public void setEntity(final org.bukkit.entity.Entity entity) { + if (this.entity != null) + throw new RuntimeException("This disguise is already in use! Try .clone()"); + this.entity = entity; + setupWatcher(); runnable.runTaskTimer(plugin, 1, 1); } @@ -366,7 +407,7 @@ public class Disguise { // If they both extend the same base class. They OBVIOUSLY share the same datavalue. Right..? if (baseClass != null && baseClass.isAssignableFrom(disguiseClass) && baseClass.isAssignableFrom(entityClass)) continue; - + // So they don't extend a basic class. // Maybe if I check that they extend each other.. // Seeing as I only store the finished forms of entitys. This should raise no problems and allow for more shared diff --git a/src/me/libraryaddict/disguise/PacketsManager.java b/src/me/libraryaddict/disguise/PacketsManager.java index 1be49b6c..ef113b45 100644 --- a/src/me/libraryaddict/disguise/PacketsManager.java +++ b/src/me/libraryaddict/disguise/PacketsManager.java @@ -101,6 +101,7 @@ public class PacketsManager { }); // Now add a client listener to cancel them interacting with uninteractable disguised entitys. // You ain't supposed to be allowed to 'interact' with a item that cannot be clicked. + // Kicks you for hacking. manager.addPacketListener(new PacketAdapter(libsDisguises, ConnectionSide.CLIENT_SIDE, ListenerPriority.NORMAL, Packets.Client.USE_ENTITY) { @Override @@ -120,7 +121,10 @@ public class PacketsManager { }); } - public static PacketContainer[] constructPacket(Disguise disguise, Entity disguisedEntity) { + /** + * Construct the packets I need to spawn in the disguise + */ + public static PacketContainer[] constructSpawnPackets(Disguise disguise, Entity disguisedEntity) { if (disguise.getEntity() == null) disguise.setEntity(disguisedEntity); net.minecraft.server.v1_6_R2.Entity nmsEntity = ((CraftEntity) disguisedEntity).getHandle(); @@ -204,7 +208,7 @@ public class PacketsManager { item = CraftItemStack.asNMSCopy(((CraftLivingEntity) disguisedEntity).getEquipment().getItemInHand()); } mods.write(7, (item == null ? 0 : item.id)); - mods.write(8, convertDataWatcher(nmsEntity.getDataWatcher(), disguise.getWatcher())); + mods.write(8, createDataWatcher(nmsEntity.getDataWatcher(), disguise.getWatcher())); } else if (disguise.getType().isMob()) { @@ -239,7 +243,7 @@ public class PacketsManager { mods.write(9, (byte) (int) (loc.getPitch() * 256.0F / 360.0F)); if (nmsEntity instanceof EntityLiving) mods.write(10, (byte) (int) (((EntityLiving) nmsEntity).aA * 256.0F / 360.0F)); - mods.write(11, convertDataWatcher(nmsEntity.getDataWatcher(), disguise.getWatcher())); + mods.write(11, createDataWatcher(nmsEntity.getDataWatcher(), disguise.getWatcher())); // Theres a list sometimes written with this. But no problems have appeared! // Probably just the metadata to be sent. But the next meta packet after fixes that anyways. @@ -302,7 +306,10 @@ public class PacketsManager { return spawnPackets; } - private static DataWatcher convertDataWatcher(DataWatcher watcher, FlagWatcher flagWatcher) { + /** + * Create a new datawatcher but with the 'correct' values + */ + private static DataWatcher createDataWatcher(DataWatcher watcher, FlagWatcher flagWatcher) { DataWatcher newWatcher = new DataWatcher(); try { Field map = newWatcher.getClass().getDeclaredField("c"); @@ -320,6 +327,9 @@ public class PacketsManager { } + /** + * Add the yaw for the disguises + */ private static byte getYaw(DisguiseType disguiseType, DisguiseType entityType, byte value) { switch (disguiseType) { case ENDER_DRAGON: @@ -640,6 +650,9 @@ public class PacketsManager { } } + /** + * Transform the packet magically into the one I have always dreamed off. My true luv!!! + */ private static PacketContainer[] transformPacket(PacketContainer sentPacket, Player observer) { PacketContainer[] packets = new PacketContainer[] { sentPacket }; try { @@ -653,6 +666,7 @@ public class PacketsManager { // This packet sends attributes switch (sentPacket.getID()) { + case Packets.Server.UPDATE_ATTRIBUTES: { @@ -696,7 +710,7 @@ public class PacketsManager { case Packets.Server.ENTITY_PAINTING: { - packets = constructPacket(disguise, entity); + packets = constructSpawnPackets(disguise, entity); break; }