This commit is contained in:
Kristian S. Stangeland 2013-07-17 07:28:36 +02:00
commit e7aa1ca98c
22 changed files with 253 additions and 62 deletions

View File

@ -1,3 +1,2 @@
eclipse.preferences.version=1 eclipse.preferences.version=1
encoding//src/main/java=cp1252
encoding/<project>=cp1252 encoding/<project>=cp1252

Binary file not shown.

View File

@ -0,0 +1,14 @@
name: ItemDisguiseMod
version: 1.0.0
description: Change the appearance of inventory items.
author: Comphenix
website: http://www.comphenix.net/ItemDisguise
main: com.comphenix.itemdisguise.ItemDisguiseMod
depends: [ProtocolLib]
database: false
commands:
explosion:
description: Creates a fake explosion around the caller.
usage: /<command>

View File

@ -0,0 +1,5 @@
#Generated by Maven
#Thu Oct 11 09:08:39 CEST 2012
version=1.0.0
groupId=com.comphenix.itemdisguise
artifactId=ItemDisguise

View File

@ -1,32 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"> <classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes> <attributes>
<attribute name="optional" value="true"/> <attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"> <classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes> <attributes>
<attribute name="optional" value="true"/> <attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes> <attributes>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<attributes> <attributes>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes> <attributes>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="output" path="target/classes"/>
</classpath> </classpath>

View File

@ -11,12 +11,12 @@
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name> <name>net.sourceforge.metrics.builder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>net.sourceforge.metrics.builder</name> <name>org.eclipse.m2e.core.maven2Builder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>

View File

