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.
Dieser Commit ist enthalten in:
Ursprung
45c28d47c8
Commit
0745fba881
@ -139,7 +139,7 @@
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>craftbukkit</artifactId>
|
||||
<version>1.3.2-R1.0</version>
|
||||
<version>1.4.5-R0.3-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -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) {
|
||||
|
@ -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<AsyncMarker> {
|
||||
|
||||
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<Method> methods = FuzzyReflection.fromClass(Packet.class).
|
||||
List<Method> methods = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).
|
||||
getMethodListByParameters(boolean.class, new Class[] {});
|
||||
|
||||
// Try to look for boolean methods
|
||||
|
@ -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<Object> 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<Object> structure) {
|
||||
public PacketContainer(int id, Object handle, StructureModifier<Object> 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<ItemStack> getItemModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<ItemStack>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.<ItemStack[]>withType(
|
||||
net.minecraft.server.ItemStack[].class,
|
||||
MinecraftReflection.getItemStackArrayClass(),
|
||||
BukkitConverters.getIgnoreNull(new EquivalentConverter<ItemStack[]>() {
|
||||
|
||||
public Object getGeneric(Class<?>genericType, 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<WorldType> getWorldTypeModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<WorldType>withType(
|
||||
net.minecraft.server.WorldType.class,
|
||||
MinecraftReflection.getWorldTypeClass(),
|
||||
BukkitConverters.getWorldTypeConverter());
|
||||
}
|
||||
|
||||
@ -292,7 +291,7 @@ public class PacketContainer implements Serializable {
|
||||
public StructureModifier<WrappedDataWatcher> getDataWatcherModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<WrappedDataWatcher>withType(
|
||||
net.minecraft.server.DataWatcher.class,
|
||||
MinecraftReflection.getDataWatcherClass(),
|
||||
BukkitConverters.getDataWatcherConverter());
|
||||
}
|
||||
|
||||
@ -319,7 +318,7 @@ public class PacketContainer implements Serializable {
|
||||
public StructureModifier<ChunkPosition> 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())
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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<Object> value = new StructureModifier<Object>(
|
||||
MinecraftRegistry.getPacketClassFromID(id, true), Packet.class, true);
|
||||
MinecraftRegistry.getPacketClassFromID(id, true), MinecraftReflection.getPacketClass(), true);
|
||||
|
||||
result = structureModifiers.putIfAbsent(id, value);
|
||||
|
||||
|
@ -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<Packet> {
|
||||
class InjectedArrayList extends ArrayList<Object> {
|
||||
|
||||
/**
|
||||
* Silly Eclipse.
|
||||
@ -44,12 +43,12 @@ class InjectedArrayList extends ArrayList<Packet> {
|
||||
private static final long serialVersionUID = -1173865905404280990L;
|
||||
|
||||
private transient PlayerInjector injector;
|
||||
private transient Set<Packet> ignoredPackets;
|
||||
private transient Set<Object> ignoredPackets;
|
||||
private transient ClassLoader classLoader;
|
||||
|
||||
private transient InvertedIntegerCallback callback;
|
||||
|
||||
public InjectedArrayList(ClassLoader classLoader, PlayerInjector injector, Set<Packet> ignoredPackets) {
|
||||
public InjectedArrayList(ClassLoader classLoader, PlayerInjector injector, Set<Object> ignoredPackets) {
|
||||
this.classLoader = classLoader;
|
||||
this.injector = injector;
|
||||
this.ignoredPackets = ignoredPackets;
|
||||
@ -57,9 +56,9 @@ class InjectedArrayList extends ArrayList<Packet> {
|
||||
}
|
||||
|
||||
@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<Packet> {
|
||||
* @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<Packet> {
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<Packet> ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap<Packet, Boolean>());
|
||||
private Set<Object> ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap<Object, Boolean>());
|
||||
|
||||
// Overridden fields
|
||||
private List<VolatileField> overridenLists = new ArrayList<VolatileField>();
|
||||
@ -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<Packet> minecraftList = (List<Packet>) overwriter.getOldValue();
|
||||
List<Object> minecraftList = (List<Object>) overwriter.getOldValue();
|
||||
|
||||
synchronized(syncObject) {
|
||||
// The list we'll be inserting
|
||||
List<Packet> hackedList = new InjectedArrayList(classLoader, this, ignoredPackets);
|
||||
List<Object> 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<Packet> minecraftList = (List<Packet>) overriden.getOldValue();
|
||||
List<Packet> hacketList = (List<Packet>) overriden.getValue();
|
||||
List<Object> minecraftList = (List<Object>) overriden.getOldValue();
|
||||
List<Object> hacketList = (List<Object>) 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<Packet>) overriden.getValue()) {
|
||||
for (Object packet : (List<Object>) overriden.getValue()) {
|
||||
minecraftList.add(packet);
|
||||
}
|
||||
} finally {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,14 +409,14 @@ 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).
|
||||
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);
|
||||
}
|
||||
|
@ -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<String, Class<?>> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
@ -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<WorldType>() {
|
||||
@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<ItemStack> getItemStackConverter() {
|
||||
return getIgnoreNull(new EquivalentConverter<ItemStack>() {
|
||||
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.
|
||||
|
@ -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<ChunkPosition> getConverter() {
|
||||
return new EquivalentConverter<ChunkPosition>() {
|
||||
@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;
|
||||
|
||||
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<Object>(other.getClass(), null, false).withType(int.class);
|
||||
if (MinecraftReflection.isChunkPosition(generic)) {
|
||||
// Use a structure modifier
|
||||
intModifier = new StructureModifier<Object>(generic.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.");
|
||||
}
|
||||
throw new IllegalStateException("Cannot read class " + generic.getClass() + " for its integer fields.");
|
||||
}
|
||||
|
||||
if (intModifier.size() >= 3) {
|
||||
|
@ -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<WrappedChunkCoordinate
|
||||
*/
|
||||
private static final boolean LARGER_THAN_NULL = true;
|
||||
|
||||
protected ChunkCoordinates handle;
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected Comparable handle;
|
||||
|
||||
// Used to access a ChunkCoordinate
|
||||
private static StructureModifier<Integer> 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<Object>(handle.getClass(), null, false).withType(int.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,7 +75,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
||||
this(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
public ChunkCoordinates getHandle() {
|
||||
public Object getHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
@ -65,7 +84,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
||||
* @return The x coordinate.
|
||||
*/
|
||||
public int getX() {
|
||||
return handle.x;
|
||||
return intModifier.read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,7 +92,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
||||
* @param newX - the new x coordinate.
|
||||
*/
|
||||
public void setX(int newX) {
|
||||
handle.x = newX;
|
||||
intModifier.write(0, newX);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,7 +100,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
||||
* @return The y coordinate.
|
||||
*/
|
||||
public int getY() {
|
||||
return handle.y;
|
||||
return intModifier.read(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,7 +108,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
||||
* @param newY - the new y coordinate.
|
||||
*/
|
||||
public void setY(int newY) {
|
||||
handle.y = newY;
|
||||
intModifier.write(1, newY);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,7 +116,15 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
||||
* @return The z coordinate.
|
||||
*/
|
||||
public int getZ() {
|
||||
return handle.z;
|
||||
return intModifier.read(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the z coordinate of the underlying coordiate.
|
||||
* @param newZ - the new z coordinate.
|
||||
*/
|
||||
public void setZ(int newZ) {
|
||||
intModifier.write(2, newZ);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,14 +135,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
||||
return new ChunkPosition(getX(), getY(), getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the z coordinate of the underlying coordiate.
|
||||
* @param newZ - the new z coordinate.
|
||||
*/
|
||||
public void setZ(int newZ) {
|
||||
handle.z = newZ;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public int compareTo(WrappedChunkCoordinate other) {
|
||||
// We'll handle NULL objects too, unlike ChunkCoordinates
|
||||
|
@ -20,11 +20,9 @@ import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
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 net.minecraft.server.DataWatcher;
|
||||
import net.minecraft.server.WatchableObject;
|
||||
|
||||
/**
|
||||
* Wraps a DataWatcher that is used to transmit arbitrary key-value pairs with a given entity.
|
||||
*
|
||||
@ -55,7 +53,7 @@ public class WrappedDataWatcher {
|
||||
private static boolean hasInitialized;
|
||||
|
||||
// The underlying DataWatcher we're modifying
|
||||
protected DataWatcher handle;
|
||||
protected Object handle;
|
||||
|
||||
// Lock
|
||||
private ReadWriteLock readWriteLock;
|
||||
@ -69,7 +67,13 @@ public class WrappedDataWatcher {
|
||||
*/
|
||||
public WrappedDataWatcher() {
|
||||
// Just create a new watcher
|
||||
this(new DataWatcher());
|
||||
try {
|
||||
this.handle = MinecraftReflection.getDataWatcherClass().newInstance();
|
||||
initialize();
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to construct DataWatcher.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,14 +81,14 @@ public class WrappedDataWatcher {
|
||||
* @param handle - the data watcher to wrap.
|
||||
* @throws FieldAccessException If we're unable to wrap a DataWatcher.
|
||||
*/
|
||||
public WrappedDataWatcher(DataWatcher handle) {
|
||||
this.handle = handle;
|
||||
public WrappedDataWatcher(Object handle) {
|
||||
if (handle == null)
|
||||
throw new IllegalArgumentException("Handle cannot be NULL.");
|
||||
if (!MinecraftReflection.isDataWatcher(handle))
|
||||
throw new IllegalArgumentException("The value " + handle + " is not a DataWatcher.");
|
||||
|
||||
try {
|
||||
this.handle = handle;
|
||||
initialize();
|
||||
} catch (FieldAccessException e) {
|
||||
throw new RuntimeException("Cannot initialize wrapper.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,7 +109,7 @@ public class WrappedDataWatcher {
|
||||
* Retrieves the underlying data watcher.
|
||||
* @return The underlying data watcher.
|
||||
*/
|
||||
public DataWatcher getHandle() {
|
||||
public Object getHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
@ -215,7 +219,7 @@ public class WrappedDataWatcher {
|
||||
*/
|
||||
public Object getObject(int index) throws FieldAccessException {
|
||||
// The get method will take care of concurrency
|
||||
WatchableObject watchable = getWatchedObject(index);
|
||||
Object watchable = getWatchedObject(index);
|
||||
|
||||
if (watchable != null) {
|
||||
return new WrappedWatchableObject(watchable).getValue();
|
||||
@ -238,7 +242,7 @@ public class WrappedDataWatcher {
|
||||
// Add each watchable object to the list
|
||||
for (Object watchable : getWatchableObjectMap().values()) {
|
||||
if (watchable != null) {
|
||||
result.add(new WrappedWatchableObject((WatchableObject) watchable));
|
||||
result.add(new WrappedWatchableObject(watchable));
|
||||
} else {
|
||||
result.add(null);
|
||||
}
|
||||
@ -305,7 +309,7 @@ public class WrappedDataWatcher {
|
||||
writeLock.lock();
|
||||
|
||||
try {
|
||||
WatchableObject watchable = getWatchedObject(index);
|
||||
Object watchable = getWatchedObject(index);
|
||||
|
||||
if (watchable != null) {
|
||||
new WrappedWatchableObject(watchable).setValue(newValue, update);
|
||||
@ -325,18 +329,18 @@ public class WrappedDataWatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private WatchableObject getWatchedObject(int index) throws FieldAccessException {
|
||||
private Object getWatchedObject(int index) throws FieldAccessException {
|
||||
// We use the get-method first and foremost
|
||||
if (getKeyValueMethod != null) {
|
||||
try {
|
||||
return (WatchableObject) getKeyValueMethod.invoke(handle, index);
|
||||
return getKeyValueMethod.invoke(handle, index);
|
||||
} catch (Exception e) {
|
||||
throw new FieldAccessException("Cannot invoke get key method for index " + index, e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
getReadWriteLock().readLock().lock();
|
||||
return (WatchableObject) getWatchableObjectMap().get(index);
|
||||
return getWatchableObjectMap().get(index);
|
||||
|
||||
} finally {
|
||||
getReadWriteLock().readLock().unlock();
|
||||
@ -388,8 +392,8 @@ public class WrappedDataWatcher {
|
||||
*/
|
||||
public static WrappedDataWatcher getEntityWatcher(Entity entity) throws FieldAccessException {
|
||||
if (entityDataField == null)
|
||||
entityDataField = FuzzyReflection.fromClass(net.minecraft.server.Entity.class, true).
|
||||
getFieldByType("datawatcher", DataWatcher.class);
|
||||
entityDataField = FuzzyReflection.fromClass(MinecraftReflection.getEntityClass(), true).
|
||||
getFieldByType("datawatcher", MinecraftReflection.getDataWatcherClass());
|
||||
|
||||
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||
|
||||
@ -397,7 +401,7 @@ public class WrappedDataWatcher {
|
||||
Object nsmWatcher = FieldUtils.readField(entityDataField, unwrapper.unwrapItem(entity), true);
|
||||
|
||||
if (nsmWatcher != null)
|
||||
return new WrappedDataWatcher((DataWatcher) nsmWatcher);
|
||||
return new WrappedDataWatcher(nsmWatcher);
|
||||
else
|
||||
return null;
|
||||
|
||||
@ -417,7 +421,7 @@ public class WrappedDataWatcher {
|
||||
else
|
||||
return;
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(DataWatcher.class, true);
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getDataWatcherClass(), true);
|
||||
|
||||
for (Field lookup : fuzzy.getFieldListByType(Map.class)) {
|
||||
if (Modifier.isStatic(lookup.getModifiers())) {
|
||||
|
@ -1,13 +1,14 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
|
||||
import net.minecraft.server.ChunkCoordinates;
|
||||
import net.minecraft.server.ItemStack;
|
||||
import net.minecraft.server.WatchableObject;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
* Represents a watchable object.
|
||||
@ -22,7 +23,10 @@ public class WrappedWatchableObject {
|
||||
// The field containing the value itself
|
||||
private static StructureModifier<Object> baseModifier;
|
||||
|
||||
protected WatchableObject handle;
|
||||
// Used to create new watchable objects
|
||||
private static Constructor<?> watchableConstructor;
|
||||
|
||||
protected Object handle;
|
||||
protected StructureModifier<Object> 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<Object>(WatchableObject.class, null, false);
|
||||
baseModifier = new StructureModifier<Object>(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<ChunkPosition> 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;
|
||||
|
@ -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<Object> modifier = new StructureModifier<Object>(
|
||||
Packet103SetSlot.class, Packet.class, true);
|
||||
|
||||
move.a = 1;
|
||||
int value = (Integer) modifier.withTarget(move).withType(int.class).read(0);
|
||||
|
||||
assertEquals(1, value);
|
||||
}
|
||||
}
|
In neuem Issue referenzieren
Einen Benutzer sperren