Added two different player injection hooks, for compatibility with
TagAPI.
Dieser Commit ist enthalten in:
Ursprung
616213924b
Commit
aa2dcefa0d
@ -10,7 +10,7 @@ import net.sf.cglib.proxy.Enhancer;
|
|||||||
import net.sf.cglib.proxy.MethodInterceptor;
|
import net.sf.cglib.proxy.MethodInterceptor;
|
||||||
import net.sf.cglib.proxy.MethodProxy;
|
import net.sf.cglib.proxy.MethodProxy;
|
||||||
|
|
||||||
import com.comphenix.protocol.injector.PlayerInjector.FakePacket;
|
import com.comphenix.protocol.injector.NetworkFieldInjector.FakePacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The array list that notifies when packets are sent by the server.
|
* The array list that notifies when packets are sent by the server.
|
||||||
|
@ -0,0 +1,145 @@
|
|||||||
|
package com.comphenix.protocol.injector;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.reflect.FieldUtils;
|
||||||
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public class NetworkFieldInjector extends PlayerInjector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker interface that indicates a packet is fake and should not be processed.
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public interface FakePacket {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packets to ignore
|
||||||
|
private Set<Packet> ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap<Packet, Boolean>());
|
||||||
|
|
||||||
|
// Overridden fields
|
||||||
|
private List<VolatileField> overridenLists = new ArrayList<VolatileField>();
|
||||||
|
|
||||||
|
// Sync field
|
||||||
|
private static Field syncField;
|
||||||
|
private Object syncObject;
|
||||||
|
|
||||||
|
public NetworkFieldInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException {
|
||||||
|
super(player, manager, sendingFilters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() throws IllegalAccessException {
|
||||||
|
super.initialize();
|
||||||
|
|
||||||
|
// Get the sync field as well
|
||||||
|
if (hasInitialized) {
|
||||||
|
if (syncField == null)
|
||||||
|
syncField = FuzzyReflection.fromObject(networkManager, true).getFieldByType("java\\.lang\\.Object");
|
||||||
|
syncObject = FieldUtils.readField(syncField, networkManager, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException {
|
||||||
|
|
||||||
|
if (networkManager != null) {
|
||||||
|
try {
|
||||||
|
if (!filtered) {
|
||||||
|
ignoredPackets.add(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that invocation target exception is a wrapper for a checked exception
|
||||||
|
queueMethod.invoke(networkManager, packet);
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new IllegalStateException("Unable to access queue method.", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unable to load network mananager. Cannot send packet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectManager() {
|
||||||
|
|
||||||
|
if (networkManager != null) {
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
StructureModifier<List> list = networkModifier.withType(List.class);
|
||||||
|
|
||||||
|
// Subclass both send queues
|
||||||
|
for (Field field : list.getFields()) {
|
||||||
|
VolatileField overwriter = new VolatileField(field, networkManager, true);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Packet> minecraftList = (List<Packet>) overwriter.getOldValue();
|
||||||
|
|
||||||
|
synchronized(syncObject) {
|
||||||
|
// The list we'll be inserting
|
||||||
|
List<Packet> hackedList = new InjectedArrayList(manager.getClassLoader(), this, ignoredPackets);
|
||||||
|
|
||||||
|
// Add every previously stored packet
|
||||||
|
for (Packet packet : minecraftList) {
|
||||||
|
hackedList.add(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don' keep stale packets around
|
||||||
|
minecraftList.clear();
|
||||||
|
overwriter.setValue(Collections.synchronizedList(hackedList));
|
||||||
|
}
|
||||||
|
|
||||||
|
overridenLists.add(overwriter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void cleanupAll() {
|
||||||
|
// Clean up
|
||||||
|
for (VolatileField overriden : overridenLists) {
|
||||||
|
List<Packet> minecraftList = (List<Packet>) overriden.getOldValue();
|
||||||
|
List<Packet> hacketList = (List<Packet>) overriden.getValue();
|
||||||
|
|
||||||
|
if (minecraftList == hacketList) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a lock before we modify the list
|
||||||
|
synchronized(syncObject) {
|
||||||
|
try {
|
||||||
|
// Copy over current packets
|
||||||
|
for (Packet packet : (List<Packet>) overriden.getValue()) {
|
||||||
|
minecraftList.add(packet);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
overriden.revertValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overridenLists.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
package com.comphenix.protocol.injector;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.minecraft.server.Packet;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection method that overrides the NetworkHandler itself, and it's sendPacket-method.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public class NetworkObjectInjector extends PlayerInjector {
|
||||||
|
public NetworkObjectInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException {
|
||||||
|
super(player, manager, sendingFilters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException {
|
||||||
|
Object networkDelegate = filtered ? networkManagerRef.getValue() : networkManagerRef.getOldValue();
|
||||||
|
|
||||||
|
if (networkDelegate != null) {
|
||||||
|
try {
|
||||||
|
// Note that invocation target exception is a wrapper for a checked exception
|
||||||
|
queueMethod.invoke(networkDelegate, packet);
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new IllegalStateException("Unable to access queue method.", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unable to load network mananager. Cannot send packet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectManager() {
|
||||||
|
|
||||||
|
if (networkManager != null) {
|
||||||
|
final Class<?> networkInterface = networkManagerField.getType();
|
||||||
|
final Object networkDelegate = networkManagerRef.getOldValue();
|
||||||
|
|
||||||
|
// Create our proxy object
|
||||||
|
Object networkProxy = Proxy.newProxyInstance(networkInterface.getClassLoader(),
|
||||||
|
new Class<?>[] { networkInterface }, new InvocationHandler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
|
// OH OH! The queue method!
|
||||||
|
if (method.equals(queueMethod)) {
|
||||||
|
Packet packet = (Packet) args[0];
|
||||||
|
|
||||||
|
if (packet != null) {
|
||||||
|
packet = handlePacketRecieved(packet);
|
||||||
|
|
||||||
|
// A NULL packet indicate cancelling
|
||||||
|
if (packet != null)
|
||||||
|
args[0] = packet;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delegate to our underlying class
|
||||||
|
try {
|
||||||
|
return method.invoke(networkDelegate, args);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw e.getCause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Inject it, if we can.
|
||||||
|
networkManagerRef.setValue(networkProxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanupAll() {
|
||||||
|
// Clean up
|
||||||
|
networkManagerRef.revertValue();
|
||||||
|
}
|
||||||
|
}
|
@ -21,11 +21,7 @@ import java.io.DataInputStream;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import net.minecraft.server.EntityPlayer;
|
import net.minecraft.server.EntityPlayer;
|
||||||
import net.minecraft.server.Packet;
|
import net.minecraft.server.Packet;
|
||||||
@ -39,17 +35,8 @@ import com.comphenix.protocol.reflect.FieldUtils;
|
|||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.VolatileField;
|
import com.comphenix.protocol.reflect.VolatileField;
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
class PlayerInjector {
|
abstract class PlayerInjector {
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker interface that indicates a packet is fake and should not be processed.
|
|
||||||
* @author Kristian
|
|
||||||
*/
|
|
||||||
public interface FakePacket {
|
|
||||||
// Nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the inject hook type. Different types allow for maximum compatibility.
|
* Sets the inject hook type. Different types allow for maximum compatibility.
|
||||||
@ -68,40 +55,34 @@ class PlayerInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cache previously retrieved fields
|
// Cache previously retrieved fields
|
||||||
private static Field serverHandlerField;
|
protected static Field serverHandlerField;
|
||||||
private static Field networkManagerField;
|
protected static Field networkManagerField;
|
||||||
private static Field inputField;
|
protected static Field inputField;
|
||||||
private static Field netHandlerField;
|
protected static Field netHandlerField;
|
||||||
|
|
||||||
// To add our injected array lists
|
// To add our injected array lists
|
||||||
private static StructureModifier<Object> networkModifier;
|
protected static StructureModifier<Object> networkModifier;
|
||||||
|
|
||||||
// And methods
|
// And methods
|
||||||
private static Method queueMethod;
|
protected static Method queueMethod;
|
||||||
private static Method processMethod;
|
protected static Method processMethod;
|
||||||
|
|
||||||
private Player player;
|
protected Player player;
|
||||||
private boolean hasInitialized;
|
protected boolean hasInitialized;
|
||||||
|
|
||||||
// Reference to the player's network manager
|
// Reference to the player's network manager
|
||||||
private VolatileField networkManagerRef;
|
protected VolatileField networkManagerRef;
|
||||||
private Object networkManager;
|
protected Object networkManager;
|
||||||
|
|
||||||
// Current net handler
|
// Current net handler
|
||||||
private Object netHandler;
|
protected Object netHandler;
|
||||||
|
|
||||||
// Overridden fields
|
|
||||||
private List<VolatileField> overridenLists = new ArrayList<VolatileField>();
|
|
||||||
|
|
||||||
// Packets to ignore
|
|
||||||
private Set<Packet> ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap<Packet, Boolean>());
|
|
||||||
|
|
||||||
// The packet manager and filters
|
// The packet manager and filters
|
||||||
private PacketFilterManager manager;
|
protected PacketFilterManager manager;
|
||||||
private Set<Integer> sendingFilters;
|
protected Set<Integer> sendingFilters;
|
||||||
|
|
||||||
// Previous data input
|
// Previous data input
|
||||||
private DataInputStream cachedInput;
|
protected DataInputStream cachedInput;
|
||||||
|
|
||||||
public PlayerInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException {
|
public PlayerInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
@ -110,7 +91,7 @@ class PlayerInjector {
|
|||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize() throws IllegalAccessException {
|
protected void initialize() throws IllegalAccessException {
|
||||||
|
|
||||||
CraftPlayer craft = (CraftPlayer) player;
|
CraftPlayer craft = (CraftPlayer) player;
|
||||||
EntityPlayer notchEntity = craft.getHandle();
|
EntityPlayer notchEntity = craft.getHandle();
|
||||||
@ -214,63 +195,17 @@ class PlayerInjector {
|
|||||||
* @param filtered - whether or not the packet will be filtered by our listeners.
|
* @param filtered - whether or not the packet will be filtered by our listeners.
|
||||||
* @param InvocationTargetException If an error occured when sending the packet.
|
* @param InvocationTargetException If an error occured when sending the packet.
|
||||||
*/
|
*/
|
||||||
public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException {
|
public abstract void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject a hook to catch packets sent to the current player.
|
||||||
|
*/
|
||||||
|
public abstract void injectManager();
|
||||||
|
|
||||||
|
/**
|
||||||
if (networkManager != null) {
|
* Remove all hooks and modifications.
|
||||||
try {
|
*/
|
||||||
if (!filtered) {
|
public abstract void cleanupAll();
|
||||||
ignoredPackets.add(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that invocation target exception is a wrapper for a checked exception
|
|
||||||
queueMethod.invoke(networkManager, packet);
|
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new IllegalStateException("Unable to access queue method.", e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Unable to load network mananager. Cannot send packet.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void injectManager() {
|
|
||||||
|
|
||||||
if (networkManager != null) {
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
StructureModifier<List> list = networkModifier.withType(List.class);
|
|
||||||
|
|
||||||
// Subclass both send queues
|
|
||||||
for (Field field : list.getFields()) {
|
|
||||||
VolatileField overwriter = new VolatileField(field, networkManager, true);
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<Packet> minecraftList = (List<Packet>) overwriter.getOldValue();
|
|
||||||
|
|
||||||
synchronized(minecraftList) {
|
|
||||||
// The list we'll be inserting
|
|
||||||
List<Packet> hackedList = new InjectedArrayList(manager.getClassLoader(), this, ignoredPackets);
|
|
||||||
|
|
||||||
// Add every previously stored packet
|
|
||||||
for (Packet packet : minecraftList) {
|
|
||||||
hackedList.add(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don' keep stale packets around
|
|
||||||
minecraftList.clear();
|
|
||||||
overwriter.setValue(Collections.synchronizedList(hackedList));
|
|
||||||
}
|
|
||||||
|
|
||||||
overridenLists.add(overwriter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows a packet to be recieved by the listeners.
|
* Allows a packet to be recieved by the listeners.
|
||||||
@ -299,6 +234,11 @@ class PlayerInjector {
|
|||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the current player's input stream.
|
||||||
|
* @param cache - whether or not to cache the result of this method.
|
||||||
|
* @return The player's input stream.
|
||||||
|
*/
|
||||||
public DataInputStream getInputStream(boolean cache) {
|
public DataInputStream getInputStream(boolean cache) {
|
||||||
// Get the associated input stream
|
// Get the associated input stream
|
||||||
try {
|
try {
|
||||||
@ -313,30 +253,4 @@ class PlayerInjector {
|
|||||||
throw new RuntimeException("Unable to read input stream.", e);
|
throw new RuntimeException("Unable to read input stream.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void cleanupAll() {
|
|
||||||
// Clean up
|
|
||||||
for (VolatileField overriden : overridenLists) {
|
|
||||||
List<Packet> minecraftList = (List<Packet>) overriden.getOldValue();
|
|
||||||
List<Packet> hacketList = (List<Packet>) overriden.getValue();
|
|
||||||
|
|
||||||
if (minecraftList == hacketList) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a lock before we modify the list
|
|
||||||
synchronized(hacketList) {
|
|
||||||
try {
|
|
||||||
// Copy over current packets
|
|
||||||
for (Packet packet : (List<Packet>) overriden.getValue()) {
|
|
||||||
minecraftList.add(packet);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
overriden.revertValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
overridenLists.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren