Archiviert
13
0

Fixed a bug preventing the entity modifier from reading entities.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-11-13 16:10:56 +01:00
Ursprung fec2734fe2
Commit 528468a342
6 geänderte Dateien mit 106 neuen und 73 gelöschten Zeilen

Datei anzeigen

@ -19,7 +19,6 @@ import com.comphenix.protocol.reflect.compiler.StructureCompiler;
import com.comphenix.protocol.reflect.instances.CollectionGenerator; import com.comphenix.protocol.reflect.instances.CollectionGenerator;
import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.reflect.instances.PrimitiveGenerator; import com.comphenix.protocol.reflect.instances.PrimitiveGenerator;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.ChunkPosition; import com.comphenix.protocol.wrappers.ChunkPosition;
import com.comphenix.protocol.wrappers.WrappedDataWatcher; import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject; import com.comphenix.protocol.wrappers.WrappedWatchableObject;
@ -50,8 +49,7 @@ class CleanupStaticMembers {
PrimitiveGenerator.class, FuzzyReflection.class, MethodUtils.class, PrimitiveGenerator.class, FuzzyReflection.class, MethodUtils.class,
BackgroundCompiler.class, StructureCompiler.class, BackgroundCompiler.class, StructureCompiler.class,
ObjectCloner.class, Packets.Server.class, Packets.Client.class, ObjectCloner.class, Packets.Server.class, Packets.Client.class,
ChunkPosition.class, WrappedDataWatcher.class, WrappedWatchableObject.class, ChunkPosition.class, WrappedDataWatcher.class, WrappedWatchableObject.class
BukkitConverters.class
}; };
String[] internalClasses = { String[] internalClasses = {

Datei anzeigen

@ -20,6 +20,7 @@ package com.comphenix.protocol;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.bukkit.World;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@ -105,6 +106,15 @@ public interface ProtocolManager extends PacketStream {
*/ */
public void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException; public void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException;
/**
* Retrieve the associated entity.
* @param container - the world the entity belongs to.
* @param id - the unique ID of the entity.
* @return The associated entity.
* @throws FieldAccessException Reflection failed.
*/
public Entity getEntityFromID(World container, int id) throws FieldAccessException;
/** /**
* Retrieves a immutable set containing the ID of the sent server packets that will be observed by listeners. * Retrieves a immutable set containing the ID of the sent server packets that will be observed by listeners.
* @return Every filtered server packet. * @return Every filtered server packet.

Datei anzeigen

@ -27,6 +27,8 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import net.minecraft.server.EntityTrackerEntry;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
@ -83,8 +85,51 @@ class EntityUtilities {
* *
*/ */
public static void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException { public static void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException {
try {
//EntityTrackerEntry trackEntity = (EntityTrackerEntry) tracker.trackedEntities.get(entity.getEntityId());
Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
World world = entity.getWorld(); if (trackedPlayersField == null) {
// This one is fairly easy
trackedPlayersField = FuzzyReflection.fromObject(trackerEntry).getFieldByType("java\\.util\\..*");
}
// Phew, finally there.
Collection<?> trackedPlayers = (Collection<?>) FieldUtils.readField(trackedPlayersField, trackerEntry, false);
List<Object> nmsPlayers = unwrapBukkit(observers);
// trackEntity.trackedPlayers.clear();
trackedPlayers.removeAll(nmsPlayers);
// We have to rely on a NAME once again. Damn it.
if (scanPlayersMethod == null) {
scanPlayersMethod = trackerEntry.getClass().getMethod("scanPlayers", List.class);
}
//trackEntity.scanPlayers(server.players);
scanPlayersMethod.invoke(trackerEntry, nmsPlayers);
} catch (IllegalArgumentException e) {
throw e;
} catch (IllegalAccessException e) {
throw new FieldAccessException("Security limitation prevents access to 'get' method in IntHashMap", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Exception occurred in Minecraft.", e);
} 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);
}
}
/**
* Retrieve the entity tracker entry given a ID.
* @param world - world server.
* @param entityID - entity ID.
* @return The entity tracker entry.
* @throws FieldAccessException
*/
private static Object getEntityTrackerEntry(World world, int entityID) throws FieldAccessException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Object worldServer = ((CraftWorld) world).getHandle(); Object worldServer = ((CraftWorld) world).getHandle();
// We have to rely on the class naming here. // We have to rely on the class naming here.
@ -149,40 +194,36 @@ class EntityUtilities {
} }
} }
// Wrap exceptions
try { try {
//EntityTrackerEntry trackEntity = (EntityTrackerEntry) tracker.trackedEntities.get(entity.getEntityId()); return hashGetMethod.invoke(trackedEntities, entityID);
Object trackerEntry = hashGetMethod.invoke(trackedEntities, entity.getEntityId());
if (trackedPlayersField == null) {
// This one is fairly easy
trackedPlayersField = FuzzyReflection.fromObject(trackerEntry).getFieldByType("java\\.util\\..*");
}
// Phew, finally there.
Collection<?> trackedPlayers = (Collection<?>) FieldUtils.readField(trackedPlayersField, trackerEntry, false);
List<Object> nmsPlayers = unwrapBukkit(observers);
// trackEntity.trackedPlayers.clear();
trackedPlayers.removeAll(nmsPlayers);
// We have to rely on a NAME once again. Damn it.
if (scanPlayersMethod == null) {
scanPlayersMethod = trackerEntry.getClass().getMethod("scanPlayers", List.class);
}
//trackEntity.scanPlayers(server.players);
scanPlayersMethod.invoke(trackerEntry, nmsPlayers);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw e; throw e;
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new FieldAccessException("Security limitation prevents access to 'get' method in IntHashMap", e); throw new FieldAccessException("Security limitation prevents access to 'get' method in IntHashMap", e);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
throw new RuntimeException("Exception occurred in Minecraft.", e); throw new RuntimeException("Exception occurred in Minecraft.", e);
} 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); /**
* Retrieve entity from a ID, even it it's newly created.
* @return The asssociated entity.
* @throws FieldAccessException Reflection error.
*/
public static Entity getEntityFromID(World world, int entityID) throws FieldAccessException {
try {
EntityTrackerEntry trackerEntry = (EntityTrackerEntry) getEntityTrackerEntry(world, entityID);
// Handle NULL cases
if (trackerEntry != null && trackerEntry.tracker != null) {
return trackerEntry.tracker.getBukkitEntity();
} else {
return null;
}
} catch (Exception e) {
throw new FieldAccessException("Cannot find entity from ID.", e);
} }
} }