@ -214,7 +214,7 @@
<dependency> <dependency>
<groupId>org.bukkit</groupId> <groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId> <artifactId>craftbukkit</artifactId>
<version>1.5.1-R0.2-SNAPSHOT</version> <version>1.6.2-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -35,6 +35,11 @@ public final class Packets {
*/ */
public static final int MAXIMUM_PACKET_ID = 255; 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. * List of packets sent only by the server.
* @author Kristian * @author Kristian

View File

@ -43,6 +43,18 @@ public class IntegerSet {
this.array = new boolean[maximumCount]; 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. * Determine whether or not the given element exists in the set.
* @param element - the element to check. Must be in the range [0, count). * @param element - the element to check. Must be in the range [0, count).

View File

@ -17,7 +17,9 @@
package com.comphenix.protocol.events; package com.comphenix.protocol.events;
import java.io.DataInput;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
@ -26,6 +28,7 @@ import java.io.Serializable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@ -37,6 +40,8 @@ import org.bukkit.WorldType;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack; 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.injector.StructureCache;
import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
@ -48,7 +53,9 @@ import com.comphenix.protocol.reflect.cloning.Cloner;
import com.comphenix.protocol.reflect.cloning.CollectionCloner; import com.comphenix.protocol.reflect.cloning.CollectionCloner;
import com.comphenix.protocol.reflect.cloning.FieldCloner; import com.comphenix.protocol.reflect.cloning.FieldCloner;
import com.comphenix.protocol.reflect.cloning.ImmutableDetector; 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.cloning.AggregateCloner.BuilderParameters;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.StreamSerializer; import com.comphenix.protocol.utility.StreamSerializer;
@ -107,6 +114,10 @@ public class PacketContainer implements Serializable {
}). }).
build(); 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. * Creates a packet container for a new packet.
* @param id - ID of the packet to create. * @param id - ID of the packet to create.
@ -421,10 +432,17 @@ public class PacketContainer implements Serializable {
* @return A deep copy of the current packet. * @return A deep copy of the current packet.
*/ */
public PacketContainer deepClone() { 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); return new PacketContainer(getID(), clonedPacket);
} }
// To save space, we'll skip copying the inflated buffers in packet 51 and 56 // To save space, we'll skip copying the inflated buffers in packet 51 and 56
private static Function<BuilderParameters, Cloner> getSpecializedDeepClonerFactory() { private static Function<BuilderParameters, Cloner> getSpecializedDeepClonerFactory() {
// Look at what you've made me do Java, look at it!! // Look at what you've made me do Java, look at it!!
@ -456,7 +474,7 @@ public class PacketContainer implements Serializable {
try { try {
// Call the write-method // Call the write-method
getMethodLazily(writeMethods, handle.getClass(), "write", DataOutputStream.class). getMethodLazily(writeMethods, handle.getClass(), "write", DataOutput.class).
invoke(handle, new DataOutputStream(output)); invoke(handle, new DataOutputStream(output));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -483,7 +501,7 @@ public class PacketContainer implements Serializable {
// Call the read method // Call the read method
try { try {
getMethodLazily(readMethods, handle.getClass(), "read", DataInputStream.class). getMethodLazily(readMethods, handle.getClass(), "read", DataInput.class).
invoke(handle, new DataInputStream(input)); invoke(handle, new DataInputStream(input));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -513,7 +531,12 @@ public class PacketContainer implements Serializable {
// Atomic operation // Atomic operation
if (method == null) { if (method == null) {
Method initialized = FuzzyReflection.fromClass(handleClass).getMethodByParameters(methodName, parameterClass); Method initialized = FuzzyReflection.fromClass(handleClass).getMethod(
FuzzyMethodContract.newBuilder().
parameterCount(1).
parameterDerivedOf(parameterClass).
returnTypeVoid().
build());
method = lookup.putIfAbsent(handleClass, initialized); method = lookup.putIfAbsent(handleClass, initialized);
// Use our version if we succeeded // Use our version if we succeeded

View File

@ -9,8 +9,6 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.apache.commons.lang.NotImplementedException;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
/** /**
@ -186,7 +184,7 @@ public abstract class MethodInfo implements GenericDeclaration, Member {
*/ */
@Override @Override
public String toString() { public String toString() {
throw new NotImplementedException(); throw new UnsupportedOperationException();
} }
/** /**

View File

@ -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);
}
}
}

View File

@ -7,8 +7,6 @@ import java.util.regex.Pattern;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.apache.commons.lang.NotImplementedException;
import com.comphenix.protocol.reflect.MethodInfo; import com.comphenix.protocol.reflect.MethodInfo;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -65,7 +63,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
@Override @Override
public boolean isMatch(Class<?>[] value, Object parent) { public boolean isMatch(Class<?>[] value, Object parent) {
throw new NotImplementedException("Use the parameter match instead."); throw new UnsupportedOperationException("Use the parameter match instead.");
} }
@Override @Override

View File

@ -18,7 +18,7 @@
package com.comphenix.protocol.utility; package com.comphenix.protocol.utility;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutput;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -219,6 +219,11 @@ public class MinecraftReflection {
MINECRAFT_FULL_PACKAGE = minecraftPackage; MINECRAFT_FULL_PACKAGE = minecraftPackage;
CRAFTBUKKIT_PACKAGE = craftBukkitPackage; CRAFTBUKKIT_PACKAGE = craftBukkitPackage;
// Make sure it exists
if (getMinecraftServerClass() == null) {
throw new IllegalArgumentException("Cannot find MinecraftServer for package " + minecraftPackage);
}
// Standard matcher // Standard matcher
setDynamicPackageMatcher(MINECRAFT_OBJECT); setDynamicPackageMatcher(MINECRAFT_OBJECT);
} }
@ -792,7 +797,7 @@ public class MinecraftReflection {
Method selected = FuzzyReflection.fromClass(getDataWatcherClass(), true). Method selected = FuzzyReflection.fromClass(getDataWatcherClass(), true).
getMethod(FuzzyMethodContract.newBuilder(). getMethod(FuzzyMethodContract.newBuilder().
requireModifier(Modifier.STATIC). requireModifier(Modifier.STATIC).
parameterSuperOf(DataOutputStream.class, 0). parameterDerivedOf(DataOutput.class, 0).
parameterMatches(getMinecraftObjectMatcher(), 1). parameterMatches(getMinecraftObjectMatcher(), 1).
build()); build());

View File

@ -2,7 +2,9 @@ package com.comphenix.protocol.utility;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -13,6 +15,7 @@ import org.bukkit.inventory.ItemStack;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
/** /**
* Utility methods for reading and writing Minecraft objects to streams. * Utility methods for reading and writing Minecraft objects to streams.
@ -37,11 +40,14 @@ public class StreamSerializer {
public ItemStack deserializeItemStack(@Nonnull DataInputStream input) throws IOException { public ItemStack deserializeItemStack(@Nonnull DataInputStream input) throws IOException {
if (input == null) if (input == null)
throw new IllegalArgumentException("Input stream cannot be NULL."); throw new IllegalArgumentException("Input stream cannot be NULL.");
if (readItemMethod == null) if (readItemMethod == null) {
readItemMethod = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()). readItemMethod = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
getMethodByParameters("readPacket", FuzzyMethodContract.newBuilder().
MinecraftReflection.getItemStackClass(), parameterCount(1).
new Class<?>[] {DataInputStream.class}); parameterDerivedOf(DataInput.class).
returnDerivedOf(MinecraftReflection.getItemStackClass()).
build());
}
try { try {
Object nmsItem = readItemMethod.invoke(null, input); Object nmsItem = readItemMethod.invoke(null, input);
@ -88,10 +94,12 @@ public class StreamSerializer {
Object nmsItem = MinecraftReflection.getMinecraftItemStack(stack); Object nmsItem = MinecraftReflection.getMinecraftItemStack(stack);
if (writeItemMethod == null) if (writeItemMethod == null)
writeItemMethod = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()). writeItemMethod = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
getMethodByParameters("writePacket", new Class<?>[] { FuzzyMethodContract.newBuilder().
MinecraftReflection.getItemStackClass(), parameterCount(2).
DataOutputStream.class }); parameterDerivedOf(MinecraftReflection.getItemStackClass(), 0).
parameterDerivedOf(DataOutput.class, 1).
build());
try { try {
writeItemMethod.invoke(null, nmsItem, output); writeItemMethod.invoke(null, nmsItem, output);
} catch (Exception e) { } catch (Exception e) {

View File

@ -4,10 +4,10 @@ import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import net.minecraft.server.v1_5_R2.StatisticList; import net.minecraft.server.v1_6_R2.StatisticList;
// Will have to be updated for every version though // Will have to be updated for every version though
import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftItemFactory; import org.bukkit.craftbukkit.v1_6_R2.inventory.CraftItemFactory;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
@ -63,6 +63,6 @@ public class BukkitInitialization {
*/ */
public static void initializePackage() { public static void initializePackage() {
// Initialize reflection // Initialize reflection
MinecraftReflection.setMinecraftPackage("net.minecraft.server.v1_5_R2", "org.bukkit.craftbukkit.v1_5_R2"); MinecraftReflection.setMinecraftPackage("net.minecraft.server.v1_6_R2", "org.bukkit.craftbukkit.v1_6_R2");
} }
} }

View File

@ -20,9 +20,17 @@ package com.comphenix.protocol.events;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.List; 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 // Will have to be updated for every version though
import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftItemFactory; import org.bukkit.craftbukkit.v1_6_R2.inventory.CraftItemFactory;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.WorldType; import org.bukkit.WorldType;
@ -305,7 +313,40 @@ public class PacketContainerTest {
watchableAccessor.write(0, list); watchableAccessor.write(0, list);
assertEquals(list, watchableAccessor.read(0)); assertEquals(list, watchableAccessor.read(0));
} }
@Test
public void testSerialization() {
PacketContainer chat = new PacketContainer(3);
chat.getStrings().write(0, "Test");
PacketContainer copy = (PacketContainer) SerializationUtils.clone(chat);
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 @Test
public void testDeepClone() { public void testDeepClone() {
// Try constructing all the packets // Try constructing all the packets

View File

@ -0,0 +1,36 @@
package com.comphenix.protocol.utility;
import static org.junit.Assert.*;
import java.io.IOException;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_6_R2.inventory.CraftItemFactory;
import org.bukkit.inventory.ItemStack;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import com.comphenix.protocol.BukkitInitialization;
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PrepareForTest(CraftItemFactory.class)
public class StreamSerializerTest {
@BeforeClass
public static void initializeBukkit() throws IllegalAccessException {
BukkitInitialization.initializeItemMeta();
}
@Test
public void testSerializer() throws IOException {
ItemStack before = new ItemStack(Material.GOLD_AXE);
StreamSerializer serializer = new StreamSerializer();
String data = serializer.serializeItemStack(before);
ItemStack after = serializer.deserializeItemStack(data);
assertEquals(before.getType(), after.getType());
assertEquals(before.getAmount(), after.getAmount());
}
}