package lilypad.bukkit.connect.injector; import java.lang.reflect.Modifier; import java.util.Map; import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.CtField; import javassist.CtMethod; import javassist.NotFoundException; import javassist.expr.ExprEditor; import javassist.expr.MethodCall; import lilypad.bukkit.connect.ConnectPlugin; import lilypad.bukkit.connect.util.JavassistUtil; import lilypad.bukkit.connect.util.ReflectionUtils; import org.bukkit.Server; public class PacketInjector { @SuppressWarnings({ "rawtypes", "unchecked" }) public static void injectStringMaxSize(Server server, String protocol, int packetId, final int maxSize) throws Exception { Object minecraftServer = ReflectionUtils.getPrivateField(server.getClass(), server, Object.class, "console"); String minecraftServerClassName = minecraftServer.getClass().getName(); final String minecraftPackage = minecraftServerClassName.substring(0, minecraftServerClassName.lastIndexOf('.')); // get the packet Map serverBound; Class<?> enumProtocolClass = Class.forName(minecraftPackage + ".EnumProtocol"); Object enumProtocol = ReflectionUtils.getPrivateField(enumProtocolClass, null, enumProtocolClass, protocol.toUpperCase()); if (ConnectPlugin.getProtocol().getGeneralVersion().equalsIgnoreCase("1.7")) { serverBound = ReflectionUtils.getPrivateField(enumProtocolClass, enumProtocol, Map.class, ConnectPlugin.getProtocol().getPacketInjectorProtocolDirections()); } else { Map protocolDirections = ReflectionUtils.getPrivateField(enumProtocolClass, enumProtocol, Map.class, ConnectPlugin.getProtocol().getPacketInjectorProtocolDirections()); Object serverBoundDirection = ReflectionUtils.getPrivateField(Class.forName(minecraftPackage + ".EnumProtocolDirection"), null, Object.class, "SERVERBOUND"); serverBound = (Map) protocolDirections.get(serverBoundDirection); } if(!serverBound.containsKey(packetId)) { throw new IllegalArgumentException("Packet Id does not exist: " + packetId); } Class<?> packetClass = (Class<?>) serverBound.get(packetId); // create packet proxy ClassPool classPool = JavassistUtil.getClassPool(); CtClass packetCtClass = classPool.getCtClass(packetClass.getName()); final CtClass packetCtClassProxy = classPool.getAndRename(packetClass.getName(), packetClass.getName() + "$stringMaxSize" + maxSize); packetCtClassProxy.setSuperclass(packetCtClass); for(CtField field : packetCtClassProxy.getDeclaredFields()) { if(Modifier.isPrivate(field.getModifiers())) { continue; } packetCtClassProxy.removeField(field); } CtMethod decodeCtMethod = packetCtClassProxy.getDeclaredMethod(ConnectPlugin.getProtocol().getPacketInjectorDecodeCtMethod(), new CtClass[] { classPool.getCtClass(minecraftPackage + ".PacketDataSerializer") }); decodeCtMethod.instrument(new ExprEditor() { public void edit(MethodCall methodCall) throws CannotCompileException { if(!methodCall.getClassName().equals(minecraftPackage + ".PacketDataSerializer") || !methodCall.getMethodName().equals("c") || !methodCall.getSignature().equals("(I)Ljava/lang/String;")) { return; } methodCall.replace("{ $1 = " + maxSize + "; $_ = $proceed($$); }"); } }); CtMethod handleCtMethod = packetCtClassProxy.getDeclaredMethod(ConnectPlugin.getProtocol().getPacketInjectorHandleCtMethod(), new CtClass[] { classPool.getCtClass(minecraftPackage + ".PacketListener") }); handleCtMethod.instrument(new ExprEditor() { public void edit(MethodCall methodCall) throws CannotCompileException { try { methodCall.getMethod().setBody("{ super.a($$); }"); } catch (NotFoundException exception) { exception.printStackTrace(); } } }); Class<?> packetClassProxy = packetCtClassProxy.toClass(); // replace packet serverBound.put(packetId, packetClassProxy); } }