Datei anzeigen

@ -34,6 +34,7 @@ import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.proxy.MethodProxy;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -565,6 +566,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
EntityUtilities.updateEntity(entity, observers); EntityUtilities.updateEntity(entity, observers);
} }
@Override
public Entity getEntityFromID(World container, int id) throws FieldAccessException {
return EntityUtilities.getEntityFromID(container, id);
}
/** /**
* Initialize the packet injection for every player. * Initialize the packet injection for every player.
* @param players - list of players to inject. * @param players - list of players to inject.

Datei anzeigen

@ -1,7 +1,6 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import java.lang.reflect.InvocationTargetException; import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -9,18 +8,16 @@ import java.util.List;
import net.minecraft.server.DataWatcher; import net.minecraft.server.DataWatcher;
import net.minecraft.server.WatchableObject; import net.minecraft.server.WatchableObject;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.WorldType; import org.bukkit.WorldType;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.reflect.instances.DefaultInstances;
/** /**
@ -32,9 +29,6 @@ public class BukkitConverters {
// Check whether or not certain classes exists // Check whether or not certain classes exists
private static boolean hasWorldType = false; private static boolean hasWorldType = false;
// The getEntity method
private static Method getEntity;
static { static {
try { try {
Class.forName("net.minecraft.server.WorldType"); Class.forName("net.minecraft.server.WorldType");
@ -183,12 +177,9 @@ public class BukkitConverters {
* @return A converter between the underlying NMS entity and Bukkit's wrapper. * @return A converter between the underlying NMS entity and Bukkit's wrapper.
*/ */
public static EquivalentConverter<Entity> getEntityConverter(World world) { public static EquivalentConverter<Entity> getEntityConverter(World world) {
final Object worldServer = ((CraftWorld) world).getHandle(); final World container = world;
final Class<?> nmsEntityClass = net.minecraft.server.Entity.class; final WeakReference<ProtocolManager> managerRef =
new WeakReference<ProtocolManager>(ProtocolLibrary.getProtocolManager());
if (getEntity == null)
getEntity = FuzzyReflection.fromObject(worldServer).getMethodByParameters(
"getEntity", nmsEntityClass, new Class[] { int.class });
return getIgnoreNull(new EquivalentConverter<Entity>() { return getIgnoreNull(new EquivalentConverter<Entity>() {
@ -201,34 +192,17 @@ public class BukkitConverters {
@Override @Override
public Entity getSpecific(Object generic) { public Entity getSpecific(Object generic) {
try { try {
net.minecraft.server.Entity nmsEntity = (net.minecraft.server.Entity)
getEntity.invoke(worldServer, generic);
Integer id = (Integer) generic; Integer id = (Integer) generic;
// Attempt to get the Bukkit entity // Use the
if (nmsEntity != null) { if (id != null && managerRef.get() != null) {
return nmsEntity.getBukkitEntity(); return managerRef.get().getEntityFromID(container, id);
} else { } else {
Server server = Bukkit.getServer();
// Maybe it's a player that has just logged in? Try a search
if (server != null) {
for (Player player : server.getOnlinePlayers()) {
if (player.getEntityId() == id) {
return player;
}
}
}
return null; return null;
} }
} catch (IllegalArgumentException e) { } catch (FieldAccessException e) {
throw new RuntimeException("Incorrect arguments detected.", e); throw new RuntimeException("Cannot retrieve entity from ID.", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot read field due to a security limitation.", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Error occured in Minecraft method.", e.getCause());
} }
} }

Datei anzeigen

@ -14,6 +14,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import com.comphenix.protocol.injector.BukkitUnwrapper;
import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FieldUtils; import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
@ -414,10 +415,13 @@ public class WrappedDataWatcher {
*/ */
public static WrappedDataWatcher getEntityWatcher(Entity entity) throws FieldAccessException { public static WrappedDataWatcher getEntityWatcher(Entity entity) throws FieldAccessException {
if (entityDataField == null) if (entityDataField == null)
entityDataField = FuzzyReflection.fromClass(Entity.class, true).getFieldByType("datawatcher", DataWatcher.class); entityDataField = FuzzyReflection.fromClass(net.minecraft.server.Entity.class, true).
getFieldByType("datawatcher", DataWatcher.class);
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
try { try {
Object nsmWatcher = FieldUtils.readField(entityDataField, entity, true); Object nsmWatcher = FieldUtils.readField(entityDataField, unwrapper.unwrapItem(entity), true);
if (nsmWatcher != null) if (nsmWatcher != null)
return new WrappedDataWatcher((DataWatcher) nsmWatcher); return new WrappedDataWatcher((DataWatcher) nsmWatcher);