From e8759d0b72dc784f29a8d525d0266ce03945f7f3 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Mon, 9 Dec 2013 13:46:41 +0100 Subject: [PATCH] Refactor the wrapper classes so they inherit from a common class. --- .../com/comphenix/protocol/PacketType.java | 36 +++++ .../protocol/wrappers/AbstractWrapper.java | 50 +++++++ .../protocol/wrappers/WrappedAttribute.java | 45 +++---- .../wrappers/WrappedAttributeModifier.java | 127 ++++++++---------- .../wrappers/WrappedChatComponent.java | 18 +-- .../wrappers/WrappedChunkCoordinate.java | 49 ++++--- .../protocol/wrappers/WrappedDataWatcher.java | 111 +++++++-------- .../protocol/wrappers/WrappedGameProfile.java | 33 ++--- .../protocol/wrappers/WrappedIntHashMap.java | 27 +--- .../wrappers/WrappedWatchableObject.java | 15 +-- .../wrappers/WrappedChunkCoordinateTest.java | 24 ++++ .../wrappers/WrappedIntHashMapTest.java | 24 ++++ 12 files changed, 303 insertions(+), 256 deletions(-) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/AbstractWrapper.java create mode 100644 ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinateTest.java create mode 100644 ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedIntHashMapTest.java diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/PacketType.java b/ProtocolLib/src/main/java/com/comphenix/protocol/PacketType.java index 664b9f84..21b3cbae 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/PacketType.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/PacketType.java @@ -43,6 +43,10 @@ public class PacketType implements Serializable { public static class Handshake { private static final Protocol PROTOCOL = Protocol.HANDSHAKING; + /** + * Incoming packets. + * @author Kristian + */ public static class Client extends ObjectEnum { private final static Sender SENDER = Sender.CLIENT; /** @@ -92,6 +96,10 @@ public class PacketType implements Serializable { public static class Play { private static final Protocol PROTOCOL = Protocol.GAME; + /** + * Outgoing packets. + * @author Kristian + */ public static class Server extends ObjectEnum { private final static Sender SENDER = Sender.SERVER; @@ -183,6 +191,10 @@ public class PacketType implements Serializable { } } + /** + * Incoming packets. + * @author Kristian + */ public static class Client extends ObjectEnum { private final static Sender SENDER = Sender.CLIENT; @@ -236,6 +248,10 @@ public class PacketType implements Serializable { public static class Status { private static final Protocol PROTOCOL = Protocol.STATUS; + /** + * Outgoing packets. + * @author Kristian + */ public static class Server extends ObjectEnum { private final static Sender SENDER = Sender.SERVER; @@ -256,6 +272,10 @@ public class PacketType implements Serializable { } } + /** + * Incoming packets. + * @author Kristian + */ public static class Client extends ObjectEnum { private final static Sender SENDER = Sender.CLIENT; @@ -288,6 +308,10 @@ public class PacketType implements Serializable { public static class Login { private static final Protocol PROTOCOL = Protocol.LOGIN; + /** + * Outgoing packets. + * @author Kristian + */ public static class Server extends ObjectEnum { private final static Sender SENDER = Sender.SERVER; @@ -309,6 +333,10 @@ public class PacketType implements Serializable { } } + /** + * Incoming packets. + * @author Kristian + */ public static class Client extends ObjectEnum { private final static Sender SENDER = Sender.CLIENT; @@ -341,6 +369,10 @@ public class PacketType implements Serializable { public static class Legacy { private static final Protocol PROTOCOL = Protocol.LEGACY; + /** + * Outgoing packets. + * @author Kristian + */ // Missing server packets: [10, 11, 12, 21, 107, 252] public static class Server extends ObjectEnum { private final static Sender SENDER = Sender.SERVER; @@ -377,6 +409,10 @@ public class PacketType implements Serializable { } } + /** + * Incoming packets. + * @author Kristian + */ // Missing client packets: [1, 9, 255] public static class Client extends ObjectEnum { private final static Sender SENDER = Sender.CLIENT; diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/AbstractWrapper.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/AbstractWrapper.java new file mode 100644 index 00000000..660a1b06 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/AbstractWrapper.java @@ -0,0 +1,50 @@ +package com.comphenix.protocol.wrappers; + +import com.google.common.base.Preconditions; + +/** + * Represents a wrapper for an NMS object. + * @author Kristian + */ +public abstract class AbstractWrapper { + protected Object handle; + protected Class handleType; + + /** + * Construct a new NMS wrapper. + * @param handle - the wrapped NMS object. + */ + public AbstractWrapper(Class handleType) { + this.handleType = Preconditions.checkNotNull(handleType, "handleType cannot be NULL"); + } + + /** + * Set the underlying NMS object. + * @param handle - the NMS object. + * @throws IllegalArgumentException If the handle is NULL. + * @throws IllegalArgumentException If the handle is not assignable to {@link #getHandleType()}. + */ + protected void setHandle(Object handle) { + if (handle == null) + throw new IllegalArgumentException("handle cannot be NULL."); + if (!handleType.isAssignableFrom(handle.getClass())) + throw new IllegalArgumentException("handle (" + handle + ") is not a " + handleType); + this.handle = handle; + } + + /** + * Retrieves the underlying NMS object. + * @return The underlying NMS object. + */ + public Object getHandle() { + return handle; + } + + /** + * Retrieve the type of the handle. + * @return The type of the handle. + */ + public Class getHandleType() { + return handleType; + } +} diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedAttribute.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedAttribute.java index 620a86d2..a4e3b639 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedAttribute.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedAttribute.java @@ -24,7 +24,7 @@ import com.google.common.collect.Sets; * Represents a single attribute sent in packet 44. * @author Kristian */ -public class WrappedAttribute { +public class WrappedAttribute extends AbstractWrapper { // Shared structure modifier private static StructureModifier ATTRIBUTE_MODIFIER; @@ -43,6 +43,22 @@ public class WrappedAttribute { // Cached modifiers list private Set attributeModifiers; + /** + * Construct a wrapper around a specific NMS instance. + * @param handle - the NMS instance. + */ + private WrappedAttribute(@Nonnull Object handle) { + super(MinecraftReflection.getAttributeSnapshotClass()); + setHandle(handle); + + // Initialize modifier + if (ATTRIBUTE_MODIFIER == null) { + ATTRIBUTE_MODIFIER = new StructureModifier(MinecraftReflection.getAttributeSnapshotClass()); + } + this.modifier = ATTRIBUTE_MODIFIER.withTarget(handle); + } + + /** * Construct a new wrapped attribute around a specific NMS instance. * @param handle - handle to a NMS AttributeSnapshot. @@ -70,33 +86,6 @@ public class WrappedAttribute { return new Builder(Preconditions.checkNotNull(template, "template cannot be NULL.")); } - /** - * Construct a wrapper around a specific NMS instance. - * @param handle - the NMS instance. - */ - private WrappedAttribute(@Nonnull Object handle) { - this.handle = Preconditions.checkNotNull(handle, "handle cannot be NULL."); - - // Check handle type - if (!MinecraftReflection.getAttributeSnapshotClass().isAssignableFrom(handle.getClass())) { - throw new IllegalArgumentException("handle (" + handle + ") must be a AttributeSnapshot."); - } - - // Initialize modifier - if (ATTRIBUTE_MODIFIER == null) { - ATTRIBUTE_MODIFIER = new StructureModifier(MinecraftReflection.getAttributeSnapshotClass()); - } - this.modifier = ATTRIBUTE_MODIFIER.withTarget(handle); - } - - /** - * Retrieve the underlying NMS attribute snapshot. - * @return The underlying attribute snapshot. - */ - public Object getHandle() { - return handle; - } - /** * Retrieve the unique attribute key that identifies its function. *

diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedAttributeModifier.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedAttributeModifier.java index bc857a03..3fd769be 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedAttributeModifier.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedAttributeModifier.java @@ -19,7 +19,7 @@ import com.google.common.base.Preconditions; * * @author Kristian */ -public class WrappedAttributeModifier { +public class WrappedAttributeModifier extends AbstractWrapper { /** * Represents the different modifier operations. *

@@ -86,10 +86,7 @@ public class WrappedAttributeModifier { // The constructor we are interested in private static Constructor ATTRIBUTE_MODIFIER_CONSTRUCTOR; - /** - * Handle to the underlying AttributeModifier. - */ - protected Object handle; + // A modifier for the wrapped handler protected StructureModifier modifier; // Cached values @@ -98,6 +95,58 @@ public class WrappedAttributeModifier { private final Operation operation; private final double amount; + /** + * Construct a new wrapped attribute modifier with no associated handle. + *

+ * Note that the handle object is not initialized after this constructor. + * @param uuid - the UUID. + * @param name - the human readable name. + * @param amount - the amount. + * @param operation - the operation. + */ + protected WrappedAttributeModifier(UUID uuid, String name, double amount, Operation operation) { + super(MinecraftReflection.getAttributeModifierClass()); + + // Use the supplied values instead of reading from the NMS instance + this.uuid = uuid; + this.name = name; + this.amount = amount; + this.operation = operation; + } + + /** + * Construct an attribute modifier wrapper around a given NMS instance. + * @param handle - the NMS instance. + */ + protected WrappedAttributeModifier(@Nonnull Object handle) { + // Update handle and modifier + super(MinecraftReflection.getAttributeModifierClass()); + setHandle(handle); + initializeModifier(handle); + + // Load final values, caching them + this.uuid = (UUID) modifier.withType(UUID.class).read(0); + this.name = (String) modifier.withType(String.class).read(0); + this.amount = (Double) modifier.withType(double.class).read(0); + this.operation = Operation.fromId((Integer) modifier.withType(int.class).read(0)); + } + + /** + * Construct an attribute modifier wrapper around a NMS instance. + * @param handle - the NMS instance. + * @param uuid - the UUID. + * @param name - the human readable name. + * @param amount - the amount. + * @param operation - the operation. + */ + protected WrappedAttributeModifier(@Nonnull Object handle, UUID uuid, String name, double amount, Operation operation) { + this(uuid, name, amount, operation); + + // Initialize handle and modifier + setHandle(handle); + initializeModifier(handle); + } + /** * Construct a new attribute modifier builder. *

@@ -135,54 +184,7 @@ public class WrappedAttributeModifier { public static WrappedAttributeModifier fromHandle(@Nonnull Object handle) { return new WrappedAttributeModifier(handle); } - - /** - * Construct a new wrapped attribute modifier with no associated handle. - * @param uuid - the UUID. - * @param name - the human readable name. - * @param amount - the amount. - * @param operation - the operation. - */ - protected WrappedAttributeModifier(UUID uuid, String name, double amount, Operation operation) { - // Use the supplied values instead of reading from the NMS instance - this.uuid = uuid; - this.name = name; - this.amount = amount; - this.operation = operation; - } - - /** - * Construct an attribute modifier wrapper around a given NMS instance. - * @param handle - the NMS instance. - */ - protected WrappedAttributeModifier(@Nonnull Object handle) { - // Update handle and modifier - setHandle(handle); - initializeModifier(handle); - // Load final values, caching them - this.uuid = (UUID) modifier.withType(UUID.class).read(0); - this.name = (String) modifier.withType(String.class).read(0); - this.amount = (Double) modifier.withType(double.class).read(0); - this.operation = Operation.fromId((Integer) modifier.withType(int.class).read(0)); - } - - /** - * Construct an attribute modifier wrapper around a NMS instance. - * @param handle - the NMS instance. - * @param uuid - the UUID. - * @param name - the human readable name. - * @param amount - the amount. - * @param operation - the operation. - */ - protected WrappedAttributeModifier(@Nonnull Object handle, UUID uuid, String name, double amount, Operation operation) { - this(uuid, name, amount, operation); - - // Initialize handle and modifier - setHandle(handle); - initializeModifier(handle); - } - /** * Initialize modifier from a given handle. * @param handle - the handle. @@ -196,17 +198,6 @@ public class WrappedAttributeModifier { this.modifier = BASE_MODIFIER.withTarget(handle); } - /** - * Set the handle of a modifier. - * @param handle - the underlying handle. - */ - private void setHandle(Object handle) { - // Check handle type - if (!MinecraftReflection.getAttributeModifierClass().isAssignableFrom(handle.getClass())) - throw new IllegalArgumentException("handle (" + handle + ") must be a AttributeModifier."); - this.handle = handle; - } - /** * Retrieve the unique UUID that identifies the origin of this modifier. * @return The unique UUID. @@ -241,16 +232,6 @@ public class WrappedAttributeModifier { return amount; } - /** - * Invoked when we need to construct a handle object. - */ - protected void checkHandle() { - if (handle == null) { - handle = newBuilder(this).build().getHandle(); - initializeModifier(handle); - } - } - /** * Retrieve the underlying attribute modifier. * @return The underlying modifier. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java index 057a5f3f..fcdc7300 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java @@ -11,7 +11,7 @@ import com.comphenix.protocol.utility.MinecraftReflection; * Represents a chat component added in Minecraft 1.7.2 * @author Kristian */ -public class WrappedChatComponent { +public class WrappedChatComponent extends AbstractWrapper { private static final Class SERIALIZER = MinecraftReflection.getChatSerializer(); private static final Class COMPONENT = MinecraftReflection.getIChatBaseComponent(); private static MethodAccessor SERIALIZE_COMPONENT = null; @@ -32,11 +32,11 @@ public class WrappedChatComponent { MinecraftReflection.getCraftChatMessage(), "fromString", String.class); } - private Object handle; private transient String cache; private WrappedChatComponent(Object handle, String cache) { - this.handle = handle; + super(MinecraftReflection.getIChatBaseComponent()); + setHandle(handle); this.cache = cache; } @@ -46,10 +46,6 @@ public class WrappedChatComponent { * @return The wrapper. */ public static WrappedChatComponent fromHandle(Object handle) { - if (handle == null) - throw new IllegalArgumentException("handle cannot be NULL."); - if (!COMPONENT.isAssignableFrom(handle.getClass())) - throw new IllegalArgumentException("handle (" + handle + ") is not a " + COMPONENT); return new WrappedChatComponent(handle, null); } @@ -100,14 +96,6 @@ public class WrappedChatComponent { this.handle = DESERIALIZE_COMPONENT.invoke(null, obj); this.cache = obj; } - - /** - * Retrieve the underlying IChatBaseComponent instance. - * @return The underlying instance. - */ - public Object getHandle() { - return handle; - } @Override public boolean equals(Object obj) { diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinate.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinate.java index 3680261f..ff0790ba 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinate.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinate.java @@ -26,27 +26,26 @@ import com.google.common.base.Objects; * * @author Kristian */ -public class WrappedChunkCoordinate implements Comparable { - +public class WrappedChunkCoordinate extends AbstractWrapper implements Comparable { /** * If TRUE, NULLs should be put before non-null instances of this class. */ private static final boolean LARGER_THAN_NULL = true; - - @SuppressWarnings("rawtypes") - protected Comparable handle; // Used to access a ChunkCoordinate - private static StructureModifier intModifier; + private static StructureModifier SHARED_MODIFIER; + + // The current modifier + private StructureModifier handleModifier; /** * Create a new empty wrapper. */ - @SuppressWarnings("rawtypes") public WrappedChunkCoordinate() { - try { - this.handle = (Comparable) MinecraftReflection.getChunkCoordinatesClass().newInstance(); - initializeModifier(); + super(MinecraftReflection.getChunkCoordinatesClass()); + + try { + setHandle(getHandleType().newInstance()); } catch (Exception e) { throw new RuntimeException("Cannot construct chunk coordinate."); } @@ -58,17 +57,17 @@ public class WrappedChunkCoordinate implements Comparable(handle.getClass(), null, false).withType(int.class); - } + private StructureModifier getModifier() { + if (SHARED_MODIFIER == null) + SHARED_MODIFIER = new StructureModifier(handle.getClass(), null, false).withType(int.class); + if (handleModifier == null) + handleModifier = SHARED_MODIFIER.withTarget(handle); + return handleModifier; } /** @@ -101,7 +100,7 @@ public class WrappedChunkCoordinate implements Comparable) handle).compareTo(other.handle); } @Override 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 8cfdb1d2..c8a71274 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java @@ -52,35 +52,32 @@ import com.google.common.collect.Iterators; * * @author Kristian */ -public class WrappedDataWatcher implements Iterable { +public class WrappedDataWatcher extends AbstractWrapper implements Iterable { /** * Used to assign integer IDs to given types. */ - private static Map, Integer> typeMap; + private static Map, Integer> TYPE_MAP; // Fields - private static Field valueMapField; - private static Field readWriteLockField; - private static Field entityField; + private static Field VALUE_MAP_FIELD; + private static Field READ_WRITE_LOCK_FIELD; + private static Field ENTITY_FIELD; // Methods - private static Method createKeyValueMethod; - private static Method updateKeyValueMethod; - private static Method getKeyValueMethod; + private static Method CREATE_KEY_VALUE_METHOD; + private static Method UPDATE_KEY_VALUE_METHOD; + private static Method GET_KEY_VALUE_METHOD; // Constructors - private static Constructor createDataWatcherConstructor; + private static Constructor CREATE_DATA_WATCHER_CONSTRUCTOR; // Entity methods - private volatile static Field entityDataField; + private volatile static Field ENTITY_DATA_FIELD; /** * Whether or not this class has already been initialized. */ - private static boolean hasInitialized; - - // The underlying DataWatcher we're modifying - protected Object handle; + private static boolean HAS_INITIALIZED; // Lock private ReadWriteLock readWriteLock; @@ -96,12 +93,14 @@ public class WrappedDataWatcher implements Iterable { * @throws FieldAccessException If we're unable to wrap a DataWatcher. */ public WrappedDataWatcher() { + super(MinecraftReflection.getDataWatcherClass()); + // Just create a new watcher try { if (MinecraftReflection.isUsingNetty()) { - this.handle = newEntityHandle(null); + setHandle(newEntityHandle(null)); } else { - this.handle = MinecraftReflection.getDataWatcherClass().newInstance(); + setHandle(getHandleType().newInstance()); } initialize(); @@ -116,12 +115,8 @@ public class WrappedDataWatcher implements Iterable { * @throws FieldAccessException If we're unable to wrap a DataWatcher. */ public WrappedDataWatcher(Object handle) { - if (handle == null) - throw new IllegalArgumentException("Handle cannot be NULL."); - if (!MinecraftReflection.isDataWatcher(handle)) - throw new IllegalArgumentException("The value " + handle + " is not a DataWatcher."); - - this.handle = handle; + super(MinecraftReflection.getDataWatcherClass()); + setHandle(handle); initialize(); } @@ -150,10 +145,10 @@ public class WrappedDataWatcher implements Iterable { Class dataWatcher = MinecraftReflection.getDataWatcherClass(); try { - if (createDataWatcherConstructor == null) - createDataWatcherConstructor = dataWatcher.getConstructor(MinecraftReflection.getEntityClass()); + if (CREATE_DATA_WATCHER_CONSTRUCTOR == null) + CREATE_DATA_WATCHER_CONSTRUCTOR = dataWatcher.getConstructor(MinecraftReflection.getEntityClass()); - return createDataWatcherConstructor.newInstance( + return CREATE_DATA_WATCHER_CONSTRUCTOR.newInstance( BukkitUnwrapper.getInstance().unwrapItem(entity) ); } catch (Exception e) { @@ -190,14 +185,6 @@ public class WrappedDataWatcher implements Iterable { } } - /** - * Retrieves the underlying data watcher. - * @return The underlying data watcher. - */ - public Object getHandle() { - return handle; - } - /** * Retrieve the ID of a given type, if it's allowed to be watched. * @return The ID, or NULL if it cannot be watched. @@ -205,7 +192,7 @@ public class WrappedDataWatcher implements Iterable { */ public static Integer getTypeID(Class clazz) throws FieldAccessException { initialize(); - return typeMap.get(WrappedWatchableObject.getUnwrappedType(clazz)); + return TYPE_MAP.get(WrappedWatchableObject.getUnwrappedType(clazz)); } /** @@ -216,7 +203,7 @@ public class WrappedDataWatcher implements Iterable { public static Class getTypeClass(int id) throws FieldAccessException { initialize(); - for (Map.Entry, Integer> entry : typeMap.entrySet()) { + for (Map.Entry, Integer> entry : TYPE_MAP.entrySet()) { if (Objects.equal(entry.getValue(), id)) { return entry.getKey(); } @@ -462,7 +449,7 @@ public class WrappedDataWatcher implements Iterable { if (watchable != null) { new WrappedWatchableObject(watchable).setValue(newValue, update); } else { - createKeyValueMethod.invoke(handle, index, WrappedWatchableObject.getUnwrapped(newValue)); + CREATE_KEY_VALUE_METHOD.invoke(handle, index, WrappedWatchableObject.getUnwrapped(newValue)); } // Handle invoking the method @@ -479,9 +466,9 @@ public class WrappedDataWatcher implements Iterable { private Object getWatchedObject(int index) throws FieldAccessException { // We use the get-method first and foremost - if (getKeyValueMethod != null) { + if (GET_KEY_VALUE_METHOD != null) { try { - return getKeyValueMethod.invoke(handle, index); + return GET_KEY_VALUE_METHOD.invoke(handle, index); } catch (Exception e) { throw new FieldAccessException("Cannot invoke get key method for index " + index, e); } @@ -506,8 +493,8 @@ public class WrappedDataWatcher implements Iterable { // Cache the read write lock if (readWriteLock != null) return readWriteLock; - else if (readWriteLockField != null) - return readWriteLock = (ReadWriteLock) FieldUtils.readField(readWriteLockField, handle, true); + else if (READ_WRITE_LOCK_FIELD != null) + return readWriteLock = (ReadWriteLock) FieldUtils.readField(READ_WRITE_LOCK_FIELD, handle, true); else return readWriteLock = new ReentrantReadWriteLock(); } catch (IllegalAccessException e) { @@ -524,7 +511,7 @@ public class WrappedDataWatcher implements Iterable { protected Map getWatchableObjectMap() throws FieldAccessException { if (watchableObjects == null) { try { - watchableObjects = (Map) FieldUtils.readField(valueMapField, handle, true); + watchableObjects = (Map) FieldUtils.readField(VALUE_MAP_FIELD, handle, true); } catch (IllegalAccessException e) { throw new FieldAccessException("Cannot read watchable object field.", e); } @@ -539,14 +526,14 @@ public class WrappedDataWatcher implements Iterable { * @throws FieldAccessException Reflection failed. */ public static WrappedDataWatcher getEntityWatcher(Entity entity) throws FieldAccessException { - if (entityDataField == null) - entityDataField = FuzzyReflection.fromClass(MinecraftReflection.getEntityClass(), true). + if (ENTITY_DATA_FIELD == null) + ENTITY_DATA_FIELD = FuzzyReflection.fromClass(MinecraftReflection.getEntityClass(), true). getFieldByType("datawatcher", MinecraftReflection.getDataWatcherClass()); BukkitUnwrapper unwrapper = new BukkitUnwrapper(); try { - Object nsmWatcher = FieldUtils.readField(entityDataField, unwrapper.unwrapItem(entity), true); + Object nsmWatcher = FieldUtils.readField(ENTITY_DATA_FIELD, unwrapper.unwrapItem(entity), true); if (nsmWatcher != null) return new WrappedDataWatcher(nsmWatcher); @@ -564,8 +551,8 @@ public class WrappedDataWatcher implements Iterable { @SuppressWarnings("unchecked") private static void initialize() throws FieldAccessException { // This method should only be run once, even if an exception is thrown - if (!hasInitialized) - hasInitialized = true; + if (!HAS_INITIALIZED) + HAS_INITIALIZED = true; else return; @@ -575,27 +562,27 @@ public class WrappedDataWatcher implements Iterable { if (Modifier.isStatic(lookup.getModifiers())) { // This must be the type map try { - typeMap = (Map, Integer>) FieldUtils.readStaticField(lookup, true); + TYPE_MAP = (Map, Integer>) FieldUtils.readStaticField(lookup, true); } catch (IllegalAccessException e) { throw new FieldAccessException("Cannot access type map field.", e); } } else { // If not, then we're probably dealing with the value map - valueMapField = lookup; + VALUE_MAP_FIELD = lookup; } } try { - readWriteLockField = fuzzy.getFieldByType("readWriteLock", ReadWriteLock.class); + READ_WRITE_LOCK_FIELD = fuzzy.getFieldByType("readWriteLock", ReadWriteLock.class); } catch (IllegalArgumentException e) { // It's not a big deal } // Check for the entity field as well if (MinecraftReflection.isUsingNetty()) { - entityField = fuzzy.getFieldByType("entity", MinecraftReflection.getEntityClass()); - entityField.setAccessible(true); + ENTITY_FIELD = fuzzy.getFieldByType("entity", MinecraftReflection.getEntityClass()); + ENTITY_FIELD.setAccessible(true); } initializeMethods(fuzzy); } @@ -606,9 +593,9 @@ public class WrappedDataWatcher implements Iterable { // Load the get-method try { - getKeyValueMethod = fuzzy.getMethodByParameters( + GET_KEY_VALUE_METHOD = fuzzy.getMethodByParameters( "getWatchableObject", MinecraftReflection.getWatchableObjectClass(), new Class[] { int.class }); - getKeyValueMethod.setAccessible(true); + GET_KEY_VALUE_METHOD.setAccessible(true); } catch (IllegalArgumentException e) { // Use the fallback method @@ -616,18 +603,18 @@ public class WrappedDataWatcher implements Iterable { for (Method method : candidates) { if (!method.getName().startsWith("watch")) { - createKeyValueMethod = method; + CREATE_KEY_VALUE_METHOD = method; } else { - updateKeyValueMethod = method; + UPDATE_KEY_VALUE_METHOD = method; } } // Did we succeed? - if (updateKeyValueMethod == null || createKeyValueMethod == null) { + if (UPDATE_KEY_VALUE_METHOD == null || CREATE_KEY_VALUE_METHOD == null) { // Go by index instead if (candidates.size() > 1) { - createKeyValueMethod = candidates.get(0); - updateKeyValueMethod = candidates.get(1); + CREATE_KEY_VALUE_METHOD = candidates.get(0); + UPDATE_KEY_VALUE_METHOD = candidates.get(1); } else { throw new IllegalStateException("Unable to find create and update watchable object. Update ProtocolLib."); } @@ -643,8 +630,8 @@ public class WrappedDataWatcher implements Iterable { } } catch (Exception e) { // Nope - updateKeyValueMethod = candidates.get(0); - createKeyValueMethod = candidates.get(1); + UPDATE_KEY_VALUE_METHOD = candidates.get(0); + CREATE_KEY_VALUE_METHOD = candidates.get(1); } } } @@ -709,7 +696,7 @@ public class WrappedDataWatcher implements Iterable { throw new IllegalStateException("This method is only supported on 1.7.2 and above."); try { - return (Entity) MinecraftReflection.getBukkitEntity(entityField.get(handle)); + return (Entity) MinecraftReflection.getBukkitEntity(ENTITY_FIELD.get(handle)); } catch (Exception e) { throw new RuntimeException("Unable to retrieve entity.", e); } @@ -726,7 +713,7 @@ public class WrappedDataWatcher implements Iterable { throw new IllegalStateException("This method is only supported on 1.7.2 and above."); try { - entityField.set(handle, BukkitUnwrapper.getInstance().unwrapItem(entity)); + ENTITY_FIELD.set(handle, BukkitUnwrapper.getInstance().unwrapItem(entity)); } catch (Exception e) { throw new RuntimeException("Unable to set entity.", e); } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java index 07dd9f14..2be8e59e 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java @@ -6,16 +6,11 @@ import net.minecraft.util.com.mojang.authlib.GameProfile; * Represents a wrapper for a game profile. * @author Kristian */ -public class WrappedGameProfile { - private GameProfile profile; - +public class WrappedGameProfile extends AbstractWrapper { // Profile from a handle private WrappedGameProfile(Object profile) { - if (profile == null) - throw new IllegalArgumentException("Profile cannot be NULL."); - if (!(profile instanceof GameProfile)) - throw new IllegalArgumentException(profile + " is not a GameProfile"); - this.profile = (GameProfile) profile; + super(GameProfile.class); + setHandle(profile); } /** @@ -34,21 +29,13 @@ public class WrappedGameProfile { public static WrappedGameProfile fromHandle(Object handle) { return new WrappedGameProfile(handle); } - - /** - * Retrieve the underlying game profile. - * @return The profile. - */ - public Object getHandle() { - return profile; - } /** * Retrieve the UUID of the player. * @return The UUID of the player, or NULL if not computed. */ public String getId() { - return profile.getId(); + return getProfile().getId(); } /** @@ -56,7 +43,11 @@ public class WrappedGameProfile { * @return The player name. */ public String getName() { - return profile.getName(); + return getProfile().getName(); + } + + private GameProfile getProfile() { + return (GameProfile) handle; } /** @@ -82,12 +73,12 @@ public class WrappedGameProfile { * @return TRUE if it does, FALSE otherwise. */ public boolean isComplete() { - return profile.isComplete(); + return getProfile().isComplete(); } @Override public int hashCode() { - return profile.hashCode(); + return getProfile().hashCode(); } @Override @@ -97,7 +88,7 @@ public class WrappedGameProfile { if (obj instanceof WrappedGameProfile) { WrappedGameProfile other = (WrappedGameProfile) obj; - return profile.equals(other.profile); + return getProfile().equals(other.getProfile()); } return false; } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedIntHashMap.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedIntHashMap.java index 65231245..0b16d168 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedIntHashMap.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedIntHashMap.java @@ -15,21 +15,18 @@ import com.google.common.base.Preconditions; * Represents a wrapper for the internal IntHashMap in Minecraft. * @author Kristian */ -public class WrappedIntHashMap { - private static final Class INT_HASH_MAP = MinecraftReflection.getIntHashMapClass(); - +public class WrappedIntHashMap extends AbstractWrapper { private static Method PUT_METHOD; private static Method GET_METHOD; private static Method REMOVE_METHOD; - private Object handle; - /** * Construct an IntHashMap wrapper around an instance. * @param handle - the NMS instance. */ private WrappedIntHashMap(Object handle) { - this.handle = handle; + super(MinecraftReflection.getIntHashMapClass()); + setHandle(handle); } /** @@ -38,7 +35,7 @@ public class WrappedIntHashMap { */ public static WrappedIntHashMap newMap() { try { - return new WrappedIntHashMap(INT_HASH_MAP.newInstance()); + return new WrappedIntHashMap(MinecraftReflection.getIntHashMapClass().newInstance()); } catch (Exception e) { throw new RuntimeException("Unable to construct IntHashMap.", e); } @@ -51,10 +48,6 @@ public class WrappedIntHashMap { * @throws IllegalArgumentException If the handle is not an IntHasMap. */ public static WrappedIntHashMap fromHandle(@Nonnull Object handle) { - Preconditions.checkNotNull(handle, "handle cannot be NULL"); - Preconditions.checkState(MinecraftReflection.isIntHashMap(handle), - "handle is a " + handle.getClass() + ", not an IntHashMap."); - return new WrappedIntHashMap(handle); } @@ -138,7 +131,7 @@ public class WrappedIntHashMap { private void initializePutMethod() { if (PUT_METHOD == null) { // Fairly straight forward - PUT_METHOD = FuzzyReflection.fromClass(INT_HASH_MAP).getMethod( + PUT_METHOD = FuzzyReflection.fromClass(MinecraftReflection.getIntHashMapClass()).getMethod( FuzzyMethodContract.newBuilder(). banModifier(Modifier.STATIC). parameterCount(2). @@ -154,7 +147,7 @@ public class WrappedIntHashMap { String expected = "hello"; // Determine which method to trust - for (Method method : FuzzyReflection.fromClass(INT_HASH_MAP). + for (Method method : FuzzyReflection.fromClass(MinecraftReflection.getIntHashMapClass()). getMethodListByParameters(Object.class, new Class[] { int.class })) { // Initialize a value @@ -183,12 +176,4 @@ public class WrappedIntHashMap { throw new IllegalStateException("Unable to find appropriate GET_METHOD for IntHashMap."); } } - - /** - * Retrieve the underlying IntHashMap object. - * @return The underlying object. - */ - public Object getHandle() { - return handle; - } } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java index 028a226c..9c849efe 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java @@ -33,8 +33,7 @@ import com.google.common.base.Objects; * * @author Kristian */ -public class WrappedWatchableObject { - +public class WrappedWatchableObject extends AbstractWrapper { // Whether or not the reflection machinery has been initialized private static boolean hasInitialized; @@ -47,7 +46,6 @@ public class WrappedWatchableObject { // The watchable object class type private static Class watchableObjectClass; - protected Object handle; protected StructureModifier modifier; // Type of the stored value @@ -58,6 +56,7 @@ public class WrappedWatchableObject { * @param handle - the raw watchable object to wrap. */ public WrappedWatchableObject(Object handle) { + super(MinecraftReflection.getWatchableObjectClass()); load(handle); } @@ -67,6 +66,8 @@ public class WrappedWatchableObject { * @param value - non-null value of specific types. */ public WrappedWatchableObject(int index, Object value) { + super(MinecraftReflection.getWatchableObjectClass()); + if (value == null) throw new IllegalArgumentException("Value cannot be NULL."); @@ -107,14 +108,6 @@ public class WrappedWatchableObject { } } - /** - * Retrieves the underlying watchable object. - * @return The underlying watchable object. - */ - public Object getHandle() { - return handle; - } - /** * Initialize reflection machinery. */ diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinateTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinateTest.java new file mode 100644 index 00000000..325885b6 --- /dev/null +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinateTest.java @@ -0,0 +1,24 @@ +package com.comphenix.protocol.wrappers; + +import static org.junit.Assert.*; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.comphenix.protocol.BukkitInitialization; + +public class WrappedChunkCoordinateTest { + @BeforeClass + public static void initializeBukkit() throws IllegalAccessException { + BukkitInitialization.initializePackage(); + } + + @Test + public void test() { + WrappedChunkCoordinate coordinate = new WrappedChunkCoordinate(1, 2, 3); + + assertEquals(1, coordinate.getX()); + assertEquals(2, coordinate.getY()); + assertEquals(3, coordinate.getZ()); + } +} diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedIntHashMapTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedIntHashMapTest.java new file mode 100644 index 00000000..939a71cd --- /dev/null +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedIntHashMapTest.java @@ -0,0 +1,24 @@ +package com.comphenix.protocol.wrappers; + +import static org.junit.Assert.*; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.comphenix.protocol.BukkitInitialization; + +public class WrappedIntHashMapTest { + @BeforeClass + public static void initializeBukkit() throws IllegalAccessException { + BukkitInitialization.initializePackage(); + } + + @Test + public void testIntMap() { + WrappedIntHashMap test = WrappedIntHashMap.newMap(); + test.put(1, "hello"); + + assertNull(test.get(0)); + assertEquals(test.get(1), "hello"); + } +}