From f4accbfe2d1a38cb9c6b64a0a81ad694d54cb8f5 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Sun, 2 Dec 2012 02:49:11 +0100 Subject: [PATCH] Make it possible to get every player that is tracking a given entity. --- .../comphenix/protocol/ProtocolManager.java | 10 +++++- .../protocol/injector/EntityUtilities.java | 36 ++++++++++++++++++- .../injector/PacketFilterManager.java | 6 ++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java index 3e319249..741c54bc 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java @@ -130,7 +130,7 @@ public interface ProtocolManager extends PacketStream { public PacketConstructor createPacketConstructor(int id, Object... arguments); /** - * Completely refresh all clients about an entity. + * Completely resend an entity to a list of clients. *

* Note that this method is NOT thread safe. If you call this method from anything * but the main thread, it will throw an exception. @@ -148,6 +148,14 @@ public interface ProtocolManager extends PacketStream { */ public Entity getEntityFromID(World container, int id) throws FieldAccessException; + /** + * Retrieve every client that is receiving information about a given entity. + * @param entity - the entity that is being tracked. + * @return Every client/player that is tracking the given entity. + * @throws FieldAccessException If reflection failed. + */ + public List getEntityTrackers(Entity entity) throws FieldAccessException; + /** * Retrieves a immutable set containing the ID of the sent server packets that will be observed by listeners. * @return Every filtered server packet. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java index 9671c6ce..ef9c9e8c 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java @@ -21,12 +21,14 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import net.minecraft.server.EntityPlayer; import net.minecraft.server.EntityTrackerEntry; import org.bukkit.World; @@ -118,7 +120,39 @@ class EntityUtilities { } catch (SecurityException e) { throw new FieldAccessException("Security limitation prevents access to 'scanPlayers' method in trackerEntry.", e); } catch (NoSuchMethodException e) { - throw new FieldAccessException("Canot find 'scanPlayers' method. Is ProtocolLib up to date?", e); + throw new FieldAccessException("Cannot find 'scanPlayers' method. Is ProtocolLib up to date?", e); + } + } + + /** + * Retrieve every client that is receiving information about a given entity. + * @param entity - the entity that is being tracked. + * @return Every client/player that is tracking the given entity. + * @throws FieldAccessException If reflection failed. + */ + public static List getEntityTrackers(Entity entity) { + try { + List result = new ArrayList(); + Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId()); + + if (trackedPlayersField == null) + trackedPlayersField = FuzzyReflection.fromObject(trackerEntry).getFieldByType("java\\.util\\..*"); + + Collection trackedPlayers = (Collection) FieldUtils.readField(trackedPlayersField, trackerEntry, false); + + // Wrap every player - we also ensure that the underlying tracker list is immutable + for (Object tracker : trackedPlayers) { + if (tracker instanceof EntityPlayer) { + EntityPlayer nmsPlayer = (EntityPlayer) tracker; + result.add(nmsPlayer.getBukkitEntity()); + } + } + return result; + + } catch (IllegalAccessException e) { + throw new FieldAccessException("Security limitation prevented access to the list of tracked players.", e); + } catch (InvocationTargetException e) { + throw new FieldAccessException("Exception occurred in Minecraft.", e); } } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java index a8706e90..663b4c09 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java @@ -55,6 +55,7 @@ import com.comphenix.protocol.events.*; import com.comphenix.protocol.injector.player.PlayerInjectionHandler; import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.wrappers.BukkitConverters; import com.google.common.base.Objects; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableSet; @@ -571,6 +572,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok return EntityUtilities.getEntityFromID(container, id); } + @Override + public List getEntityTrackers(Entity entity) throws FieldAccessException { + return EntityUtilities.getEntityTrackers(entity); + } + /** * Initialize the packet injection for every player. * @param players - list of players to inject.