From 0745fba8815efae4ca87b48e439dc2e2ca6a2705 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Thu, 6 Dec 2012 03:37:20 +0100 Subject: [PATCH] Massive update that ensures ProtocolLib is compatible with 1.4.5-R3.0 Due to 8f12382e8efc8c39a919af9180dd884caf3720ff, CraftBukkit has now moved the net.minecraft.server package and org.bukkit.craftbukkit to versioned package names, breaking all plugins that rely on these directly. ProtocolLib was never intended to be updated specifcally for new versions of Minecraft (hence the index-based system of accessing packets instead of making wrapper classes), so we will use reflection to "ignore" this hack entirely. Luckily, ProtocolLib was initially designed for this in mind, so we don't have to refactor it entirely. --- ProtocolLib/dependency-reduced-pom.xml | 2 +- .../com/comphenix/protocol/CommandPacket.java | 6 +- .../comphenix/protocol/async/AsyncMarker.java | 7 +- .../protocol/events/PacketContainer.java | 33 +- .../protocol/injector/EntityUtilities.java | 23 +- .../protocol/injector/ListenerInvoker.java | 4 +- .../protocol/injector/MinecraftRegistry.java | 4 +- .../protocol/injector/PacketConstructor.java | 4 +- .../injector/PacketFilterManager.java | 8 +- .../protocol/injector/PacketInjector.java | 5 +- .../protocol/injector/ReadPacketModifier.java | 11 +- .../protocol/injector/StructureCache.java | 9 +- .../injector/player/InjectedArrayList.java | 15 +- .../player/InjectedServerConnection.java | 6 +- .../injector/player/NetworkFieldInjector.java | 18 +- .../player/NetworkObjectInjector.java | 5 +- .../player/NetworkServerInjector.java | 9 +- .../player/PlayerInjectionHandler.java | 4 +- .../injector/player/PlayerInjector.java | 31 +- .../protocol/utility/CachedPackage.java | 46 ++ .../protocol/utility/MinecraftReflection.java | 444 +++++++++++++++++- .../protocol/wrappers/BukkitConverters.java | 64 +-- .../protocol/wrappers/ChunkPosition.java | 41 +- .../wrappers/WrappedChunkCoordinate.java | 58 ++- .../protocol/wrappers/WrappedDataWatcher.java | 50 +- .../wrappers/WrappedWatchableObject.java | 67 ++- .../reflect/StructureModifierTest.java | 26 - 27 files changed, 757 insertions(+), 243 deletions(-) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/utility/CachedPackage.java delete mode 100644 ProtocolLib/src/test/java/com/comphenix/protocol/reflect/StructureModifierTest.java diff --git a/ProtocolLib/dependency-reduced-pom.xml b/ProtocolLib/dependency-reduced-pom.xml index 7f3c8e0c..f877ad9e 100644 --- a/ProtocolLib/dependency-reduced-pom.xml +++ b/ProtocolLib/dependency-reduced-pom.xml @@ -139,7 +139,7 @@ org.bukkit craftbukkit - 1.3.2-R1.0 + 1.4.5-R0.3-SNAPSHOT provided diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java index 3b8245c9..5719a097 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java @@ -10,7 +10,6 @@ import java.util.WeakHashMap; import java.util.logging.Level; import java.util.logging.Logger; -import net.minecraft.server.Packet; import net.sf.cglib.proxy.Factory; import org.bukkit.ChatColor; @@ -29,6 +28,7 @@ import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.PrettyPrinter; import com.comphenix.protocol.utility.ChatExtensions; +import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.collect.DiscreteDomains; import com.google.common.collect.Range; import com.google.common.collect.Ranges; @@ -394,7 +394,7 @@ class CommandPacket extends CommandBase { // Detailed will print the packet's content too if (detailed) { try { - Packet packet = event.getPacket().getHandle(); + Object packet = event.getPacket().getHandle(); Class clazz = packet.getClass(); // Get the first Minecraft super class @@ -404,7 +404,7 @@ class CommandPacket extends CommandBase { } logger.info(shortDescription + ":\n" + - PrettyPrinter.printObject(packet, clazz, Packet.class) + PrettyPrinter.printObject(packet, clazz, MinecraftReflection.getPacketClass()) ); } catch (IllegalAccessException e) { diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncMarker.java b/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncMarker.java index 7b6b038b..5b0e6a1c 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncMarker.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncMarker.java @@ -25,13 +25,12 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import net.minecraft.server.Packet; - import com.comphenix.protocol.PacketStream; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.injector.PrioritizedListener; import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.primitives.Longs; /** @@ -403,10 +402,10 @@ public class AsyncMarker implements Serializable, Comparable { if (isMinecraftAsync == null && !alwaysSync) { try { - isMinecraftAsync = FuzzyReflection.fromClass(Packet.class).getMethodByName("a_.*"); + isMinecraftAsync = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethodByName("a_.*"); } catch (RuntimeException e) { // This will occur in 1.2.5 (or possibly in later versions) - List methods = FuzzyReflection.fromClass(Packet.class). + List methods = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()). getMethodListByParameters(boolean.class, new Class[] {}); // Try to look for boolean methods 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 6f424874..a7b4a265 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -40,14 +40,13 @@ import com.comphenix.protocol.injector.StructureCache; import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.StructureModifier; +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.collect.Maps; -import net.minecraft.server.Packet; - /** * Represents a Minecraft packet indirectly. * @@ -61,7 +60,7 @@ public class PacketContainer implements Serializable { private static final long serialVersionUID = 2074805748222377230L; protected int id; - protected transient Packet handle; + protected transient Object handle; // Current structure modifier protected transient StructureModifier structureModifier; @@ -83,7 +82,7 @@ public class PacketContainer implements Serializable { * @param id - ID of the given packet. * @param handle - contained packet. */ - public PacketContainer(int id, Packet handle) { + public PacketContainer(int id, Object handle) { this(id, handle, StructureCache.getStructure(id).withTarget(handle)); } @@ -93,7 +92,7 @@ public class PacketContainer implements Serializable { * @param handle - contained packet. * @param structure - structure modifier. */ - public PacketContainer(int id, Packet handle, StructureModifier structure) { + public PacketContainer(int id, Object handle, StructureModifier structure) { if (handle == null) throw new IllegalArgumentException("handle cannot be null."); @@ -112,7 +111,7 @@ public class PacketContainer implements Serializable { * Retrieves the underlying Minecraft packet. * @return Underlying Minecraft packet. */ - public Packet getHandle() { + public Object getHandle() { return handle; } @@ -222,7 +221,7 @@ public class PacketContainer implements Serializable { public StructureModifier getItemModifier() { // Convert to and from the Bukkit wrapper return structureModifier.withType( - net.minecraft.server.ItemStack.class, BukkitConverters.getItemStackConverter()); + MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter()); } /** @@ -238,23 +237,23 @@ public class PacketContainer implements Serializable { // Convert to and from the Bukkit wrapper return structureModifier.withType( - net.minecraft.server.ItemStack[].class, + MinecraftReflection.getItemStackArrayClass(), BukkitConverters.getIgnoreNull(new EquivalentConverter() { public Object getGeneric(ClassgenericType, ItemStack[] specific) { - net.minecraft.server.ItemStack[] result = new net.minecraft.server.ItemStack[specific.length]; + Object[] result = new Object[specific.length]; // Unwrap every item for (int i = 0; i < result.length; i++) { - result[i] = (net.minecraft.server.ItemStack) stackConverter.getGeneric( - net.minecraft.server.ItemStack.class, specific[i]); + result[i] = stackConverter.getGeneric( + MinecraftReflection.getItemStackClass(), specific[i]); } return result; } @Override public ItemStack[] getSpecific(Object generic) { - net.minecraft.server.ItemStack[] input = (net.minecraft.server.ItemStack[]) generic; + Object[] input = (Object[]) generic; ItemStack[] result = new ItemStack[input.length]; // Add the wrapper @@ -281,7 +280,7 @@ public class PacketContainer implements Serializable { public StructureModifier getWorldTypeModifier() { // Convert to and from the Bukkit wrapper return structureModifier.withType( - net.minecraft.server.WorldType.class, + MinecraftReflection.getWorldTypeClass(), BukkitConverters.getWorldTypeConverter()); } @@ -292,7 +291,7 @@ public class PacketContainer implements Serializable { public StructureModifier getDataWatcherModifier() { // Convert to and from the Bukkit wrapper return structureModifier.withType( - net.minecraft.server.DataWatcher.class, + MinecraftReflection.getDataWatcherClass(), BukkitConverters.getDataWatcherConverter()); } @@ -319,7 +318,7 @@ public class PacketContainer implements Serializable { public StructureModifier getPositionModifier() { // Convert to and from the Bukkit wrapper return structureModifier.withType( - net.minecraft.server.ChunkPosition.class, + MinecraftReflection.getChunkPositionClass(), ChunkPosition.getConverter()); } @@ -335,7 +334,7 @@ public class PacketContainer implements Serializable { return structureModifier.withType( Collection.class, BukkitConverters.getListConverter( - net.minecraft.server.ChunkPosition.class, + MinecraftReflection.getChunkPositionClass(), ChunkPosition.getConverter()) ); } @@ -352,7 +351,7 @@ public class PacketContainer implements Serializable { return structureModifier.withType( Collection.class, BukkitConverters.getListConverter( - net.minecraft.server.WatchableObject.class, + MinecraftReflection.getWatchableObjectClass(), BukkitConverters.getWatchableObjectConverter()) ); } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java index 806c03e1..9927230a 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/EntityUtilities.java @@ -28,11 +28,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import net.minecraft.server.EntityPlayer; -import net.minecraft.server.EntityTrackerEntry; - import org.bukkit.World; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -52,6 +48,7 @@ class EntityUtilities { private static Field entityTrackerField; private static Field trackedEntitiesField; private static Field trackedPlayersField; + private static Field trackerField; private static Method hashGetMethod; private static Method scanPlayersMethod; @@ -143,9 +140,8 @@ class EntityUtilities { // Wrap every player - we also ensure that the underlying tracker list is immutable for (Object tracker : trackedPlayers) { - if (tracker instanceof EntityPlayer) { - EntityPlayer nmsPlayer = (EntityPlayer) tracker; - result.add(nmsPlayer.getBukkitEntity()); + if (MinecraftReflection.isMinecraftPlayer(tracker)) { + result.add((Player) MinecraftReflection.getBukkitEntity(tracker)); } } return result; @@ -165,7 +161,8 @@ class EntityUtilities { * @throws FieldAccessException */ private static Object getEntityTrackerEntry(World world, int entityID) throws FieldAccessException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { - Object worldServer = ((CraftWorld) world).getHandle(); + BukkitUnwrapper unwrapper = new BukkitUnwrapper(); + Object worldServer = unwrapper.unwrapItem(world); // We have to rely on the class naming here. if (entityTrackerField == null) @@ -248,11 +245,15 @@ class EntityUtilities { */ public static Entity getEntityFromID(World world, int entityID) throws FieldAccessException { try { - EntityTrackerEntry trackerEntry = (EntityTrackerEntry) getEntityTrackerEntry(world, entityID); + Object trackerEntry = getEntityTrackerEntry(world, entityID); + + if (trackerField == null) + trackerField = trackerEntry.getClass().getField("tracker"); + Object tracker = FieldUtils.readField(trackerField, trackerEntry, true); // Handle NULL cases - if (trackerEntry != null && trackerEntry.tracker != null) { - return trackerEntry.tracker.getBukkitEntity(); + if (trackerEntry != null && tracker != null) { + return (Entity) MinecraftReflection.getBukkitEntity(tracker); } else { return null; } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java index 52c52e7d..f27b64e5 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java @@ -17,8 +17,6 @@ package com.comphenix.protocol.injector; -import net.minecraft.server.Packet; - import com.comphenix.protocol.events.PacketEvent; /** @@ -45,7 +43,7 @@ public interface ListenerInvoker { * @param packet - the packet. * @return The packet ID. */ - public abstract int getPacketID(Packet packet); + public abstract int getPacketID(Object packet); /** * Associate a given class with the given packet ID. Internal method. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/MinecraftRegistry.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/MinecraftRegistry.java index e433604e..5cdddd7c 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/MinecraftRegistry.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/MinecraftRegistry.java @@ -23,12 +23,12 @@ import java.util.List; import java.util.Map; import java.util.Set; -import net.minecraft.server.Packet; import net.sf.cglib.proxy.Factory; import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FieldUtils; import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; @@ -78,7 +78,7 @@ class MinecraftRegistry { */ private static FuzzyReflection getPacketRegistry() { if (packetRegistry == null) - packetRegistry = FuzzyReflection.fromClass(Packet.class, true); + packetRegistry = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true); return packetRegistry; } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java index 7c1f85e6..3d138a13 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java @@ -21,8 +21,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.List; -import net.minecraft.server.Packet; - import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.reflect.FieldAccessException; import com.google.common.collect.ImmutableList; @@ -157,7 +155,7 @@ public class PacketConstructor { } } - Packet nmsPacket = (Packet) constructorMethod.newInstance(values); + Object nmsPacket = constructorMethod.newInstance(values); return new PacketContainer(packetID, nmsPacket); } catch (IllegalArgumentException e) { diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java index 27f7c7c0..e43921ef 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java @@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nullable; -import net.minecraft.server.Packet; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; @@ -55,6 +54,7 @@ import com.comphenix.protocol.events.*; import com.comphenix.protocol.injector.player.PlayerInjectionHandler; import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.base.Objects; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableSet; @@ -508,7 +508,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok if (packetCreation.compareAndSet(false, true)) incrementPhases(GamePhase.PLAYING); - Packet mcPacket = packet.getHandle(); + Object mcPacket = packet.getHandle(); // Make sure the packet isn't cancelled packetInjector.undoCancel(packet.getID(), mcPacket); @@ -686,9 +686,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok } @Override - public int getPacketID(Packet packet) { + public int getPacketID(Object packet) { if (packet == null) throw new IllegalArgumentException("Packet cannot be NULL."); + if (!MinecraftReflection.isPacketClass(packet)) + throw new IllegalArgumentException("The given object " + packet + " is not a packet."); return MinecraftRegistry.getPacketToID().get(packet.getClass()); } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketInjector.java index 6f6fb19a..0a83c8ec 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketInjector.java @@ -27,7 +27,6 @@ import java.util.concurrent.ConcurrentHashMap; import org.bukkit.entity.Player; -import net.minecraft.server.Packet; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Enhancer; @@ -81,7 +80,7 @@ class PacketInjector { * @param id - the id of the packet. * @param packet - packet to uncancel. */ - public void undoCancel(Integer id, Packet packet) { + public void undoCancel(Integer id, Object packet) { ReadPacketModifier modifier = readModifier.get(id); // See if this packet has been cancelled before @@ -93,7 +92,7 @@ class PacketInjector { private void initialize() throws IllegalAccessException { if (intHashMap == null) { // We're looking for the first static field with a Minecraft-object. This should be a IntHashMap. - Field intHashMapField = FuzzyReflection.fromClass(Packet.class, true). + Field intHashMapField = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true). getFieldByType(MinecraftReflection.MINECRAFT_OBJECT); try { diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ReadPacketModifier.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ReadPacketModifier.java index ee32ddc2..ceb702c6 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ReadPacketModifier.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ReadPacketModifier.java @@ -29,7 +29,6 @@ import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; -import net.minecraft.server.Packet; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; @@ -61,7 +60,7 @@ class ReadPacketModifier implements MethodInterceptor { * Remove any packet overrides. * @param packet - the packet to rever */ - public void removeOverride(Packet packet) { + public void removeOverride(Object packet) { override.remove(packet); } @@ -70,7 +69,7 @@ class ReadPacketModifier implements MethodInterceptor { * @param packet - the given packet. * @return Overriden object. */ - public Object getOverride(Packet packet) { + public Object getOverride(Object packet) { return override.get(packet); } @@ -79,7 +78,7 @@ class ReadPacketModifier implements MethodInterceptor { * @param packet - the packet to check. * @return TRUE if it has been cancelled, FALSE otherwise. */ - public boolean hasCancelled(Packet packet) { + public boolean hasCancelled(Object packet) { return getOverride(packet) == CANCEL_MARKER; } @@ -121,12 +120,12 @@ class ReadPacketModifier implements MethodInterceptor { DataInputStream input = (DataInputStream) args[0]; // Let the people know - PacketContainer container = new PacketContainer(packetID, (Packet) thisObj); + PacketContainer container = new PacketContainer(packetID, thisObj); PacketEvent event = packetInjector.packetRecieved(container, input); // Handle override if (event != null) { - Packet result = event.getPacket().getHandle(); + Object result = event.getPacket().getHandle(); if (event.isCancelled()) { override.put(thisObj, CANCEL_MARKER); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/StructureCache.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/StructureCache.java index aeedc16a..bc4f7aa2 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/StructureCache.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/StructureCache.java @@ -22,12 +22,11 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import net.minecraft.server.Packet; - import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.compiler.BackgroundCompiler; import com.comphenix.protocol.reflect.compiler.CompileListener; import com.comphenix.protocol.reflect.compiler.CompiledStructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; /** * Caches structure modifiers. @@ -45,9 +44,9 @@ public class StructureCache { * @param id - packet ID. * @return Created packet. */ - public static Packet newPacket(int id) { + public static Object newPacket(int id) { try { - return (Packet) MinecraftRegistry.getPacketClassFromID(id, true).newInstance(); + return MinecraftRegistry.getPacketClassFromID(id, true).newInstance(); } catch (InstantiationException e) { return null; } catch (IllegalAccessException e) { @@ -79,7 +78,7 @@ public class StructureCache { if (result == null) { // Use the vanilla class definition final StructureModifier value = new StructureModifier( - MinecraftRegistry.getPacketClassFromID(id, true), Packet.class, true); + MinecraftRegistry.getPacketClassFromID(id, true), MinecraftReflection.getPacketClass(), true); result = structureModifiers.putIfAbsent(id, value); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java index b2fc3855..60f570b5 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java @@ -25,7 +25,6 @@ import java.util.Set; import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.player.NetworkFieldInjector.FakePacket; -import net.minecraft.server.Packet; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; @@ -36,7 +35,7 @@ import net.sf.cglib.proxy.MethodProxy; * * @author Kristian */ -class InjectedArrayList extends ArrayList { +class InjectedArrayList extends ArrayList { /** * Silly Eclipse. @@ -44,12 +43,12 @@ class InjectedArrayList extends ArrayList { private static final long serialVersionUID = -1173865905404280990L; private transient PlayerInjector injector; - private transient Set ignoredPackets; + private transient Set ignoredPackets; private transient ClassLoader classLoader; private transient InvertedIntegerCallback callback; - public InjectedArrayList(ClassLoader classLoader, PlayerInjector injector, Set ignoredPackets) { + public InjectedArrayList(ClassLoader classLoader, PlayerInjector injector, Set ignoredPackets) { this.classLoader = classLoader; this.injector = injector; this.ignoredPackets = ignoredPackets; @@ -57,9 +56,9 @@ class InjectedArrayList extends ArrayList { } @Override - public boolean add(Packet packet) { + public boolean add(Object packet) { - Packet result = null; + Object result = null; // Check for fake packets and ignored packets if (packet instanceof FakePacket) { @@ -94,7 +93,7 @@ class InjectedArrayList extends ArrayList { * @param source - packet to invert. * @return The inverted packet. */ - Packet createNegativePacket(Packet source) { + Object createNegativePacket(Object source) { ListenerInvoker invoker = injector.getInvoker(); int packetID = invoker.getPacketID(source); @@ -133,7 +132,7 @@ class InjectedArrayList extends ArrayList { try { // Temporarily associate the fake packet class invoker.registerPacketClass(proxyClass, packetID); - return (Packet) proxyClass.newInstance(); + return proxyClass.newInstance(); } catch (Exception e) { // Don't pollute the throws tree diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedServerConnection.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedServerConnection.java index c9ae47ff..1d94a9c9 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedServerConnection.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedServerConnection.java @@ -22,7 +22,6 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; -import net.minecraft.server.NetLoginHandler; import net.sf.cglib.proxy.Factory; import org.bukkit.Server; @@ -32,6 +31,7 @@ import com.comphenix.protocol.reflect.FieldUtils; import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.ObjectCloner; import com.comphenix.protocol.reflect.VolatileField; +import com.comphenix.protocol.utility.MinecraftReflection; /** * Used to ensure that the 1.3 server is referencing the correct server handler. @@ -229,7 +229,7 @@ class InjectedServerConnection { @Override protected void onInserting(Object inserting) { // Ready for some login handler injection? - if (inserting instanceof NetLoginHandler) { + if (MinecraftReflection.isLoginHandler(inserting)) { Object replaced = netLoginInjector.onNetLoginCreated(inserting); // Only replace if it has changed @@ -241,7 +241,7 @@ class InjectedServerConnection { @Override protected void onRemoved(Object removing) { // Clean up? - if (removing instanceof NetLoginHandler) { + if (MinecraftReflection.isLoginHandler(removing)) { netLoginInjector.cleanup(removing); } } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkFieldInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkFieldInjector.java index dd65fa17..ffb6ca3d 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkFieldInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkFieldInjector.java @@ -40,8 +40,6 @@ import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.VolatileField; import com.google.common.collect.Sets; -import net.minecraft.server.Packet; - /** * Injection hook that overrides the packet queue lists in NetworkHandler. * @@ -58,7 +56,7 @@ class NetworkFieldInjector extends PlayerInjector { } // Packets to ignore - private Set ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap()); + private Set ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap()); // Overridden fields private List overridenLists = new ArrayList(); @@ -99,7 +97,7 @@ class NetworkFieldInjector extends PlayerInjector { } @Override - public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException { + public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException { if (networkManager != null) { try { @@ -147,14 +145,14 @@ class NetworkFieldInjector extends PlayerInjector { VolatileField overwriter = new VolatileField(field, networkManager, true); @SuppressWarnings("unchecked") - List minecraftList = (List) overwriter.getOldValue(); + List minecraftList = (List) overwriter.getOldValue(); synchronized(syncObject) { // The list we'll be inserting - List hackedList = new InjectedArrayList(classLoader, this, ignoredPackets); + List hackedList = new InjectedArrayList(classLoader, this, ignoredPackets); // Add every previously stored packet - for (Packet packet : minecraftList) { + for (Object packet : minecraftList) { hackedList.add(packet); } @@ -172,8 +170,8 @@ class NetworkFieldInjector extends PlayerInjector { protected void cleanHook() { // Clean up for (VolatileField overriden : overridenLists) { - List minecraftList = (List) overriden.getOldValue(); - List hacketList = (List) overriden.getValue(); + List minecraftList = (List) overriden.getOldValue(); + List hacketList = (List) overriden.getValue(); if (minecraftList == hacketList) { return; @@ -183,7 +181,7 @@ class NetworkFieldInjector extends PlayerInjector { synchronized(syncObject) { try { // Copy over current packets - for (Packet packet : (List) overriden.getValue()) { + for (Object packet : (List) overriden.getValue()) { minecraftList.add(packet); } } finally { diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkObjectInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkObjectInjector.java index e391d832..951c4b23 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkObjectInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkObjectInjector.java @@ -19,7 +19,6 @@ package com.comphenix.protocol.injector.player; import java.lang.reflect.InvocationTargetException; -import net.minecraft.server.Packet; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.Enhancer; @@ -67,7 +66,7 @@ class NetworkObjectInjector extends PlayerInjector { } @Override - public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException { + public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException { Object networkDelegate = filtered ? networkManagerRef.getValue() : networkManagerRef.getOldValue(); if (networkDelegate != null) { @@ -114,7 +113,7 @@ class NetworkObjectInjector extends PlayerInjector { Callback queueFilter = new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - Packet packet = (Packet) args[0]; + Object packet = args[0]; if (packet != null) { packet = handlePacketSending(packet); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkServerInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkServerInjector.java index 3a346dfd..a7b42de2 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkServerInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetworkServerInjector.java @@ -21,7 +21,6 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import net.minecraft.server.Packet; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.Enhancer; @@ -43,6 +42,7 @@ import com.comphenix.protocol.reflect.ObjectCloner; import com.comphenix.protocol.reflect.VolatileField; import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.reflect.instances.ExistingGenerator; +import com.comphenix.protocol.utility.MinecraftReflection; /** * Represents a player hook into the NetServerHandler class. @@ -94,7 +94,7 @@ public class NetworkServerInjector extends PlayerInjector { } @Override - public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException { + public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException { Object serverDeleage = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue(); if (serverDeleage != null) { @@ -152,8 +152,7 @@ public class NetworkServerInjector extends PlayerInjector { Callback sendPacketCallback = new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - - Packet packet = (Packet) args[0]; + Object packet = args[0]; if (packet != null) { packet = handlePacketSending(packet); @@ -237,7 +236,7 @@ public class NetworkServerInjector extends PlayerInjector { } private Class getFirstMinecraftSuperClass(Class clazz) { - if (clazz.getName().startsWith("net.minecraft.server.")) + if (clazz.getName().startsWith(MinecraftReflection.getMinecraftPackage())) return clazz; else if (clazz.equals(Object.class)) return clazz; diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java index c5f832b9..3722e4f5 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java @@ -26,8 +26,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import net.minecraft.server.Packet; - import org.bukkit.Server; import org.bukkit.entity.Player; @@ -501,7 +499,7 @@ public class PlayerInjectionHandler { * @throws IllegalAccessException If the reflection machinery failed. * @throws InvocationTargetException If the underlying method caused an error. */ - public void processPacket(Player player, Packet mcPacket) throws IllegalAccessException, InvocationTargetException { + public void processPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException { PlayerInjector injector = getInjector(player); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java index 7739b68f..f4f8d871 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjector.java @@ -27,14 +27,15 @@ import java.net.SocketAddress; import net.sf.cglib.proxy.Factory; -import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitWorker; import com.comphenix.protocol.Packets; import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketListener; +import com.comphenix.protocol.injector.BukkitUnwrapper; import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; @@ -121,8 +122,8 @@ abstract class PlayerInjector { * @return Notch player object. */ protected Object getEntityPlayer(Player player) { - CraftPlayer craft = (CraftPlayer) player; - return craft.getHandle(); + BukkitUnwrapper unwrapper = new BukkitUnwrapper(); + return unwrapper.unwrapItem(player); } /** @@ -136,7 +137,7 @@ abstract class PlayerInjector { //Dispatch to the correct injection method if (injectionSource instanceof Player) initializePlayer(injectionSource); - else if (injectionSource instanceof NetLoginHandler) + else if (MinecraftReflection.isLoginHandler(injectionSource)) initializeLogin(injectionSource); else throw new IllegalArgumentException("Cannot initialize a player hook using a " + injectionSource.getClass().getName()); @@ -148,7 +149,7 @@ abstract class PlayerInjector { */ public void initializePlayer(Object player) { - EntityPlayer notchEntity = getEntityPlayer((Player) player); + Object notchEntity = getEntityPlayer((Player) player); if (!hasInitialized) { // Do this first, in case we encounter an exception @@ -202,7 +203,7 @@ abstract class PlayerInjector { // And the queue method if (queueMethod == null) queueMethod = FuzzyReflection.fromClass(reference.getType()). - getMethodByParameters("queue", Packet.class ); + getMethodByParameters("queue", MinecraftReflection.getPacketClass()); // And the data input stream that we'll use to identify a player if (inputField == null) @@ -321,7 +322,7 @@ abstract class PlayerInjector { } } - private Field getProxyField(EntityPlayer notchEntity, Field serverField) { + private Field getProxyField(Object notchEntity, Field serverField) { try { Object handler = FieldUtils.readField(serverHandlerField, notchEntity, true); @@ -396,10 +397,10 @@ abstract class PlayerInjector { * @return The stored entity player. * @throws IllegalAccessException If the reflection failed. */ - private EntityPlayer getEntityPlayer(Object netHandler) throws IllegalAccessException { + private Object getEntityPlayer(Object netHandler) throws IllegalAccessException { if (entityPlayerField == null) entityPlayerField = FuzzyReflection.fromObject(netHandler).getFieldByType(".*EntityPlayer"); - return (EntityPlayer) FieldUtils.readField(entityPlayerField, netHandler); + return FieldUtils.readField(entityPlayerField, netHandler); } /** @@ -408,15 +409,15 @@ abstract class PlayerInjector { * @throws IllegalAccessException If the reflection machinery failed. * @throws InvocationTargetException If the underlying method caused an error. */ - public void processPacket(Packet packet) throws IllegalAccessException, InvocationTargetException { + public void processPacket(Object packet) throws IllegalAccessException, InvocationTargetException { Object netHandler = getNetHandler(); // Get the process method if (processMethod == null) { try { - processMethod = FuzzyReflection.fromClass(Packet.class). - getMethodByParameters("processPacket", netHandlerField.getType()); + processMethod = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()). + getMethodByParameters("processPacket", netHandlerField.getType()); } catch (RuntimeException e) { throw new IllegalArgumentException("Cannot locate process packet method: " + e.getMessage()); } @@ -438,7 +439,7 @@ abstract class PlayerInjector { * @param filtered - whether or not the packet will be filtered by our listeners. * @param InvocationTargetException If an error occured when sending the packet. */ - public abstract void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException; + public abstract void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException; /** * Inject a hook to catch packets sent to the current player. @@ -499,7 +500,7 @@ abstract class PlayerInjector { * @param packet - packet to sent. * @return The given packet, or the packet replaced by the listeners. */ - public Packet handlePacketSending(Packet packet) { + public Object handlePacketSending(Object packet) { try { // Get the packet ID too Integer id = invoker.getPacketID(packet); @@ -514,7 +515,7 @@ abstract class PlayerInjector { if (updateOnLogin) { if (id == Packets.Server.LOGIN) { try { - updatedPlayer = getEntityPlayer(getNetHandler()).getBukkitEntity(); + updatedPlayer = (Player) MinecraftReflection.getBukkitEntity(getEntityPlayer(getNetHandler())); } catch (IllegalAccessException e) { reporter.reportDetailed(this, "Cannot update player in PlayerEvent.", e, packet); } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/CachedPackage.java b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/CachedPackage.java new file mode 100644 index 00000000..e69f956c --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/CachedPackage.java @@ -0,0 +1,46 @@ +package com.comphenix.protocol.utility; + +import java.util.Map; + +import com.google.common.collect.Maps; + +/** + * Represents a dynamic package and an arbitrary number of cached classes. + * + * @author Kristian + */ +class CachedPackage { + private Map> cache; + private String packageName; + + public CachedPackage(String packageName) { + this.packageName = packageName; + this.cache = Maps.newConcurrentMap(); + } + + /** + * Retrieve the class object of a specific class in the current package. + * @param className - the specific class. + * @return Class object. + * @throws RuntimeException If we are unable to find the given class. + */ + @SuppressWarnings("rawtypes") + public Class getPackageClass(String className) { + try { + Class result = cache.get(className); + + // Concurrency is not a problem - we don't care if we look up a class twice + if (result == null) { + // Look up the class dynamically + result = CachedPackage.class.getClassLoader(). + loadClass(packageName + "." + className); + cache.put(className, result); + } + + return result; + + } catch (ClassNotFoundException e) { + throw new RuntimeException("Cannot find class " + className, e); + } + } +} diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java index 80f73190..1a62fcae 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -1,13 +1,453 @@ package com.comphenix.protocol.utility; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import javax.annotation.Nonnull; + +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + +import com.comphenix.protocol.injector.BukkitUnwrapper; + /** * Methods and constants specifically used in conjuction with reflecting Minecraft object. + * * @author Kristian - * */ public class MinecraftReflection { /** - * Matches a Minecraft object. + * Regular expression that matches a Minecraft object. */ public static final String MINECRAFT_OBJECT = "net\\.minecraft(\\.\\w+)+"; + + /** + * The package name of all the classes that belongs to the native code in Minecraft. + */ + private static String MINECRAFT_SERVER_PACKAGE = "net.minecraft.server"; + + private static String MINECRAFT_FULL_PACKAGE = null; + private static String CRAFTBUKKIT_PACKAGE = null; + + private static CachedPackage minecraftPackage; + private static CachedPackage craftbukkitPackage; + + // org.bukkit.craftbukkit + private static Class craftItemStackClass; + private static Constructor craftNMSConstructor; + private static Constructor craftBukkitConstructor; + + // net.minecraft.server + private static Class itemStackArrayClass; + + /** + * Retrieve the name of the Minecraft server package. + * @return Full canonical name of the Minecraft server package. + */ + public static String getMinecraftPackage() { + // Speed things up + if (MINECRAFT_FULL_PACKAGE != null) + return MINECRAFT_FULL_PACKAGE; + + Server craftServer = Bukkit.getServer(); + + // This server should have a "getHandle" method that we can use + if (craftServer != null) { + try { + Class craftClass = craftServer.getClass(); + Method getHandle = craftClass.getMethod("getHandle"); + + Class returnType = getHandle.getReturnType(); + String returnName = returnType.getCanonicalName(); + + // The return type will tell us the full package, regardless of formating + CRAFTBUKKIT_PACKAGE = getPackage(craftClass.getCanonicalName()); + MINECRAFT_FULL_PACKAGE = getPackage(returnName); + return MINECRAFT_FULL_PACKAGE; + + } catch (SecurityException e) { + throw new RuntimeException("Security violation. Cannot get handle method.", e); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Cannot find getHandle() method on server. Is this a modified CraftBukkit version?", e); + } + + } else { + throw new IllegalStateException("Cannot find Bukkit. Is it running?"); + } + } + + /** + * Retrieve the name of the root CraftBukkit package. + * @return Full canonical name of the root CraftBukkit package. + */ + public static String getCraftBukkitPackage() { + // Ensure it has been initialized + getMinecraftPackage(); + return CRAFTBUKKIT_PACKAGE; + } + + /** + * Retrieve the package name from a given canonical Java class name. + * @param fullName - full Java class name. + * @return The package name. + */ + private static String getPackage(String fullName) { + return fullName.substring(0, fullName.lastIndexOf(".")); + } + + /** + * Determine if a given object can be found within the package net.minecraft.server. + * @param obj - the object to test. + * @return TRUE if it can, FALSE otherwise. + */ + public static boolean isMinecraftObject(@Nonnull Object obj) { + if (obj == null) + throw new IllegalArgumentException("Cannot determine the type of a null object."); + + // Doesn't matter if we don't check for the version here + return obj.getClass().getName().startsWith(MINECRAFT_SERVER_PACKAGE); + } + + /** + * Determine if a given object is found in net.minecraft.server, and has the given name. + * @param obj - the object to test. + * @param className - the class name to test. + * @return TRUE if it can, FALSE otherwise. + */ + public static boolean isMinecraftObject(@Nonnull Object obj, String className) { + if (obj == null) + throw new IllegalArgumentException("Cannot determine the type of a null object."); + + String javaName = obj.getClass().getName(); + return javaName.startsWith(MINECRAFT_SERVER_PACKAGE) && javaName.endsWith(className); + } + + /** + * Dynamically retrieve the Bukkit entity from a given entity. + * @param nmsObject - the NMS entity. + * @return A bukkit entity. + * @throws RuntimeException If we were unable to retrieve the Bukkit entity. + */ + public static Object getBukkitEntity(Object nmsObject) { + if (nmsObject == null) + return null; + + // We will have to do this dynamically, unfortunately + try { + return nmsObject.getClass().getMethod("getBukkitEntity").invoke(nmsObject); + } catch (Exception e) { + throw new RuntimeException("Cannot get Bukkit entity from " + nmsObject, e); + } + } + + /** + * Determine if a given object is a ChunkPosition. + * @param obj - the object to test. + * @return TRUE if it can, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isChunkPosition(Object obj) { + return getChunkPositionClass().isAssignableFrom(obj.getClass()); + } + + /** + * Determine if a given object is a ChunkCoordinate. + * @param obj - the object to test. + * @return TRUE if it can, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isChunkCoordinates(Object obj) { + return getChunkCoordinatesClass().isAssignableFrom(obj.getClass()); + } + + /** + * Determine if the given object is actually a Minecraft packet. + * @param obj - the given object. + * @return TRUE if it is, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isPacketClass(Object obj) { + return getPacketClass().isAssignableFrom(obj.getClass()); + } + + /** + * Determine if the given object is a NetLoginHandler. + * @param obj - the given object. + * @return TRUE if it is, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isLoginHandler(Object obj) { + return getNetLoginHandlerClass().isAssignableFrom(obj.getClass()); + } + + /** + * Determine if the given object is actually a Minecraft packet. + * @param obj - the given object. + * @return TRUE if it is, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isMinecraftEntity(Object obj) { + return getEntityClass().isAssignableFrom(obj.getClass()); + } + + /** + * Determine if the given object is a NMS ItemStack. + * @param obj - the given object. + * @return TRUE if it is, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isItemStack(Object value) { + return getItemStackClass().isAssignableFrom(value.getClass()); + } + + /** + * Determine if the given object is a Minecraft player entity. + * @param obj - the given object. + * @return TRUE if it is, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isMinecraftPlayer(Object obj) { + return getEntityPlayerClass().isAssignableFrom(obj.getClass()); + } + + /** + * Determine if the given object is a watchable object. + * @param obj - the given object. + * @return TRUE if it is, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isWatchableObject(Object obj) { + return getWatchableObjectClass().isAssignableFrom(obj.getClass()); + } + + /** + * Determine if the given object is a data watcher object. + * @param obj - the given object. + * @return TRUE if it is, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isDataWatcher(Object obj) { + return getDataWatcherClass().isAssignableFrom(obj.getClass()); + } + + /** + * Determine if the given object is a CraftItemStack instancey. + * @param obj - the given object. + * @return TRUE if it is, FALSE otherwise. + */ + @SuppressWarnings("unchecked") + public static boolean isCraftItemStack(Object obj) { + return getCraftItemStackClass().isAssignableFrom(obj.getClass()); + } + + /** + * Retrieve the EntityPlayer (NMS) class. + * @return The entity class. + */ + @SuppressWarnings("rawtypes") + public static Class getEntityPlayerClass() { + return getMinecraftClass("EntityPlayer"); + } + + /** + * Retrieve the entity (NMS) class. + * @return The entity class. + */ + @SuppressWarnings("rawtypes") + public static Class getEntityClass() { + return getMinecraftClass("Entity"); + } + + /** + * Retrieve the packet class. + * @return The packet class. + */ + @SuppressWarnings("rawtypes") + public static Class getPacketClass() { + return getMinecraftClass("Packet"); + } + + /** + * Retrieve the NetLoginHandler class. + * @return The NetLoginHandler class. + */ + @SuppressWarnings("rawtypes") + public static Class getNetLoginHandlerClass() { + return getMinecraftClass("NetLoginHandler"); + } + + /** + * Retrieve the NetLoginHandler class. + * @return The NetLoginHandler class. + */ + @SuppressWarnings("rawtypes") + public static Class getItemStackClass() { + return getMinecraftClass("ItemStack"); + } + + /** + * Retrieve the WorldType class. + * @return The WorldType class. + */ + @SuppressWarnings("rawtypes") + public static Class getWorldTypeClass() { + return getMinecraftClass("WorldType"); + } + + /** + * Retrieve the DataWatcher class. + * @return The DataWatcher class. + */ + @SuppressWarnings("rawtypes") + public static Class getDataWatcherClass() { + return getMinecraftClass("DataWatcher"); + } + + /** + * Retrieve the ChunkPosition class. + * @return The ChunkPosition class. + */ + @SuppressWarnings("rawtypes") + public static Class getChunkPositionClass() { + return getMinecraftClass("ChunkPosition"); + } + + /** + * Retrieve the ChunkPosition class. + * @return The ChunkPosition class. + */ + @SuppressWarnings("rawtypes") + public static Class getChunkCoordinatesClass() { + return getMinecraftClass("ChunkCoordinates"); + } + + /** + * Retrieve the WatchableObject class. + * @return The WatchableObject class. + */ + @SuppressWarnings("rawtypes") + public static Class getWatchableObjectClass() { + return getMinecraftClass("WatchableObject"); + } + + /** + * Retrieve the ItemStack[] class. + * @return The ItemStack[] class. + */ + @SuppressWarnings("rawtypes") + public static Class getItemStackArrayClass() { + if (itemStackArrayClass == null) + itemStackArrayClass = getArrayClass(getItemStackClass()); + return itemStackArrayClass; + } + + /** + * Retrieve the array class of a given component type. + * @param componentType - type of each element in the array. + * @return The class of the array. + */ + @SuppressWarnings("rawtypes") + public static Class getArrayClass(Class componentType) { + // Bit of a hack, but it works + return Array.newInstance(componentType, 0).getClass(); + } + + /** + * Retrieve the CraftItemStack class. + * @return The CraftItemStack class. + */ + @SuppressWarnings("rawtypes") + public static Class getCraftItemStackClass() { + if (craftItemStackClass == null) + craftItemStackClass = getCraftBukkitClass("inventory.CraftItemStack"); + return craftItemStackClass; + } + + /** + * Retrieve a CraftItemStack from a given ItemStack. + * @param bukkitItemStack - the Bukkit ItemStack to convert. + * @return A CraftItemStack as an ItemStack. + */ + @SuppressWarnings("unchecked") + public static ItemStack getBukkitItemStack(ItemStack bukkitItemStack) { + if (craftBukkitConstructor == null) { + try { + craftBukkitConstructor = getCraftItemStackClass().getConstructor(ItemStack.class); + } catch (Exception e) { + throw new RuntimeException("Cannot find CraftItemStack(org.bukkit.inventory.ItemStack).", e); + } + } + + // Try to create the CraftItemStack + try { + return (ItemStack) craftBukkitConstructor.newInstance(bukkitItemStack); + } catch (Exception e) { + throw new RuntimeException("Cannot construct CraftItemStack.", e); + } + } + + /** + * Retrieve the Bukkit ItemStack from a given net.minecraft.server ItemStack. + * @param minecraftItemStack - the NMS ItemStack to wrap. + * @return The wrapped ItemStack. + */ + @SuppressWarnings("unchecked") + public static ItemStack getBukkitItemStack(Object minecraftItemStack) { + if (craftNMSConstructor == null) { + try { + craftNMSConstructor = getCraftItemStackClass().getConstructor(minecraftItemStack.getClass()); + } catch (Exception e) { + throw new RuntimeException("Cannot find CraftItemStack(net.mineraft.server.ItemStack).", e); + } + } + + // Try to create the CraftItemStack + try { + return (ItemStack) craftNMSConstructor.newInstance(minecraftItemStack); + } catch (Exception e) { + throw new RuntimeException("Cannot construct CraftItemStack.", e); + } + } + + /** + * Retrieve the net.minecraft.server ItemStack from a Bukkit ItemStack. + * @param stack - the Bukkit ItemStack to convert. + * @return The NMS ItemStack. + */ + public static Object getMinecraftItemStack(ItemStack stack) { + // Make sure this is a CraftItemStack + if (!isCraftItemStack(stack)) + stack = getBukkitItemStack(stack); + + BukkitUnwrapper unwrapper = new BukkitUnwrapper(); + return unwrapper.unwrapItem(stack); + } + + /** + * Retrieve the class object of a specific CraftBukkit class. + * @param className - the specific CraftBukkit class. + * @return Class object. + * @throws RuntimeException If we are unable to find the given class. + */ + @SuppressWarnings("rawtypes") + public static Class getCraftBukkitClass(String className) { + if (craftbukkitPackage == null) + craftbukkitPackage = new CachedPackage(getCraftBukkitPackage()); + return craftbukkitPackage.getPackageClass(className); + } + + /** + * Retrieve the class object of a specific Minecraft class. + * @param className - the specific Minecraft class. + * @return Class object. + * @throws RuntimeException If we are unable to find the given class. + */ + @SuppressWarnings("rawtypes") + public static Class getMinecraftClass(String className) { + if (minecraftPackage == null) + minecraftPackage = new CachedPackage(getMinecraftPackage()); + return minecraftPackage.getPackageClass(className); + } } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java index ce2af3e8..7b9bfe49 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java @@ -1,16 +1,13 @@ package com.comphenix.protocol.wrappers; import java.lang.ref.WeakReference; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import net.minecraft.server.DataWatcher; -import net.minecraft.server.WatchableObject; - import org.bukkit.World; import org.bukkit.WorldType; -import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; @@ -19,6 +16,7 @@ import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.instances.DefaultInstances; +import com.comphenix.protocol.utility.MinecraftReflection; /** * Contains several useful equivalent converters for normal Bukkit types. @@ -29,9 +27,13 @@ public class BukkitConverters { // Check whether or not certain classes exists private static boolean hasWorldType = false; + // Used to access the world type + private static Method worldTypeName; + private static Method worldTypeGetType; + static { try { - Class.forName("net.minecraft.server.WorldType"); + Class.forName(MinecraftReflection.getMinecraftPackage() + ".WorldType"); hasWorldType = true; } catch (ClassNotFoundException e) { } @@ -100,8 +102,8 @@ public class BukkitConverters { } public WrappedWatchableObject getSpecific(Object generic) { - if (generic instanceof WatchableObject) - return new WrappedWatchableObject((WatchableObject) generic); + if (MinecraftReflection.isWatchableObject(generic)) + return new WrappedWatchableObject(generic); else if (generic instanceof WrappedWatchableObject) return (WrappedWatchableObject) generic; else @@ -128,8 +130,8 @@ public class BukkitConverters { @Override public WrappedDataWatcher getSpecific(Object generic) { - if (generic instanceof DataWatcher) - return new WrappedDataWatcher((DataWatcher) generic); + if (MinecraftReflection.isDataWatcher(generic)) + return new WrappedDataWatcher(generic); else if (generic instanceof WrappedDataWatcher) return (WrappedDataWatcher) generic; else @@ -153,15 +155,35 @@ public class BukkitConverters { return null; return getIgnoreNull(new EquivalentConverter() { + @SuppressWarnings("unchecked") @Override public Object getGeneric(Class genericType, WorldType specific) { - return net.minecraft.server.WorldType.getType(specific.getName()); + try { + if (worldTypeGetType == null) + worldTypeGetType = MinecraftReflection.getWorldTypeClass().getMethod("getType", String.class); + + // Convert to the Bukkit world type + return worldTypeGetType.invoke(this, specific.getName()); + + } catch (Exception e) { + throw new FieldAccessException("Cannot find the WorldType.getType() method.", e); + } } + @SuppressWarnings("unchecked") @Override public WorldType getSpecific(Object generic) { - net.minecraft.server.WorldType type = (net.minecraft.server.WorldType) generic; - return WorldType.getByName(type.name()); + try { + if (worldTypeName == null) + worldTypeName = MinecraftReflection.getWorldTypeClass().getMethod("name"); + + // Dynamically call the namne method + String name = (String) worldTypeName.invoke(generic); + return WorldType.getByName(name); + + } catch (Exception e) { + throw new FieldAccessException("Cannot call the name method in WorldType.", e); + } } @Override @@ -221,12 +243,12 @@ public class BukkitConverters { public static EquivalentConverter getItemStackConverter() { return getIgnoreNull(new EquivalentConverter() { public Object getGeneric(Class genericType, ItemStack specific) { - return toStackNMS(specific); + return MinecraftReflection.getMinecraftItemStack(specific); } @Override public ItemStack getSpecific(Object generic) { - return new CraftItemStack((net.minecraft.server.ItemStack) generic); + return MinecraftReflection.getBukkitItemStack(generic); } @Override @@ -236,20 +258,6 @@ public class BukkitConverters { }); } - /** - * Convert an item stack to the NMS equivalent. - * @param stack - Bukkit stack to convert. - * @return A bukkit stack. - */ - private static net.minecraft.server.ItemStack toStackNMS(ItemStack stack) { - // We must be prepared for an object that simply implements ItemStcak - if (stack instanceof CraftItemStack) { - return ((CraftItemStack) stack).getHandle(); - } else { - return (new CraftItemStack(stack)).getHandle(); - } - } - /** * Wraps a given equivalent converter in NULL checks, ensuring that such values are ignored. * @param delegate - the underlying equivalent converter. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/ChunkPosition.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/ChunkPosition.java index a00a139a..fd7bc679 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/ChunkPosition.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/ChunkPosition.java @@ -1,10 +1,13 @@ package com.comphenix.protocol.wrappers; +import java.lang.reflect.Constructor; + import org.bukkit.util.Vector; import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.base.Objects; /** @@ -19,6 +22,8 @@ public class ChunkPosition { */ public static ChunkPosition ORIGIN = new ChunkPosition(0, 0, 0); + private static Constructor chunkPositionConstructor; + // Use protected members, like Bukkit protected final int x; protected final int y; @@ -128,27 +133,35 @@ public class ChunkPosition { */ public static EquivalentConverter getConverter() { return new EquivalentConverter() { + @SuppressWarnings("unchecked") @Override public Object getGeneric(Class genericType, ChunkPosition specific) { - return new net.minecraft.server.ChunkPosition(specific.x, specific.y, specific.z); + if (chunkPositionConstructor == null) { + try { + chunkPositionConstructor = MinecraftReflection.getChunkPositionClass(). + getConstructor(int.class, int.class, int.class); + } catch (Exception e) { + throw new RuntimeException("Cannot find chunk position constructor.", e); + } + } + + // Construct the underlying ChunkPosition + try { + return chunkPositionConstructor.newInstance(specific.x, specific.y, specific.z); + } catch (Exception e) { + throw new RuntimeException("Cannot construct ChunkPosition.", e); + } } @Override public ChunkPosition getSpecific(Object generic) { - if (generic instanceof net.minecraft.server.ChunkPosition) { - net.minecraft.server.ChunkPosition other = (net.minecraft.server.ChunkPosition) generic; + if (MinecraftReflection.isChunkPosition(generic)) { + // Use a structure modifier + intModifier = new StructureModifier(generic.getClass(), null, false).withType(int.class); - try { - if (intModifier == null) - return new ChunkPosition(other.x, other.y, other.z); - } catch (LinkageError e) { - // It could happen. If it does, use a structure modifier instead - intModifier = new StructureModifier(other.getClass(), null, false).withType(int.class); - - // Damn it all - if (intModifier.size() < 3) { - throw new IllegalStateException("Cannot read class " + other.getClass() + " for its integer fields."); - } + // Damn it all + if (intModifier.size() < 3) { + throw new IllegalStateException("Cannot read class " + generic.getClass() + " for its integer fields."); } if (intModifier.size() >= 3) { diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinate.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinate.java index 8385770d..2b6bb244 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinate.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChunkCoordinate.java @@ -1,9 +1,9 @@ package com.comphenix.protocol.wrappers; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.base.Objects; -import net.minecraft.server.ChunkCoordinates; - /** * Allows access to a chunk coordinate. * @@ -16,23 +16,42 @@ public class WrappedChunkCoordinate implements Comparable intModifier; + /** * Create a new empty wrapper. */ + @SuppressWarnings("rawtypes") public WrappedChunkCoordinate() { - this(new ChunkCoordinates()); + try { + this.handle = (Comparable) MinecraftReflection.getChunkCoordinatesClass().newInstance(); + initializeModifier(); + } catch (Exception e) { + throw new RuntimeException("Cannot construct chunk coordinate."); + } } /** * Create a wrapper for a specific chunk coordinates. * @param handle - the NMS chunk coordinates. */ - public WrappedChunkCoordinate(ChunkCoordinates handle) { + @SuppressWarnings("rawtypes") + public WrappedChunkCoordinate(Comparable handle) { if (handle == null) throw new IllegalArgumentException("handle cannot be NULL"); this.handle = handle; + initializeModifier(); + } + + // Ensure that the structure modifier is initialized + private void initializeModifier() { + if (intModifier == null) { + intModifier = new StructureModifier(handle.getClass(), null, false).withType(int.class); + } } /** @@ -56,7 +75,7 @@ public class WrappedChunkCoordinate implements Comparable baseModifier; - protected WatchableObject handle; + // Used to create new watchable objects + private static Constructor watchableConstructor; + + protected Object handle; protected StructureModifier modifier; // Type of the stored value @@ -32,7 +36,7 @@ public class WrappedWatchableObject { * Wrap a given raw Minecraft watchable object. * @param handle - the raw watchable object to wrap. */ - public WrappedWatchableObject(WatchableObject handle) { + public WrappedWatchableObject(Object handle) { load(handle); } @@ -41,6 +45,7 @@ public class WrappedWatchableObject { * @param index - the index. * @param value - non-null value of specific types. */ + @SuppressWarnings("unchecked") public WrappedWatchableObject(int index, Object value) { if (value == null) throw new IllegalArgumentException("Value cannot be NULL."); @@ -49,14 +54,28 @@ public class WrappedWatchableObject { Integer typeID = WrappedDataWatcher.getTypeID(value.getClass()); if (typeID != null) { - load(new WatchableObject(typeID, index, getUnwrapped(value))); + if (watchableConstructor == null) { + try { + watchableConstructor = MinecraftReflection.getWatchableObjectClass(). + getConstructor(int.class, int.class, Object.class); + } catch (Exception e) { + throw new RuntimeException("Cannot get the WatchableObject(int, int, Object) constructor.", e); + } + } + + // Create the object + try { + load(watchableConstructor.newInstance(typeID, index, getUnwrapped(value))); + } catch (Exception e) { + throw new RuntimeException("Cannot construct underlying WatchableObject.", e); + } } else { throw new IllegalArgumentException("Cannot watch the type " + value.getClass()); } } // Wrap a NMS object - private void load(WatchableObject handle) { + private void load(Object handle) { initialize(); this.handle = handle; this.modifier = baseModifier.withTarget(handle); @@ -66,7 +85,7 @@ public class WrappedWatchableObject { * Retrieves the underlying watchable object. * @return The underlying watchable object. */ - public WatchableObject getHandle() { + public Object getHandle() { return handle; } @@ -76,7 +95,7 @@ public class WrappedWatchableObject { private static void initialize() { if (!hasInitialized) { hasInitialized = true; - baseModifier = new StructureModifier(WatchableObject.class, null, false); + baseModifier = new StructureModifier(MinecraftReflection.getWatchableObjectClass(), null, false); } } @@ -204,12 +223,13 @@ public class WrappedWatchableObject { * @param value - the raw NMS object to wrap. * @return The wrapped object. */ + @SuppressWarnings("rawtypes") static Object getWrapped(Object value) { // Handle the special cases - if (value instanceof net.minecraft.server.ItemStack) { + if (MinecraftReflection.isItemStack(value)) { return BukkitConverters.getItemStackConverter().getSpecific(value); - } else if (value instanceof ChunkCoordinates) { - return new WrappedChunkCoordinate((ChunkCoordinates) value); + } else if (MinecraftReflection.isChunkCoordinates(value)) { + return new WrappedChunkCoordinate((Comparable) value); } else { return value; } @@ -221,9 +241,9 @@ public class WrappedWatchableObject { * @return The wrapped class type. */ static Class getWrappedType(Class unwrapped) { - if (unwrapped.equals(net.minecraft.server.ChunkPosition.class)) + if (unwrapped.equals(MinecraftReflection.getChunkPositionClass())) return ChunkPosition.class; - else if (unwrapped.equals(ChunkCoordinates.class)) + else if (unwrapped.equals(MinecraftReflection.getChunkCoordinatesClass())) return WrappedChunkCoordinate.class; else return unwrapped; @@ -240,7 +260,7 @@ public class WrappedWatchableObject { return ((WrappedChunkCoordinate) wrapped).getHandle(); else if (wrapped instanceof ItemStack) return BukkitConverters.getItemStackConverter().getGeneric( - net.minecraft.server.ItemStack.class, (org.bukkit.inventory.ItemStack) wrapped); + MinecraftReflection.getItemStackClass(), (ItemStack) wrapped); else return wrapped; } @@ -252,9 +272,9 @@ public class WrappedWatchableObject { */ static Class getUnwrappedType(Class wrapped) { if (wrapped.equals(ChunkPosition.class)) - return net.minecraft.server.ChunkPosition.class; + return MinecraftReflection.getChunkPositionClass(); else if (wrapped.equals(WrappedChunkCoordinate.class)) - return ChunkCoordinates.class; + return MinecraftReflection.getChunkCoordinatesClass(); else return wrapped; } @@ -265,7 +285,8 @@ public class WrappedWatchableObject { * @throws FieldAccessException If we're unable to use reflection. */ public WrappedWatchableObject deepClone() throws FieldAccessException { - WrappedWatchableObject clone = new WrappedWatchableObject(DefaultInstances.DEFAULT.getDefault(WatchableObject.class)); + @SuppressWarnings("unchecked") + WrappedWatchableObject clone = new WrappedWatchableObject(DefaultInstances.DEFAULT.getDefault(MinecraftReflection.getWatchableObjectClass())); clone.setDirtyState(getDirtyState()); clone.setIndex(getIndex()); @@ -279,11 +300,11 @@ public class WrappedWatchableObject { Object value = getValue(); // Only a limited set of references types are supported - if (value instanceof net.minecraft.server.ChunkPosition) { + if (MinecraftReflection.isChunkPosition(value)) { EquivalentConverter converter = ChunkPosition.getConverter(); - return converter.getGeneric(net.minecraft.server.ChunkPosition.class, converter.getSpecific(value)); - } else if (value instanceof ItemStack) { - return ((ItemStack) value).cloneItemStack(); + return converter.getGeneric(MinecraftReflection.getChunkPositionClass(), converter.getSpecific(value)); + } else if (MinecraftReflection.isItemStack(value)) { + return MinecraftReflection.getMinecraftItemStack(MinecraftReflection.getBukkitItemStack(value).clone()); } else { // A string or primitive wrapper, which are all immutable. return value; diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/reflect/StructureModifierTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/reflect/StructureModifierTest.java deleted file mode 100644 index af570e39..00000000 --- a/ProtocolLib/src/test/java/com/comphenix/protocol/reflect/StructureModifierTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.comphenix.protocol.reflect; - -import static org.junit.Assert.*; - -import net.minecraft.server.Packet103SetSlot; - -import org.junit.Test; - -import com.avaje.ebeaninternal.server.cluster.Packet; -import com.comphenix.protocol.reflect.StructureModifier; - -public class StructureModifierTest { - - @Test - public void test() throws FieldAccessException { - - Packet103SetSlot move = new Packet103SetSlot(); - StructureModifier modifier = new StructureModifier( - Packet103SetSlot.class, Packet.class, true); - - move.a = 1; - int value = (Integer) modifier.withTarget(move).withType(int.class).read(0); - - assertEquals(1, value); - } -}