Added yet another player hook method.
This method works by injecting into the NetServerHandler object of a player. That way, we can also intercept map chunk packets.
Dieser Commit ist enthalten in:
Ursprung
9e402a3ab4
Commit
e04a78fc04
@ -0,0 +1,115 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.server.Packet;
|
||||
import net.sf.cglib.proxy.Enhancer;
|
||||
import net.sf.cglib.proxy.Factory;
|
||||
import net.sf.cglib.proxy.MethodInterceptor;
|
||||
import net.sf.cglib.proxy.MethodProxy;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
|
||||
/**
|
||||
* Represents a player hook into the NetServerHandler class.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class NetworkServerInjector extends PlayerInjector {
|
||||
|
||||
private static Method sendPacket;
|
||||
|
||||
public NetworkServerInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException {
|
||||
super(player, manager, sendingFilters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize() throws IllegalAccessException {
|
||||
super.initialize();
|
||||
|
||||
// Get the send packet method!
|
||||
if (hasInitialized) {
|
||||
if (sendPacket == null)
|
||||
sendPacket = FuzzyReflection.fromObject(serverHandler).getMethodByParameters("sendPacket", Packet.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException {
|
||||
Object serverDeleage = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue();
|
||||
|
||||
if (serverDeleage != null) {
|
||||
try {
|
||||
// Note that invocation target exception is a wrapper for a checked exception
|
||||
sendPacket.invoke(serverDeleage, packet);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw e;
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Unable to access send packet method.", e);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Unable to load server handler. Cannot send packet.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectManager() {
|
||||
if (serverHandlerRef == null)
|
||||
throw new IllegalStateException("Cannot find server handler.");
|
||||
// Don't inject twice
|
||||
if (serverHandlerRef.getValue() instanceof Factory)
|
||||
return;
|
||||
|
||||
Enhancer ex = new Enhancer();
|
||||
ex.setClassLoader(manager.getClassLoader());
|
||||
ex.setSuperclass(serverHandler.getClass());
|
||||
ex.setCallback(new MethodInterceptor() {
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
// The send packet method!
|
||||
if (method.equals(sendPacket)) {
|
||||
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(serverHandler, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Inject it now
|
||||
serverHandlerRef.setValue(ex.create());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanupAll() {
|
||||
if (serverHandlerRef != null)
|
||||
serverHandlerRef.revertValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInject() {
|
||||
// Probably always
|
||||
return true;
|
||||
}
|
||||
}
|
@ -60,14 +60,23 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
*/
|
||||
public enum PlayerInjectHooks {
|
||||
/**
|
||||
* Override the packet queue lists in NetworkHandler.
|
||||
* Override the packet queue lists in NetworkHandler.
|
||||
* <p>
|
||||
* Cannot intercept MapChunk packets.
|
||||
*/
|
||||
NETWORK_HANDLER_FIELDS,
|
||||
|
||||
/**
|
||||
* Override the network handler object itself.
|
||||
* Override the network handler object itself. Only works in 1.3.
|
||||
* <p>
|
||||
* Cannot intercept MapChunk packets.
|
||||
*/
|
||||
NETWORK_MANAGER_OBJECT,
|
||||
|
||||
/**
|
||||
* Override the server handler object. Versatile, but slow.
|
||||
*/
|
||||
NETWORK_SERVER_OBJECT;
|
||||
}
|
||||
|
||||
// Create a concurrent set
|
||||
@ -79,7 +88,7 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
private Map<Player, PlayerInjector> playerInjection = new HashMap<Player, PlayerInjector>();
|
||||
|
||||
// Player injection type
|
||||
private PlayerInjectHooks playerHook = PlayerInjectHooks.NETWORK_HANDLER_FIELDS;
|
||||
private PlayerInjectHooks playerHook = PlayerInjectHooks.NETWORK_SERVER_OBJECT;
|
||||
|
||||
// Packet injection
|
||||
private PacketInjector packetInjector;
|
||||
@ -373,6 +382,8 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
return new NetworkFieldInjector(player, this, sendingFilters);
|
||||
case NETWORK_MANAGER_OBJECT:
|
||||
return new NetworkObjectInjector(player, this, sendingFilters);
|
||||
case NETWORK_SERVER_OBJECT:
|
||||
return new NetworkServerInjector(player, this, sendingFilters);
|
||||
default:
|
||||
throw new IllegalArgumentException("Cannot construct a player injector.");
|
||||
}
|
||||
|
@ -56,9 +56,11 @@ abstract class PlayerInjector {
|
||||
|
||||
// Reference to the player's network manager
|
||||
protected VolatileField networkManagerRef;
|
||||
protected VolatileField serverHandlerRef;
|
||||
protected Object networkManager;
|
||||
|
||||
// Current net handler
|
||||
protected Object serverHandler;
|
||||
protected Object netHandler;
|
||||
|
||||
// The packet manager and filters
|
||||
@ -75,12 +77,18 @@ abstract class PlayerInjector {
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the notch (NMS) entity player object.
|
||||
* @return Notch player object.
|
||||
*/
|
||||
protected EntityPlayer getEntityPlayer() {
|
||||
CraftPlayer craft = (CraftPlayer) player;
|
||||
return craft.getHandle();
|
||||
}
|
||||
|
||||
protected void initialize() throws IllegalAccessException {
|
||||
|
||||
CraftPlayer craft = (CraftPlayer) player;
|
||||
EntityPlayer notchEntity = craft.getHandle();
|
||||
|
||||
Object serverHandler = null;
|
||||
EntityPlayer notchEntity = getEntityPlayer();
|
||||
|
||||
if (!hasInitialized) {
|
||||
// Do this first, in case we encounter an exception
|
||||
@ -89,7 +97,8 @@ abstract class PlayerInjector {
|
||||
// Retrieve the server handler
|
||||
if (serverHandlerField == null)
|
||||
serverHandlerField = FuzzyReflection.fromObject(notchEntity).getFieldByType(".*NetServerHandler");
|
||||
serverHandler = FieldUtils.readField(serverHandlerField, notchEntity);
|
||||
serverHandlerRef = new VolatileField(serverHandlerField, notchEntity);
|
||||
serverHandler = serverHandlerRef.getValue();
|
||||
|
||||
// Next, get the network manager
|
||||
if (networkManagerField == null)
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren