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 eff03790..266d45cd 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -30,6 +30,8 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.ConcurrentMap; +import javax.annotation.Nullable; + import org.bukkit.World; import org.bukkit.WorldType; import org.bukkit.entity.Entity; @@ -38,13 +40,19 @@ import org.bukkit.inventory.ItemStack; import com.comphenix.protocol.injector.StructureCache; import com.comphenix.protocol.reflect.EquivalentConverter; 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.Cloner; +import com.comphenix.protocol.reflect.cloning.FieldCloner; +import com.comphenix.protocol.reflect.cloning.AggregateCloner.BuilderParameters; +import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.wrappers.BukkitConverters; import com.comphenix.protocol.wrappers.ChunkPosition; import com.comphenix.protocol.wrappers.WrappedDataWatcher; import com.comphenix.protocol.wrappers.WrappedWatchableObject; +import com.google.common.base.Function; import com.google.common.collect.Maps; /** @@ -69,6 +77,21 @@ public class PacketContainer implements Serializable { private static ConcurrentMap, Method> writeMethods = Maps.newConcurrentMap(); private static ConcurrentMap, Method> readMethods = Maps.newConcurrentMap(); + // Used to clone packets + private static final AggregateCloner DEEP_CLONER = AggregateCloner.DEFAULT; + private static final AggregateCloner SHALLOW_CLONER = AggregateCloner.newBuilder(). + instanceProvider(DefaultInstances.DEFAULT). + andThen(new Function() { + @Override + public Cloner apply(@Nullable BuilderParameters param) { + return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{ + // Use a default writer with no concept of cloning + writer = new ObjectWriter(); + }}; + } + }). + build(); + /** * Creates a packet container for a new packet. * @param id - ID of the packet to create. @@ -364,12 +387,29 @@ public class PacketContainer implements Serializable { return id; } + /** + * Create a shallow copy of the current packet. + *

+ * This merely writes the content of each field to the new class directly, + * without performing any expensive copies. + * + * @return A shallow copy of the current packet. + */ + public PacketContainer shallowClone() { + Object clonedPacket = SHALLOW_CLONER.clone(getHandle()); + return new PacketContainer(getID(), clonedPacket); + } + /** * Create a deep copy of the current packet. + *

+ * This will perform a full copy of the entire object tree, only skipping + * known immutable objects and primitive types. + * * @return A deep copy of the current packet. */ public PacketContainer deepClone() { - Object clonedPacket = AggregateCloner.DEFAULT.clone(getHandle()); + Object clonedPacket = DEEP_CLONER.clone(getHandle()); return new PacketContainer(getID(), clonedPacket); } 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 233afbbb..07e6fc49 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 @@ -47,6 +47,11 @@ public class AggregateCloner implements Cloner { } } + /** + * Represents a builder for aggregate (combined) cloners. + * + * @author Kristian + */ public static class Builder { private List> factories = Lists.newArrayList(); private BuilderParameters parameters; @@ -75,7 +80,7 @@ public class AggregateCloner implements Cloner { */ public Builder andThen(final Class type) { // Use reflection to generate a factory on the fly - return orCloner(new Function() { + return andThen(new Function() { @Override public Cloner apply(@Nullable BuilderParameters param) { Object result = param.typeConstructor.create(type); @@ -97,7 +102,7 @@ public class AggregateCloner implements Cloner { * @param factory - factory constructing the next cloner. * @return This builder. */ - public Builder orCloner(Function factory) { + public Builder andThen(Function factory) { factories.add(factory); return this; } 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 5eb7f514..20149156 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 @@ -10,11 +10,11 @@ import com.comphenix.protocol.reflect.instances.InstanceProvider; * @author Kristian */ public class FieldCloner implements Cloner { - private final Cloner defaultCloner; - private final InstanceProvider instanceProvider; + protected Cloner defaultCloner; + protected InstanceProvider instanceProvider; // Used to clone objects - private final ObjectWriter writer; + protected ObjectWriter writer; /** * Constructs a field cloner that copies objects by reading and writing the internal fields directly. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/IdentityCloner.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/IdentityCloner.java deleted file mode 100644 index 576baee1..00000000 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/IdentityCloner.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.comphenix.protocol.reflect.cloning; - -/** - * Represents a cloner that simply returns the given object. - * - * @author Kristian - */ -public class IdentityCloner implements Cloner { - @Override - public boolean canClone(Object source) { - return true; - } - - @Override - public Object clone(Object source) { - return source; - } -}