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