mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-10-31 16:00:52 +01:00
Added two different player injection hooks, for compatibility with
TagAPI.
This commit is contained in:
parent
616213924b
commit
aa2dcefa0d
@ -10,7 +10,7 @@ import net.sf.cglib.proxy.Enhancer;
|
||||
import net.sf.cglib.proxy.MethodInterceptor;
|
||||
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.
|
||||
|
@ -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.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.minecraft.server.EntityPlayer;
|
||||
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.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.VolatileField;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
class PlayerInjector {
|
||||
|
||||
/**
|
||||
* Marker interface that indicates a packet is fake and should not be processed.
|
||||
* @author Kristian
|
||||
*/
|
||||
public interface FakePacket {
|
||||
// Nothing
|
||||
}
|
||||
abstract class PlayerInjector {
|
||||
|
||||
/**
|
||||
* Sets the inject hook type. Different types allow for maximum compatibility.
|
||||
@ -68,40 +55,34 @@ class PlayerInjector {
|
||||
}
|
||||
|
||||
// Cache previously retrieved fields
|
||||
private static Field serverHandlerField;
|
||||
private static Field networkManagerField;
|
||||
private static Field inputField;
|
||||
private static Field netHandlerField;
|
||||
protected static Field serverHandlerField;
|
||||
protected static Field networkManagerField;
|
||||
protected static Field inputField;
|
||||
protected static Field netHandlerField;
|
||||
|
||||
// To add our injected array lists
|
||||
private static StructureModifier<Object> networkModifier;
|
||||
protected static StructureModifier<Object> networkModifier;
|
||||
|
||||
// And methods
|
||||
private static Method queueMethod;
|
||||
private static Method processMethod;
|
||||
protected static Method queueMethod;
|
||||
protected static Method processMethod;
|
||||
|
||||
private Player player;
|
||||
private boolean hasInitialized;
|
||||
protected Player player;
|
||||
protected boolean hasInitialized;
|
||||
|
||||
// Reference to the player's network manager
|
||||
private VolatileField networkManagerRef;
|
||||
private Object networkManager;
|
||||
protected VolatileField networkManagerRef;
|
||||
protected Object networkManager;
|
||||
|
||||
// Current net handler
|
||||
private Object netHandler;
|
||||
|
||||
// Overridden fields
|
||||
private List<VolatileField> overridenLists = new ArrayList<VolatileField>();
|
||||
|
||||
// Packets to ignore
|
||||
private Set<Packet> ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap<Packet, Boolean>());
|
||||
protected Object netHandler;
|
||||
|
||||
// The packet manager and filters
|
||||
private PacketFilterManager manager;
|
||||
private Set<Integer> sendingFilters;
|
||||
protected PacketFilterManager manager;
|
||||
protected Set<Integer> sendingFilters;
|
||||
|
||||
// Previous data input
|
||||
private DataInputStream cachedInput;
|
||||
protected DataInputStream cachedInput;
|
||||
|
||||
public PlayerInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException {
|
||||
this.player = player;
|
||||
@ -110,7 +91,7 @@ class PlayerInjector {
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() throws IllegalAccessException {
|
||||
protected void initialize() throws IllegalAccessException {
|
||||
|
||||
CraftPlayer craft = (CraftPlayer) player;
|
||||
EntityPlayer notchEntity = craft.getHandle();
|
||||
@ -214,63 +195,17 @@ 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 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) {
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove all hooks and modifications.
|
||||
*/
|
||||
public abstract void cleanupAll();
|
||||
|
||||
/**
|
||||
* Allows a packet to be recieved by the listeners.
|
||||
@ -299,6 +234,11 @@ class PlayerInjector {
|
||||
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) {
|
||||
// Get the associated input stream
|
||||
try {
|
||||
@ -313,30 +253,4 @@ class PlayerInjector {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user