From 242b25eb1ef5f745072023ee8033cc2855e56d03 Mon Sep 17 00:00:00 2001 From: Dan Mulloy Date: Wed, 6 Jul 2016 15:47:24 -0400 Subject: [PATCH] Wrap all serializable objects in data watchers --- .../protocol/wrappers/BukkitConverters.java | 2 +- .../comphenix/protocol/wrappers/Vector3F.java | 110 ++++++++++++++++++ .../protocol/wrappers/WrappedDataWatcher.java | 80 ++++++++++++- .../wrappers/WrappedWatchableObject.java | 68 ++++++++--- 4 files changed, 237 insertions(+), 23 deletions(-) create mode 100644 modules/API/src/main/java/com/comphenix/protocol/wrappers/Vector3F.java diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java index 37c10b64..2d01f412 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java @@ -124,7 +124,7 @@ public class BukkitConverters { * @author Kristian * @param - type that can be converted. */ - private static abstract class IgnoreNullConverter implements EquivalentConverter { + public static abstract class IgnoreNullConverter implements EquivalentConverter { @Override public final Object getGeneric(Class genericType, TType specific) { if (specific != null) diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/Vector3F.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/Vector3F.java new file mode 100644 index 00000000..776fe6b5 --- /dev/null +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/Vector3F.java @@ -0,0 +1,110 @@ +/** + * (c) 2016 dmulloy2 + */ +package com.comphenix.protocol.wrappers; + +import java.lang.reflect.Constructor; + +import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.BukkitConverters.IgnoreNullConverter; + +/** + * @author dmulloy2 + */ +public class Vector3F { + protected float x; + protected float y; + protected float z; + + public Vector3F() { + this(0, 0, 0); + } + + public Vector3F(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + public float getX() { + return x; + } + + public Vector3F setX(float x) { + this.x = x; + return this; + } + + public float getY() { + return y; + } + + public Vector3F setY(float y) { + this.y = y; + return this; + } + + public float getZ() { + return z; + } + + public Vector3F setZ(float z) { + this.z = z; + return this; + } + + public boolean equals(Object object) { + if (object instanceof Vector3F) { + Vector3F that = (Vector3F) object; + return this.x == that.x && this.y == that.y && this.z == that.z; + } + + return false; + } + + private static Constructor constructor = null; + private static Class clazz = MinecraftReflection.getMinecraftClass("Vector3f"); + + public static Class getMinecraftClass() { + return clazz; + } + + public static EquivalentConverter getConverter() { + return new IgnoreNullConverter() { + + @Override + public Class getSpecificType() { + return Vector3F.class; + } + + @Override + protected Object getGenericValue(Class genericType, Vector3F specific) { + if (constructor == null) { + try { + constructor = clazz.getConstructor(float.class, float.class, float.class); + } catch (ReflectiveOperationException ex) { + throw new RuntimeException("Failed to find constructor for Vector3f", ex); + } + } + + try { + return constructor.newInstance(specific.x, specific.y, specific.z); + } catch (ReflectiveOperationException ex) { + throw new RuntimeException("Failed to create new instance of Vector3f", ex); + } + } + + @Override + protected Vector3F getSpecificValue(Object generic) { + StructureModifier modifier = new StructureModifier(generic.getClass()) + .withTarget(generic).withType(float.class); + float x = modifier.read(0); + float y = modifier.read(1); + float z = modifier.read(2); + return new Vector3F(x, y, z); + } + }; + } +} \ No newline at end of file diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java index 0bb2e391..2ac6a118 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java @@ -25,6 +25,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import org.apache.commons.lang.Validate; import org.bukkit.entity.Entity; @@ -234,7 +235,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterablemust be wrapped in an {@link Optional} + * @return The serializer + */ + public static Serializer getItemStackSerializer(boolean optional) { + return get(MinecraftReflection.getItemStackClass(), optional); + } + + /** + * Gets the serializer for BlockData + * @param optional If true, objects must be wrapped in an {@link Optional} + * @return The serializer + */ + public static Serializer getBlockDataSerializer(boolean optional) { + return get(MinecraftReflection.getIBlockDataClass(), optional); + } + + /** + * Gets the serializer for Vector3Fs + * @return The serializer + */ + public static Serializer getVectorSerializer() { + return get(Vector3F.getMinecraftClass()); + } + + /** + * Gets the serializer for BlockPositions + * @param optional If true, objects must be wrapped in an {@link Optional} + * @return The serializer + */ + public static Serializer getBlockPositionSerializer(boolean optional) { + return get(MinecraftReflection.getBlockPositionClass(), optional); + } + + /** + * Gets the serializer for Directions + * @return The serializer + */ + public static Serializer getDirectionSerializer() { + return get(EnumWrappers.getDirectionClass()); + } + + /** + * Gets the serializer for UUIDs + * @param optional If true, objects must be wrapped in an {@link Optional} + * @return The serializer + */ + public static Serializer getUUIDSerializer(boolean optional) { + return get(UUID.class, optional); + } } } diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java index 63355931..1415445c 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java +++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java @@ -22,6 +22,8 @@ import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.EnumWrappers.Direction; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; import com.google.common.base.Optional; @@ -158,7 +160,8 @@ public class WrappedWatchableObject extends AbstractWrapper { // ---- Wrapping /** - * Retrieve the wrapped object value, if needed. + * Retrieve the wrapped object value, if needed. All non-primitive objects + * with {@link Serializer}s should be covered by this. * * @param value - the raw NMS object to wrap. * @return The wrapped object. @@ -175,17 +178,37 @@ public class WrappedWatchableObject extends AbstractWrapper { } } - if (MinecraftReflection.isItemStack(value)) { + // Current supported classes + if (is(MinecraftReflection.getIChatBaseComponentClass(), value)) { + return WrappedChatComponent.fromHandle(value); + } else if (is(MinecraftReflection.getItemStackClass(), value)) { return BukkitConverters.getItemStackConverter().getSpecific(value); - } else if (MinecraftReflection.isChunkCoordinates(value)) { - return new WrappedChunkCoordinate((Comparable) value); - } else if (MinecraftReflection.isBlockPosition(value)) { + } else if (is(MinecraftReflection.getIBlockDataClass(), value)) { + return BukkitConverters.getWrappedBlockDataConverter().getSpecific(value); + } else if (is (Vector3F.getMinecraftClass(), value)) { + return Vector3F.getConverter().getSpecific(value); + } else if (is(MinecraftReflection.getBlockPositionClass(), value)) { return BlockPosition.getConverter().getSpecific(value); - } else if (MinecraftReflection.isChunkPosition(value)) { - return ChunkPosition.getConverter().getSpecific(value); - } else { - return value; + } else if (is(EnumWrappers.getDirectionClass(), value)) { + return EnumWrappers.getDirectionConverter().getSpecific(value); } + + // Legacy classes + if (is(MinecraftReflection.getChunkCoordinatesClass(), value)) { + return new WrappedChunkCoordinate((Comparable) value); + } else if (is(MinecraftReflection.getChunkPositionClass(), value)) { + return ChunkPosition.getConverter().getSpecific(value); + } + + return value; + } + + private static boolean is(Class clazz, Object object) { + if (clazz == null || object == null) { + return false; + } + + return clazz.isAssignableFrom(object.getClass()); } /** @@ -194,6 +217,7 @@ public class WrappedWatchableObject extends AbstractWrapper { * @param wrapped - the wrapped position. * @return The raw NMS object. */ + // Must be kept in sync with getWrapped! static Object getUnwrapped(Object wrapped) { if (wrapped instanceof Optional) { Optional optional = (Optional) wrapped; @@ -204,16 +228,28 @@ public class WrappedWatchableObject extends AbstractWrapper { } } - if (wrapped instanceof ItemStack) { + // Current supported classes + if (wrapped instanceof WrappedChatComponent) { + return ((WrappedChatComponent) wrapped).getHandle(); + } else if (wrapped instanceof ItemStack) { return BukkitConverters.getItemStackConverter().getGeneric(MinecraftReflection.getItemStackClass(), (ItemStack) wrapped); - } else if (wrapped instanceof WrappedChunkCoordinate) { - return ((WrappedChunkCoordinate) wrapped).getHandle(); + } else if (wrapped instanceof WrappedBlockData) { + return BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), (WrappedBlockData) wrapped); + } else if (wrapped instanceof Vector3F) { + return Vector3F.getConverter().getGeneric(Vector3F.getMinecraftClass(), (Vector3F) wrapped); } else if (wrapped instanceof BlockPosition) { return BlockPosition.getConverter().getGeneric(MinecraftReflection.getBlockPositionClass(), (BlockPosition) wrapped); - } else if (wrapped instanceof ChunkPosition) { - return ChunkPosition.getConverter().getGeneric(MinecraftReflection.getChunkPositionClass(), (ChunkPosition) wrapped); - } else { - return wrapped; + } else if (wrapped instanceof Direction) { + return EnumWrappers.getDirectionConverter().getGeneric(EnumWrappers.getDirectionClass(), (Direction) wrapped); } + + // Legacy classes + if (wrapped instanceof ChunkPosition) { + return ChunkPosition.getConverter().getGeneric(MinecraftReflection.getChunkPositionClass(), (ChunkPosition) wrapped); + } else if (wrapped instanceof WrappedChunkCoordinate) { + return ((WrappedChunkCoordinate) wrapped).getHandle(); + } + + return wrapped; } }