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 266d45cd..c724a266 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -43,8 +43,11 @@ import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.ObjectWriter; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.cloning.AggregateCloner; +import com.comphenix.protocol.reflect.cloning.BukkitCloner; 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.AggregateCloner.BuilderParameters; import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.utility.MinecraftReflection; @@ -78,7 +81,14 @@ public class PacketContainer implements Serializable { private static ConcurrentMap, Method> readMethods = Maps.newConcurrentMap(); // Used to clone packets - private static final AggregateCloner DEEP_CLONER = AggregateCloner.DEFAULT; + private static final AggregateCloner DEEP_CLONER = AggregateCloner.newBuilder(). + instanceProvider(DefaultInstances.DEFAULT). + andThen(BukkitCloner.class). + andThen(ImmutableDetector.class). + andThen(CollectionCloner.class). + andThen(getSpecializedDeepClonerFactory()). + build(); + private static final AggregateCloner SHALLOW_CLONER = AggregateCloner.newBuilder(). instanceProvider(DefaultInstances.DEFAULT). andThen(new Function() { @@ -405,6 +415,8 @@ public class PacketContainer implements Serializable { *

* This will perform a full copy of the entire object tree, only skipping * known immutable objects and primitive types. + *

+ * Note that the inflated buffers in packet 51 and 56 will be copied directly to save memory. * * @return A deep copy of the current packet. */ @@ -413,6 +425,28 @@ public class PacketContainer implements Serializable { return new PacketContainer(getID(), clonedPacket); } + // To save space, we'll skip copying the inflated buffers in packet 51 and 56 + private static Function getSpecializedDeepClonerFactory() { + // Look at what you've made me do Java, look at it!! + return new Function() { + @Override + public Cloner apply(@Nullable BuilderParameters param) { + return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{ + this.writer = new ObjectWriter() { + protected void transformField(StructureModifier modifierSource, + StructureModifier modifierDest, int fieldIndex) { + // No need to clone inflated buffers + if (modifierSource.getField(fieldIndex).getName().startsWith("inflatedBuffer")) + modifierDest.write(fieldIndex, modifierSource.read(fieldIndex)); + else + defaultTransform(modifierSource, modifierDest, getDefaultCloner(), fieldIndex); + }; + }; + }}; + } + }; + } + private void writeObject(ObjectOutputStream output) throws IOException { // Default serialization output.defaultWriteObject(); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/AggregateCloner.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/AggregateCloner.java index eefc3235..19874b5a 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/AggregateCloner.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/AggregateCloner.java @@ -35,6 +35,11 @@ import com.google.common.collect.Lists; * @author Kristian */ public class AggregateCloner implements Cloner { + /** + * Supplies the cloner factories with necessary parameters. + * + * @author Kristian + */ public static class BuilderParameters { // Can only be modified by the builder private InstanceProvider instanceProvider; diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/FieldCloner.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/FieldCloner.java index d5e3daa7..62a07bc7 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/FieldCloner.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/FieldCloner.java @@ -47,12 +47,25 @@ public class FieldCloner implements Cloner { @Override protected void transformField(StructureModifier modifierSource, StructureModifier modifierDest, int fieldIndex) { - Object value = modifierSource.read(fieldIndex); - modifierDest.write(fieldIndex, getDefaultCloner().clone(value)); + defaultTransform(modifierDest, modifierDest, getDefaultCloner(), fieldIndex); } }; } + /** + * Default implementation of the field transform. Applies a clone operation before a field value is written. + * @param modifierSource - modifier for the original object. + * @param modifierDest - modifier for the new cloned object. + * @param defaultCloner - cloner to use. + * @param fieldIndex - the current field index. + */ + protected void defaultTransform(StructureModifier modifierSource, + StructureModifier modifierDest, Cloner defaultCloner, int fieldIndex) { + + Object value = modifierSource.read(fieldIndex); + modifierDest.write(fieldIndex, defaultCloner.clone(value)); + } + @Override public boolean canClone(Object source) { if (source == null)