From a39a37ec51a54ceee61b50a1687a787794225367 Mon Sep 17 00:00:00 2001 From: Dan Mulloy Date: Sat, 5 Mar 2016 20:36:54 -0500 Subject: [PATCH] Allow new entries to be created in the data watcher Addresses #160 --- .../protocol/injector/EntityUtilities.java | 2 +- .../protocol/wrappers/WrappedDataWatcher.java | 91 +++++++++++++++---- .../wrappers/WrappedDataWatcherTest.java | 42 +++++++-- 3 files changed, 110 insertions(+), 25 deletions(-) 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 bef960db..572b9422 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java @@ -217,7 +217,7 @@ class EntityUtilities { } Object trackerEntry = WrappedIntHashMap.fromHandle(trackedEntities).get(entityID); - Class entryClass = MinecraftReflection.getEntityTrackerClass(); + Class entryClass = MinecraftReflection.getMinecraftClass("EntityTrackerEntry"); return entryClass.cast(trackerEntry); } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java index 205b5145..398730b0 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java @@ -17,6 +17,7 @@ package com.comphenix.protocol.wrappers; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -27,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.apache.commons.lang.Validate; import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; @@ -39,6 +41,7 @@ import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.reflect.accessors.MethodAccessor; +import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.base.Optional; @@ -50,7 +53,8 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable HANDLE_TYPE = MinecraftReflection.getDataWatcherClass(); private static MethodAccessor GETTER = null; - private static MethodAccessor SETTER = null; + public static MethodAccessor SETTER = null; + public static MethodAccessor REGISTER = null; private static FieldAccessor ENTITY_FIELD = null; private static FieldAccessor MAP_FIELD = null; @@ -297,15 +301,37 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable methods = fuzzy.getMethodList(FuzzyMethodContract.newBuilder() + .banModifier(Modifier.STATIC) + .requireModifier(Modifier.PUBLIC) + .parameterExactArray(object.getHandleType(), Object.class) + .build()); + for (Method method : methods) { + if (method.getName().equals("set")) { + SETTER = Accessors.getMethodAccessor(method); + } else if (method.getName().equals("register")) { + REGISTER = Accessors.getMethodAccessor(method); + } else { + System.out.println(method); + } + } } - SETTER.invoke(handle, watcherObject.getHandle(), WrappedWatchableObject.getUnwrapped(value)); + if (hasIndex(object.getIndex())) { + SETTER.invoke(handle, object.getHandle(), WrappedWatchableObject.getUnwrapped(value)); + } else { + Serializer serializer = object.getSerializer(); + Validate.notNull(serializer, "You must specify a serializer to register an object!"); + REGISTER.invoke(handle, object.getHandle(), WrappedWatchableObject.getUnwrapped(value)); + } } // TODO Add support for setting the dirty state @@ -318,8 +344,8 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable entry : asMap().entrySet()) { - clone.setObject(entry.getKey(), entry.getValue()); + for (WrappedWatchableObject wrapper : this) { + clone.setObject(wrapper.getWatcherObject(), wrapper); } return clone; @@ -452,6 +478,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable HANDLE_TYPE = MinecraftReflection.getDataWatcherObjectClass(); private static ConstructorAccessor constructor = null; + private static MethodAccessor getSerializer = null; private final StructureModifier modifier; @@ -492,10 +519,21 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable clazz) { - if (! INITIALIZED) { - initialize(); - INITIALIZED = true; - } - + initialize(); return REGISTRY.get(clazz); } + public static Serializer fromHandle(Object handle) { + initialize(); + + for (Serializer serializer : REGISTRY.values()) { + if (serializer.getHandle().equals(handle)) { + return serializer; + } + } + + return null; + } + private static void initialize() { + if (!INITIALIZED) { + INITIALIZED = true; + } else { + return; + } + List candidates = FuzzyReflection.fromClass(MinecraftReflection.getMinecraftClass("DataWatcherRegistry"), true) .getFieldListByType(MinecraftReflection.getDataWatcherSerializerClass()); for (Field candidate : candidates) { diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java index 207f5fb1..c8aa21e5 100644 --- a/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java @@ -3,6 +3,7 @@ */ package com.comphenix.protocol.wrappers; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import net.minecraft.server.v1_9_R1.DataWatcher; import net.minecraft.server.v1_9_R1.Entity; @@ -28,19 +29,46 @@ public class WrappedDataWatcherTest { } @Test - public void test() { - Entity entity = new EntityLightning(null, 0, 0, 0, true); - DataWatcher handle = entity.getDataWatcher(); + public void testBytes() { + WrappedDataWatcher wrapper = create(); + WrappedWatchableObject watchable = wrapper.getWatchableObject(0); + WrappedDataWatcherObject object = watchable.getWatcherObject(); - WrappedDataWatcher wrapper = new WrappedDataWatcher(handle); + // Make sure the serializers work + assertEquals(object.getSerializer(), Registry.get(Byte.class)); + // Make sure we can set existing objects wrapper.setObject(0, (byte) 1); assertTrue(wrapper.getByte(0) == 1); + } + @Test + public void testStrings() { + WrappedDataWatcher wrapper = create(); + + // Make sure we can create watcher objects Serializer serializer = Registry.get(String.class); - WrappedDataWatcherObject watcherObject = new WrappedDataWatcherObject(3, serializer); - wrapper.setObject(watcherObject, "Hiya"); + WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer); + wrapper.setObject(object, "Test"); - assertTrue(wrapper.getString(3).equals("Hiya")); + assertEquals(wrapper.getString(3), "Test"); + } + + @Test + public void testFloats() { + WrappedDataWatcher wrapper = create(); + + // Make sure we can add new entries + Serializer serializer = Registry.get(Float.class); + WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer); + wrapper.setObject(object, 1.0F); + + assertTrue(wrapper.hasIndex(10)); + } + + private WrappedDataWatcher create() { + Entity entity = new EntityLightning(null, 0, 0, 0, true); + DataWatcher handle = entity.getDataWatcher(); + return new WrappedDataWatcher(handle); } } \ No newline at end of file