From 5115bcaf98ca0a53497096bcf1e924f39dd62ca6 Mon Sep 17 00:00:00 2001 From: Dan Mulloy Date: Sun, 6 Mar 2016 14:02:45 -0500 Subject: [PATCH] Add an optional cloner, fix sound cloning, clean up the data watcher --- .../protocol/events/PacketContainer.java | 2 + .../reflect/cloning/ImmutableDetector.java | 10 ++ .../reflect/cloning/OptionalCloner.java | 39 +++++ .../protocol/wrappers/WrappedDataWatcher.java | 134 ++++++++++-------- 4 files changed, 122 insertions(+), 63 deletions(-) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/OptionalCloner.java diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java index 7499d9ae..f5eb6262 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -61,6 +61,7 @@ import com.comphenix.protocol.reflect.cloning.Cloner; import com.comphenix.protocol.reflect.cloning.CollectionCloner; import com.comphenix.protocol.reflect.cloning.FieldCloner; import com.comphenix.protocol.reflect.cloning.ImmutableDetector; +import com.comphenix.protocol.reflect.cloning.OptionalCloner; import com.comphenix.protocol.reflect.cloning.SerializableCloner; import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; import com.comphenix.protocol.reflect.instances.DefaultInstances; @@ -125,6 +126,7 @@ public class PacketContainer implements Serializable { instanceProvider(DefaultInstances.DEFAULT). andThen(BukkitCloner.class). andThen(ImmutableDetector.class). + andThen(OptionalCloner.class). andThen(CollectionCloner.class). andThen(getSpecializedDeepClonerFactory()). build(); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/ImmutableDetector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/ImmutableDetector.java index c5801b9f..1a03909b 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/ImmutableDetector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/ImmutableDetector.java @@ -72,6 +72,7 @@ public class ImmutableDetector implements Cloner { // All primitive types if (Primitives.isWrapperType(type) || String.class.equals(type)) return true; + // May not be true, but if so, that kind of code is broken anyways if (isEnumWorkaround(type)) return true; @@ -86,6 +87,15 @@ public class ImmutableDetector implements Cloner { return true; } } + + // Check for known immutable classes in 1.9 + if (MinecraftReflection.dataWatcherItemExists()) { + if (type.equals(MinecraftReflection.getDataWatcherSerializerClass()) + || type.equals(MinecraftReflection.getMinecraftClass("SoundEffect"))) { + return true; + } + } + // Probably not return false; } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/OptionalCloner.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/OptionalCloner.java new file mode 100644 index 00000000..7f583109 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/OptionalCloner.java @@ -0,0 +1,39 @@ +/** + * (c) 2016 dmulloy2 + */ +package com.comphenix.protocol.reflect.cloning; + +import com.google.common.base.Optional; + +/** + * A cloner that can clone Optional objects + * @author dmulloy2 + */ + +public class OptionalCloner implements Cloner { + protected Cloner wrapped; + + public OptionalCloner(Cloner wrapped) { + this.wrapped = wrapped; + } + + @Override + public boolean canClone(Object source) { + return source instanceof Optional; + } + + @Override + public Object clone(Object source) { + Optional optional = (Optional) source; + if (!optional.isPresent()) { + return Optional.absent(); + } + + // Clone the inner value + return Optional.of(wrapped.clone(optional.get())); + } + + public Cloner getWrapped() { + return wrapped; + } +} \ No newline at end of file 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 9f871eed..3992eaab 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java @@ -26,7 +26,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; +import java.util.Set; import org.apache.commons.lang.Validate; import org.bukkit.entity.Entity; @@ -34,7 +34,6 @@ import org.bukkit.inventory.ItemStack; import com.comphenix.protocol.injector.BukkitUnwrapper; import com.comphenix.protocol.reflect.FieldAccessException; -import com.comphenix.protocol.reflect.FieldUtils; import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.accessors.Accessors; @@ -43,6 +42,7 @@ 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.comphenix.protocol.wrappers.collection.ConvertedMap; import com.google.common.base.Optional; /** @@ -54,12 +54,12 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable HANDLE_TYPE = MinecraftReflection.getDataWatcherClass(); private static MethodAccessor GETTER = null; - public static MethodAccessor SETTER = null; - public static MethodAccessor REGISTER = null; + private static MethodAccessor SETTER = null; + private static MethodAccessor REGISTER = null; + private static FieldAccessor ENTITY_DATA_FIELD = null; private static FieldAccessor ENTITY_FIELD = null; private static FieldAccessor MAP_FIELD = null; - private static Field ENTITY_DATA_FIELD = null; private static ConstructorAccessor constructor = null; private static ConstructorAccessor lightningConstructor = null; @@ -117,24 +117,26 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable getMap() { - FuzzyReflection fuzzy = FuzzyReflection.fromClass(handleType, true); - List candidates = fuzzy.getFieldListByType(Map.class); + private Map getMap() { + if (MAP_FIELD == null) { + FuzzyReflection fuzzy = FuzzyReflection.fromClass(handleType, true); + List candidates = fuzzy.getFieldListByType(Map.class); - for (Field candidate : candidates) { - if (Modifier.isStatic(candidate.getModifiers())) { - // This is the entity class to current index map, which we really don't have a use for - } else { - // This is the map we're looking for - MAP_FIELD = Accessors.getFieldAccessor(candidate); + for (Field candidate : candidates) { + if (Modifier.isStatic(candidate.getModifiers())) { + // This is the entity class to current index map, which we really don't have a use for + } else { + // This is the map we're looking for + MAP_FIELD = Accessors.getFieldAccessor(candidate); + } } } if (MAP_FIELD == null) { - throw new FieldAccessException("Could not find index -> object map."); + throw new FieldAccessException("Could not find index <-> Item map."); } - return (Map) MAP_FIELD.get(handle); + return (Map) MAP_FIELD.get(handle); } /** @@ -142,13 +144,25 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable asMap() { - Map ret = new HashMap<>(); + return new ConvertedMap(getMap()) { + @Override + protected WrappedWatchableObject toOuter(Object inner) { + return inner != null ? new WrappedWatchableObject(inner) : null; + } - for (Entry entry : getMap().entrySet()) { - ret.put(entry.getKey(), new WrappedWatchableObject(entry.getValue())); - } + @Override + protected Object toInner(WrappedWatchableObject outer) { + return outer != null ? outer.getHandle() : null; + } + }; + } - return ret; + /** + * Gets a set containing the registered indexes. + * @return The set + */ + public Set getIndexes() { + return getMap().keySet(); } /** @@ -173,9 +187,9 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable - * Warning: This is only supported on 1.7.2 and above. - * * @return The entity, or NULL. */ public Entity getEntity() { - if (!MinecraftReflection.isUsingNetty()) - throw new IllegalStateException("This method is only supported on 1.7.2 and above."); - if (ENTITY_FIELD == null) { ENTITY_FIELD = Accessors.getFieldAccessor(HANDLE_TYPE, MinecraftReflection.getEntityClass(), true); } - try { - return (Entity) MinecraftReflection.getBukkitEntity(ENTITY_FIELD.get(handle)); - } catch (Exception e) { - throw new RuntimeException("Unable to retrieve entity.", e); - } + return (Entity) MinecraftReflection.getBukkitEntity(ENTITY_FIELD.get(handle)); } /** * Set the entity associated with this data watcher. - *

- * Warning: This is only supported on 1.7.2 and above. - * * @param entity - the new entity. */ public void setEntity(Entity entity) { - if (!MinecraftReflection.isUsingNetty()) - throw new IllegalStateException("This method is only supported on 1.7.2 and above."); - if (ENTITY_FIELD == null) { ENTITY_FIELD = Accessors.getFieldAccessor(HANDLE_TYPE, MinecraftReflection.getEntityClass(), true); } - try { - ENTITY_FIELD.set(handle, BukkitUnwrapper.getInstance().unwrapItem(entity)); - } catch (Exception e) { - throw new RuntimeException("Unable to set entity.", e); - } + ENTITY_FIELD.set(handle, BukkitUnwrapper.getInstance().unwrapItem(entity)); } /** @@ -489,6 +487,13 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable clazz) { + Validate.notNull("Class cannot be null!"); initialize(); + return REGISTRY.get(clazz); } @@ -648,6 +655,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable