Make it possible to specify a custom incoming packet interceptor.
Dieser Commit ist enthalten in:
Ursprung
6cf3307a3b
Commit
7abfd2148e
@ -51,8 +51,9 @@ import com.comphenix.protocol.async.AsyncFilterManager;
|
|||||||
import com.comphenix.protocol.async.AsyncMarker;
|
import com.comphenix.protocol.async.AsyncMarker;
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
import com.comphenix.protocol.events.*;
|
import com.comphenix.protocol.events.*;
|
||||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
|
||||||
import com.comphenix.protocol.injector.packet.PacketInjector;
|
import com.comphenix.protocol.injector.packet.PacketInjector;
|
||||||
|
import com.comphenix.protocol.injector.packet.InjectorFactory;
|
||||||
|
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
@ -180,8 +181,10 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Initialize injection mangers
|
// Initialize injection mangers
|
||||||
this.playerInjection = new PlayerInjectionHandler(classLoader, reporter, isInjectionNecessary, this, packetListeners, server);
|
this.playerInjection = new PlayerInjectionHandler(
|
||||||
this.packetInjector = new PacketInjector(classLoader, this, playerInjection, reporter);
|
classLoader, reporter, isInjectionNecessary, this, packetListeners, server);
|
||||||
|
this.packetInjector = InjectorFactory.getInstance().createProxyInjector(
|
||||||
|
classLoader, this, playerInjection, reporter);
|
||||||
this.asyncFilterManager = new AsyncFilterManager(reporter, server.getScheduler(), this);
|
this.asyncFilterManager = new AsyncFilterManager(reporter, server.getScheduler(), this);
|
||||||
|
|
||||||
// Attempt to load the list of server and client packets
|
// Attempt to load the list of server and client packets
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.comphenix.protocol.injector.packet;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||||
|
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A singleton factory for creating incoming packet injectors.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public class InjectorFactory {
|
||||||
|
private static final InjectorFactory INSTANCE = new InjectorFactory();
|
||||||
|
|
||||||
|
private InjectorFactory() {
|
||||||
|
// No need to construct this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the factory singleton.
|
||||||
|
* @return Factory singleton.
|
||||||
|
*/
|
||||||
|
public static InjectorFactory getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a packet injector that intercepts packets by overriding the packet registry.
|
||||||
|
* @param classLoader - current class loader.
|
||||||
|
* @param manager - packet invoker.
|
||||||
|
* @param playerInjection - to lookup Player by DataInputStream.
|
||||||
|
* @param reporter - error reporter.
|
||||||
|
* @return A packet injector with these features.
|
||||||
|
* @throws IllegalAccessException If we fail to create the injector.
|
||||||
|
*/
|
||||||
|
public PacketInjector createProxyInjector(
|
||||||
|
ClassLoader classLoader, ListenerInvoker manager,
|
||||||
|
PlayerInjectionHandler playerInjection, ErrorReporter reporter) throws IllegalAccessException {
|
||||||
|
|
||||||
|
return new ProxyPacketInjector(classLoader, manager, playerInjection, reporter);
|
||||||
|
}
|
||||||
|
}
|
@ -1,224 +1,51 @@
|
|||||||
/*
|
|
||||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
|
||||||
* Copyright (C) 2012 Kristian S. Stangeland
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
|
||||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with this program;
|
|
||||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
||||||
* 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.comphenix.protocol.injector.packet;
|
package com.comphenix.protocol.injector.packet;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import net.sf.cglib.proxy.Callback;
|
|
||||||
import net.sf.cglib.proxy.Enhancer;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.error.ErrorReporter;
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
|
||||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
|
||||||
import com.comphenix.protocol.reflect.FieldUtils;
|
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is responsible for adding or removing proxy objects that intercepts recieved packets.
|
* Represents a incoming packet injector.
|
||||||
*
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class PacketInjector {
|
public interface PacketInjector {
|
||||||
|
|
||||||
// The "put" method that associates a packet ID with a packet class
|
|
||||||
private static Method putMethod;
|
|
||||||
private static Object intHashMap;
|
|
||||||
|
|
||||||
// The packet filter manager
|
|
||||||
private ListenerInvoker manager;
|
|
||||||
|
|
||||||
// Error reporter
|
|
||||||
private ErrorReporter reporter;
|
|
||||||
|
|
||||||
// Allows us to determine the sender
|
|
||||||
private PlayerInjectionHandler playerInjection;
|
|
||||||
|
|
||||||
// Allows us to look up read packet injectors
|
|
||||||
private Map<Integer, ReadPacketModifier> readModifier;
|
|
||||||
|
|
||||||
// Class loader
|
|
||||||
private ClassLoader classLoader;
|
|
||||||
|
|
||||||
public PacketInjector(ClassLoader classLoader, ListenerInvoker manager,
|
|
||||||
PlayerInjectionHandler playerInjection, ErrorReporter reporter) throws IllegalAccessException {
|
|
||||||
|
|
||||||
this.classLoader = classLoader;
|
|
||||||
this.manager = manager;
|
|
||||||
this.playerInjection = playerInjection;
|
|
||||||
this.reporter = reporter;
|
|
||||||
this.readModifier = new ConcurrentHashMap<Integer, ReadPacketModifier>();
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undo a packet cancel.
|
* Undo a packet cancel.
|
||||||
* @param id - the id of the packet.
|
* @param id - the id of the packet.
|
||||||
* @param packet - packet to uncancel.
|
* @param packet - packet to uncancel.
|
||||||
*/
|
*/
|
||||||
public void undoCancel(Integer id, Object packet) {
|
public abstract void undoCancel(Integer id, Object packet);
|
||||||
ReadPacketModifier modifier = readModifier.get(id);
|
|
||||||
|
|
||||||
// See if this packet has been cancelled before
|
/**
|
||||||
if (modifier != null && modifier.hasCancelled(packet)) {
|
* Start intercepting packets with the given packet ID.
|
||||||
modifier.removeOverride(packet);
|
* @param packetID - the ID of the packets to start intercepting.
|
||||||
}
|
* @return TRUE if we didn't already intercept these packets, FALSE otherwise.
|
||||||
}
|
*/
|
||||||
|
public abstract boolean addPacketHandler(int packetID);
|
||||||
|
|
||||||
private void initialize() throws IllegalAccessException {
|
/**
|
||||||
if (intHashMap == null) {
|
* Stop intercepting packets with the given packet ID.
|
||||||
// We're looking for the first static field with a Minecraft-object. This should be a IntHashMap.
|
* @param packetID - the ID of the packets to stop intercepting.
|
||||||
Field intHashMapField = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true).
|
* @return TRUE if we successfuly stopped intercepting a given packet ID, FALSE otherwise.
|
||||||
getFieldByType(MinecraftReflection.getMinecraftObjectRegex());
|
*/
|
||||||
|
public abstract boolean removePacketHandler(int packetID);
|
||||||
|
|
||||||
try {
|
/**
|
||||||
intHashMap = FieldUtils.readField(intHashMapField, (Object) null, true);
|
* Determine if packets with the given packet ID is being intercepted.
|
||||||
} catch (IllegalArgumentException e) {
|
* @param packetID - the packet ID to lookup.
|
||||||
throw new RuntimeException("Minecraft is incompatible.", e);
|
* @return TRUE if we do, FALSE otherwise.
|
||||||
}
|
*/
|
||||||
|
public abstract boolean hasPacketHandler(int packetID);
|
||||||
|
|
||||||
// Now, get the "put" method.
|
/**
|
||||||
putMethod = FuzzyReflection.fromObject(intHashMap).getMethodByParameters("put", int.class, Object.class);
|
* Retrieve every intercepted packet ID.
|
||||||
}
|
* @return Every intercepted packet ID.
|
||||||
}
|
*/
|
||||||
|
public abstract Set<Integer> getPacketHandlers();
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
public boolean addPacketHandler(int packetID) {
|
|
||||||
if (hasPacketHandler(packetID))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Enhancer ex = new Enhancer();
|
|
||||||
|
|
||||||
// Unfortunately, we can't easily distinguish between these two functions:
|
|
||||||
// * Object lookup(int par1)
|
|
||||||
// * Object removeObject(int par1)
|
|
||||||
|
|
||||||
// So, we'll use the classMapToInt registry instead.
|
|
||||||
Map<Integer, Class> overwritten = PacketRegistry.getOverwrittenPackets();
|
|
||||||
Map<Integer, Class> previous = PacketRegistry.getPreviousPackets();
|
|
||||||
Map<Class, Integer> registry = PacketRegistry.getPacketToID();
|
|
||||||
Class old = PacketRegistry.getPacketClassFromID(packetID);
|
|
||||||
|
|
||||||
// If this packet is not known
|
|
||||||
if (old == null) {
|
|
||||||
throw new IllegalStateException("Packet ID " + packetID + " is not a valid packet ID in this version.");
|
|
||||||
}
|
|
||||||
// Check for previous injections
|
|
||||||
if (!MinecraftReflection.isMinecraftClass(old)) {
|
|
||||||
throw new IllegalStateException("Packet " + packetID + " has already been injected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subclass the specific packet class
|
|
||||||
ex.setSuperclass(old);
|
|
||||||
ex.setCallbackType(ReadPacketModifier.class);
|
|
||||||
ex.setClassLoader(classLoader);
|
|
||||||
Class proxy = ex.createClass();
|
|
||||||
|
|
||||||
// Create the proxy handler
|
|
||||||
ReadPacketModifier modifier = new ReadPacketModifier(packetID, this, reporter);
|
|
||||||
readModifier.put(packetID, modifier);
|
|
||||||
|
|
||||||
// Add a static reference
|
|
||||||
Enhancer.registerStaticCallbacks(proxy, new Callback[] { modifier });
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Override values
|
|
||||||
previous.put(packetID, old);
|
|
||||||
registry.put(proxy, packetID);
|
|
||||||
overwritten.put(packetID, proxy);
|
|
||||||
putMethod.invoke(intHashMap, packetID, proxy);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
throw new RuntimeException("Illegal argument.", e);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new RuntimeException("Cannot access method.", e);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
throw new RuntimeException("Exception occured in IntHashMap.put.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
public boolean removePacketHandler(int packetID) {
|
|
||||||
if (!hasPacketHandler(packetID))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Map<Class, Integer> registry = PacketRegistry.getPacketToID();
|
|
||||||
Map<Integer, Class> previous = PacketRegistry.getPreviousPackets();
|
|
||||||
Map<Integer, Class> overwritten = PacketRegistry.getOverwrittenPackets();
|
|
||||||
|
|
||||||
// Use the old class definition
|
|
||||||
try {
|
|
||||||
Class old = previous.get(packetID);
|
|
||||||
Class proxy = PacketRegistry.getPacketClassFromID(packetID);
|
|
||||||
|
|
||||||
putMethod.invoke(intHashMap, packetID, old);
|
|
||||||
previous.remove(packetID);
|
|
||||||
readModifier.remove(packetID);
|
|
||||||
registry.remove(proxy);
|
|
||||||
overwritten.remove(packetID);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Handle some problems
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return false;
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new RuntimeException("Cannot access method.", e);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
throw new RuntimeException("Exception occured in IntHashMap.put.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPacketHandler(int packetID) {
|
|
||||||
return PacketRegistry.getPreviousPackets().containsKey(packetID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Integer> getPacketHandlers() {
|
|
||||||
return PacketRegistry.getPreviousPackets().keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from the ReadPacketModified monitor
|
|
||||||
public PacketEvent packetRecieved(PacketContainer packet, DataInputStream input) {
|
|
||||||
try {
|
|
||||||
Player client = playerInjection.getPlayerByConnection(input);
|
|
||||||
|
|
||||||
// Never invoke a event if we don't know where it's from
|
|
||||||
if (client != null)
|
|
||||||
return packetRecieved(packet, client);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// We will ignore this - it occurs when a player disconnects
|
|
||||||
//reporter.reportDetailed(this, "Thread was interrupted.", e, packet, input);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let the packet listeners process the given packet.
|
* Let the packet listeners process the given packet.
|
||||||
@ -226,32 +53,10 @@ public class PacketInjector {
|
|||||||
* @param client - the client that sent the packet.
|
* @param client - the client that sent the packet.
|
||||||
* @return The resulting packet event.
|
* @return The resulting packet event.
|
||||||
*/
|
*/
|
||||||
public PacketEvent packetRecieved(PacketContainer packet, Player client) {
|
public abstract PacketEvent packetRecieved(PacketContainer packet, Player client);
|
||||||
PacketEvent event = PacketEvent.fromClient((Object) manager, packet, client);
|
|
||||||
|
|
||||||
manager.invokePacketRecieving(event);
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
public synchronized void cleanupAll() {
|
|
||||||
Map<Integer, Class> overwritten = PacketRegistry.getOverwrittenPackets();
|
|
||||||
Map<Integer, Class> previous = PacketRegistry.getPreviousPackets();
|
|
||||||
|
|
||||||
// Remove every packet handler
|
|
||||||
for (Integer id : previous.keySet().toArray(new Integer[0])) {
|
|
||||||
removePacketHandler(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
overwritten.clear();
|
|
||||||
previous.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inform the current PlayerInjector that it should update the DataInputStream next.
|
* Perform any necessary cleanup before unloading ProtocolLib.
|
||||||
* @param player - the player to update.
|
|
||||||
*/
|
*/
|
||||||
public void scheduleDataInputRefresh(Player player) {
|
public abstract void cleanupAll();
|
||||||
playerInjection.scheduleDataInputRefresh(player);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||||
|
* Copyright (C) 2012 Kristian S. Stangeland
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program;
|
||||||
|
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
* 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.comphenix.protocol.injector.packet;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import net.sf.cglib.proxy.Callback;
|
||||||
|
import net.sf.cglib.proxy.Enhancer;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.error.ErrorReporter;
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||||
|
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
||||||
|
import com.comphenix.protocol.reflect.FieldUtils;
|
||||||
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is responsible for adding or removing proxy objects that intercepts recieved packets.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
class ProxyPacketInjector implements PacketInjector {
|
||||||
|
|
||||||
|
// The "put" method that associates a packet ID with a packet class
|
||||||
|
private static Method putMethod;
|
||||||
|
private static Object intHashMap;
|
||||||
|
|
||||||
|
// The packet filter manager
|
||||||
|
private ListenerInvoker manager;
|
||||||
|
|
||||||
|
// Error reporter
|
||||||
|
private ErrorReporter reporter;
|
||||||
|
|
||||||
|
// Allows us to determine the sender
|
||||||
|
private PlayerInjectionHandler playerInjection;
|
||||||
|
|
||||||
|
// Allows us to look up read packet injectors
|
||||||
|
private Map<Integer, ReadPacketModifier> readModifier;
|
||||||
|
|
||||||
|
// Class loader
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
|
public ProxyPacketInjector(ClassLoader classLoader, ListenerInvoker manager,
|
||||||
|
PlayerInjectionHandler playerInjection, ErrorReporter reporter) throws IllegalAccessException {
|
||||||
|
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
this.manager = manager;
|
||||||
|
this.playerInjection = playerInjection;
|
||||||
|
this.reporter = reporter;
|
||||||
|
this.readModifier = new ConcurrentHashMap<Integer, ReadPacketModifier>();
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo a packet cancel.
|
||||||
|
* @param id - the id of the packet.
|
||||||
|
* @param packet - packet to uncancel.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void undoCancel(Integer id, Object packet) {
|
||||||
|
ReadPacketModifier modifier = readModifier.get(id);
|
||||||
|
|
||||||
|
// See if this packet has been cancelled before
|
||||||
|
if (modifier != null && modifier.hasCancelled(packet)) {
|
||||||
|
modifier.removeOverride(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(MinecraftReflection.getPacketClass(), true).
|
||||||
|
getFieldByType(MinecraftReflection.getMinecraftObjectRegex());
|
||||||
|
|
||||||
|
try {
|
||||||
|
intHashMap = FieldUtils.readField(intHashMapField, (Object) null, true);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new RuntimeException("Minecraft is incompatible.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, get the "put" method.
|
||||||
|
putMethod = FuzzyReflection.fromObject(intHashMap).getMethodByParameters("put", int.class, Object.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public boolean addPacketHandler(int packetID) {
|
||||||
|
if (hasPacketHandler(packetID))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Enhancer ex = new Enhancer();
|
||||||
|
|
||||||
|
// Unfortunately, we can't easily distinguish between these two functions:
|
||||||
|
// * Object lookup(int par1)
|
||||||
|
// * Object removeObject(int par1)
|
||||||
|
|
||||||
|
// So, we'll use the classMapToInt registry instead.
|
||||||
|
Map<Integer, Class> overwritten = PacketRegistry.getOverwrittenPackets();
|
||||||
|
Map<Integer, Class> previous = PacketRegistry.getPreviousPackets();
|
||||||
|
Map<Class, Integer> registry = PacketRegistry.getPacketToID();
|
||||||
|
Class old = PacketRegistry.getPacketClassFromID(packetID);
|
||||||
|
|
||||||
|
// If this packet is not known
|
||||||
|
if (old == null) {
|
||||||
|
throw new IllegalStateException("Packet ID " + packetID + " is not a valid packet ID in this version.");
|
||||||
|
}
|
||||||
|
// Check for previous injections
|
||||||
|
if (!MinecraftReflection.isMinecraftClass(old)) {
|
||||||
|
throw new IllegalStateException("Packet " + packetID + " has already been injected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subclass the specific packet class
|
||||||
|
ex.setSuperclass(old);
|
||||||
|
ex.setCallbackType(ReadPacketModifier.class);
|
||||||
|
ex.setClassLoader(classLoader);
|
||||||
|
Class proxy = ex.createClass();
|
||||||
|
|
||||||
|
// Create the proxy handler
|
||||||
|
ReadPacketModifier modifier = new ReadPacketModifier(packetID, this, reporter);
|
||||||
|
readModifier.put(packetID, modifier);
|
||||||
|
|
||||||
|
// Add a static reference
|
||||||
|
Enhancer.registerStaticCallbacks(proxy, new Callback[] { modifier });
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Override values
|
||||||
|
previous.put(packetID, old);
|
||||||
|
registry.put(proxy, packetID);
|
||||||
|
overwritten.put(packetID, proxy);
|
||||||
|
putMethod.invoke(intHashMap, packetID, proxy);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new RuntimeException("Illegal argument.", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException("Cannot access method.", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new RuntimeException("Exception occured in IntHashMap.put.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public boolean removePacketHandler(int packetID) {
|
||||||
|
if (!hasPacketHandler(packetID))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Map<Class, Integer> registry = PacketRegistry.getPacketToID();
|
||||||
|
Map<Integer, Class> previous = PacketRegistry.getPreviousPackets();
|
||||||
|
Map<Integer, Class> overwritten = PacketRegistry.getOverwrittenPackets();
|
||||||
|
|
||||||
|
// Use the old class definition
|
||||||
|
try {
|
||||||
|
Class old = previous.get(packetID);
|
||||||
|
Class proxy = PacketRegistry.getPacketClassFromID(packetID);
|
||||||
|
|
||||||
|
putMethod.invoke(intHashMap, packetID, old);
|
||||||
|
previous.remove(packetID);
|
||||||
|
readModifier.remove(packetID);
|
||||||
|
registry.remove(proxy);
|
||||||
|
overwritten.remove(packetID);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Handle some problems
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return false;
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException("Cannot access method.", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new RuntimeException("Exception occured in IntHashMap.put.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPacketHandler(int packetID) {
|
||||||
|
return PacketRegistry.getPreviousPackets().containsKey(packetID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Integer> getPacketHandlers() {
|
||||||
|
return PacketRegistry.getPreviousPackets().keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called from the ReadPacketModified monitor
|
||||||
|
public PacketEvent packetRecieved(PacketContainer packet, DataInputStream input) {
|
||||||
|
try {
|
||||||
|
Player client = playerInjection.getPlayerByConnection(input);
|
||||||
|
|
||||||
|
// Never invoke a event if we don't know where it's from
|
||||||
|
if (client != null)
|
||||||
|
return packetRecieved(packet, client);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// We will ignore this - it occurs when a player disconnects
|
||||||
|
//reporter.reportDetailed(this, "Thread was interrupted.", e, packet, input);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Let the packet listeners process the given packet.
|
||||||
|
* @param packet - a packet to process.
|
||||||
|
* @param client - the client that sent the packet.
|
||||||
|
* @return The resulting packet event.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PacketEvent packetRecieved(PacketContainer packet, Player client) {
|
||||||
|
PacketEvent event = PacketEvent.fromClient((Object) manager, packet, client);
|
||||||
|
|
||||||
|
manager.invokePacketRecieving(event);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public synchronized void cleanupAll() {
|
||||||
|
Map<Integer, Class> overwritten = PacketRegistry.getOverwrittenPackets();
|
||||||
|
Map<Integer, Class> previous = PacketRegistry.getPreviousPackets();
|
||||||
|
|
||||||
|
// Remove every packet handler
|
||||||
|
for (Integer id : previous.keySet().toArray(new Integer[0])) {
|
||||||
|
removePacketHandler(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
overwritten.clear();
|
||||||
|
previous.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inform the current PlayerInjector that it should update the DataInputStream next.
|
||||||
|
* @param player - the player to update.
|
||||||
|
*/
|
||||||
|
public void scheduleDataInputRefresh(Player player) {
|
||||||
|
playerInjection.scheduleDataInputRefresh(player);
|
||||||
|
}
|
||||||
|
}
|
@ -41,7 +41,7 @@ class ReadPacketModifier implements MethodInterceptor {
|
|||||||
private static final Object CANCEL_MARKER = new Object();
|
private static final Object CANCEL_MARKER = new Object();
|
||||||
|
|
||||||
// Common for all packets of the same type
|
// Common for all packets of the same type
|
||||||
private PacketInjector packetInjector;
|
private ProxyPacketInjector packetInjector;
|
||||||
private int packetID;
|
private int packetID;
|
||||||
|
|
||||||
// Report errors
|
// Report errors
|
||||||
@ -50,7 +50,7 @@ class ReadPacketModifier implements MethodInterceptor {
|
|||||||
// Whether or not a packet has been cancelled
|
// Whether or not a packet has been cancelled
|
||||||
private static Map<Object, Object> override = Collections.synchronizedMap(new WeakHashMap<Object, Object>());
|
private static Map<Object, Object> override = Collections.synchronizedMap(new WeakHashMap<Object, Object>());
|
||||||
|
|
||||||
public ReadPacketModifier(int packetID, PacketInjector packetInjector, ErrorReporter reporter) {
|
public ReadPacketModifier(int packetID, ProxyPacketInjector packetInjector, ErrorReporter reporter) {
|
||||||
this.packetID = packetID;
|
this.packetID = packetID;
|
||||||
this.packetInjector = packetInjector;
|
this.packetInjector = packetInjector;
|
||||||
this.reporter = reporter;
|
this.reporter = reporter;
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren