Use reflection to clone certain packets (44 - update attributes).
These packets contain objects (AttributeSnapshot and AttributeModifiable) isn't supported by the current cloning system.
Dieser Commit ist enthalten in:
Ursprung
468d013032
Commit
45f36f9ad6
@ -35,6 +35,11 @@ public final class Packets {
|
||||
*/
|
||||
public static final int MAXIMUM_PACKET_ID = 255;
|
||||
|
||||
/**
|
||||
* The maximum number of unique packet IDs. It's unlikely this will ever change.
|
||||
*/
|
||||
public static final int PACKET_COUNT = 256;
|
||||
|
||||
/**
|
||||
* List of packets sent only by the server.
|
||||
* @author Kristian
|
||||
|
@ -43,6 +43,18 @@ public class IntegerSet {
|
||||
this.array = new boolean[maximumCount];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a lookup table with a given maximum and value list.
|
||||
* <p>
|
||||
* The provided elements must be in the range [0, count).
|
||||
* @param maximumCount - the maximum element value and count.
|
||||
* @param values - the elements to add to the set.
|
||||
*/
|
||||
public IntegerSet(int maximumCount, Collection<Integer> values) {
|
||||
this.array = new boolean[maximumCount];
|
||||
addAll(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not the given element exists in the set.
|
||||
* @param element - the element to check. Must be in the range [0, count).
|
||||
|
@ -28,6 +28,7 @@ import java.io.Serializable;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
@ -39,6 +40,8 @@ import org.bukkit.WorldType;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.concurrency.IntegerSet;
|
||||
import com.comphenix.protocol.injector.StructureCache;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
@ -50,6 +53,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.ReflectionCloner;
|
||||
import com.comphenix.protocol.reflect.cloning.AggregateCloner.BuilderParameters;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
@ -110,6 +114,10 @@ public class PacketContainer implements Serializable {
|
||||
}).
|
||||
build();
|
||||
|
||||
// Packets that cannot be cloned by our default deep cloner
|
||||
private static final IntegerSet CLONING_UNSUPPORTED = new IntegerSet(Packets.PACKET_COUNT,
|
||||
Arrays.asList(Packets.Server.UPDATE_ATTRIBUTES));
|
||||
|
||||
/**
|
||||
* Creates a packet container for a new packet.
|
||||
* @param id - ID of the packet to create.
|
||||
@ -424,10 +432,17 @@ public class PacketContainer implements Serializable {
|
||||
* @return A deep copy of the current packet.
|
||||
*/
|
||||
public PacketContainer deepClone() {
|
||||
Object clonedPacket = DEEP_CLONER.clone(getHandle());
|
||||
Object clonedPacket = null;
|
||||
|
||||
// Fall back on the alternative (but slower) method of reading and writing back the packet
|
||||
if (CLONING_UNSUPPORTED.contains(id)) {
|
||||
clonedPacket = ReflectionCloner.clone(this).getHandle();
|
||||
} else {
|
||||
clonedPacket = DEEP_CLONER.clone(getHandle());
|
||||
}
|
||||
return new PacketContainer(getID(), clonedPacket);
|
||||
}
|
||||
|
||||
|
||||
// To save space, we'll skip copying the inflated buffers in packet 51 and 56
|
||||
private static Function<BuilderParameters, Cloner> getSpecializedDeepClonerFactory() {
|
||||
// Look at what you've made me do Java, look at it!!
|
||||
|
@ -9,8 +9,6 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
@ -186,7 +184,7 @@ public abstract class MethodInfo implements GenericDeclaration, Member {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
throw new NotImplementedException();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,47 @@
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents a cloner that can clone any class that implements Serializable.
|
||||
* @author Kristian Stangeland
|
||||
*/
|
||||
public class ReflectionCloner implements Cloner {
|
||||
|
||||
@Override
|
||||
public boolean canClone(Object source) {
|
||||
if (source == null)
|
||||
return false;
|
||||
return source instanceof Serializable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone(Object source) {
|
||||
return clone(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the given object using serialization.
|
||||
* @param obj - the object to clone.
|
||||
* @return The cloned object.
|
||||
* @throws RuntimeException If we were unable to clone the object.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Serializable> T clone(final T obj) {
|
||||
try {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oout = new ObjectOutputStream(out);
|
||||
|
||||
oout.writeObject(obj);
|
||||
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
|
||||
return (T) in.readObject();
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to clone object " + obj, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,8 +7,6 @@ import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
import com.comphenix.protocol.reflect.MethodInfo;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@ -65,7 +63,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
|
||||
@Override
|
||||
public boolean isMatch(Class<?>[] value, Object parent) {
|
||||
throw new NotImplementedException("Use the parameter match instead.");
|
||||
throw new UnsupportedOperationException("Use the parameter match instead.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,8 +20,15 @@ package com.comphenix.protocol.events;
|
||||
import static org.junit.Assert.*;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.minecraft.server.v1_6_R2.AttributeModifier;
|
||||
import net.minecraft.server.v1_6_R2.AttributeSnapshot;
|
||||
import net.minecraft.server.v1_6_R2.Packet44UpdateAttributes;
|
||||
|
||||
import org.apache.commons.lang.SerializationUtils;
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringStyle;
|
||||
// Will have to be updated for every version though
|
||||
import org.bukkit.craftbukkit.v1_6_R2.inventory.CraftItemFactory;
|
||||
|
||||
@ -317,7 +324,29 @@ public class PacketContainerTest {
|
||||
assertEquals(3, copy.getID());
|
||||
assertEquals("Test", copy.getStrings().read(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeList() {
|
||||
PacketContainer attribute = new PacketContainer(Packets.Server.UPDATE_ATTRIBUTES);
|
||||
attribute.getIntegers().write(0, 123); // Entity ID
|
||||
|
||||
// Initialize some test data
|
||||
List<AttributeModifier> modifiers = Lists.newArrayList(
|
||||
new AttributeModifier(UUID.randomUUID(), "Unknown synced attribute modifier", 10, 0));
|
||||
AttributeSnapshot snapshot = new AttributeSnapshot(
|
||||
(Packet44UpdateAttributes) attribute.getHandle(), "generic.Maxhealth", 20.0, modifiers);
|
||||
|
||||
attribute.getSpecificModifier(List.class).write(0, Lists.newArrayList(snapshot));
|
||||
PacketContainer cloned = attribute.deepClone();
|
||||
AttributeSnapshot clonedSnapshot = (AttributeSnapshot) cloned.getSpecificModifier(List.class).read(0).get(0);
|
||||
|
||||
assertEquals(
|
||||
ToStringBuilder.reflectionToString(snapshot, ToStringStyle.SHORT_PREFIX_STYLE),
|
||||
ToStringBuilder.reflectionToString(clonedSnapshot, ToStringStyle.SHORT_PREFIX_STYLE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeepClone() {
|
||||
// Try constructing all the packets
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren