From 6af440789cf2ee1951ef0f3bd00527612c015b8f Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Tue, 7 May 2013 23:11:41 +0200 Subject: [PATCH] Invert the actual packet instance instead of a new instance. In NetworkFieldInjector, we use a "inverted" packet class to undo the data received counter when a packet has been cancelled. Previously, we would generate a proxy class that inherits from the class of the packet (Packet3Chat, etc.) along with its size() method (which is called and added to the counter, cancelling the other packet), but this doesn't work for packets that are dynamically sized such as Packet255KickDisconnect. Instead, we now pass the actual instance to the proxy class through a weak hash map. --- .../protocol/injector/ListenerInvoker.java | 133 +++++++++--------- .../injector/player/InjectedArrayList.java | 38 +++-- 2 files changed, 97 insertions(+), 74 deletions(-) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java index f27b64e5..52b702fc 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java @@ -1,67 +1,68 @@ -/* - * 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; - -import com.comphenix.protocol.events.PacketEvent; - -/** - * Represents an object that initiate the packet listeners. - * - * @author Kristian - */ -public interface ListenerInvoker { - - /** - * Invokes the given packet event for every registered listener. - * @param event - the packet event to invoke. - */ - public abstract void invokePacketRecieving(PacketEvent event); - - /** - * Invokes the given packet event for every registered listener. - * @param event - the packet event to invoke. - */ - public abstract void invokePacketSending(PacketEvent event); - - /** - * Retrieve the associated ID of a packet. - * @param packet - the packet. - * @return The packet ID. - */ - public abstract int getPacketID(Object packet); - - /** - * Associate a given class with the given packet ID. Internal method. - * @param clazz - class to associate. - */ - public abstract void unregisterPacketClass(Class clazz); - - /** - * Remove a given class from the packet registry. Internal method. - * @param clazz - class to remove. - */ - public abstract void registerPacketClass(Class clazz, int packetID); - - /** - * Retrieves the correct packet class from a given packet ID. - * @param packetID - the packet ID. - * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. - * @return The associated class. - */ - public abstract Class getPacketClassFromID(int packetID, boolean forceVanilla); +/* + * 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; + +import com.comphenix.protocol.events.PacketEvent; + +/** + * Represents an object that initiate the packet listeners. + * + * @author Kristian + */ +public interface ListenerInvoker { + + /** + * Invokes the given packet event for every registered listener. + * @param event - the packet event to invoke. + */ + public abstract void invokePacketRecieving(PacketEvent event); + + /** + * Invokes the given packet event for every registered listener. + * @param event - the packet event to invoke. + */ + public abstract void invokePacketSending(PacketEvent event); + + /** + * Retrieve the associated ID of a packet. + * @param packet - the packet. + * @return The packet ID. + */ + public abstract int getPacketID(Object packet); + + /** + * Associate a given class with the given packet ID. Internal method. + * @param clazz - class to associate. + */ + public abstract void unregisterPacketClass(Class clazz); + + /** + * Register a given class in the packet registry. Internal method. + * @param clazz - class to register. + * @param packetID - the the new associated packet ID. + */ + public abstract void registerPacketClass(Class clazz, int packetID); + + /** + * Retrieves the correct packet class from a given packet ID. + * @param packetID - the packet ID. + * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. + * @return The associated class. + */ + public abstract Class getPacketClassFromID(int packetID, boolean forceVanilla); } \ No newline at end of file diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java index 33e45f63..bc4cf76f 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/InjectedArrayList.java @@ -21,12 +21,16 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import com.comphenix.protocol.Packets; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.player.NetworkFieldInjector.FakePacket; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.google.common.collect.MapMaker; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Enhancer; @@ -46,6 +50,9 @@ class InjectedArrayList extends ArrayList { */ private static final long serialVersionUID = -1173865905404280990L; + // Fake inverted proxy objects + private static ConcurrentMap delegateLookup = new MapMaker().weakKeys().makeMap(); + private transient PlayerInjector injector; private transient Set ignoredPackets; private transient ClassLoader classLoader; @@ -108,10 +115,7 @@ class InjectedArrayList extends ArrayList { ListenerInvoker invoker = injector.getInvoker(); int packetID = invoker.getPacketID(source); - Class type = invoker.getPacketClassFromID(packetID, true); - System.out.println(type.getName()); - // We want to subtract the byte amount that were added to the running // total of outstanding packets. Otherwise, cancelling too many packets // might cause a "disconnect.overflow" error. @@ -131,7 +135,7 @@ class InjectedArrayList extends ArrayList { // ect. // } Enhancer ex = new Enhancer(); - ex.setSuperclass(type); + ex.setSuperclass(MinecraftReflection.getPacketClass()); ex.setInterfaces(new Class[] { FakePacket.class } ); ex.setUseCache(true); ex.setClassLoader(classLoader); @@ -143,7 +147,10 @@ class InjectedArrayList extends ArrayList { try { // Temporarily associate the fake packet class invoker.registerPacketClass(proxyClass, packetID); - return proxyClass.newInstance(); + Object proxy = proxyClass.newInstance(); + + InjectedArrayList.registerDelegate(proxy, source); + return proxy; } catch (Exception e) { // Don't pollute the throws tree @@ -154,18 +161,33 @@ class InjectedArrayList extends ArrayList { } } + /** + * Ensure that the inverted integer proxy uses the given object as source. + * @param proxy - inverted integer proxy. + * @param source - source object. + */ + private static void registerDelegate(Object proxy, Object source) { + delegateLookup.put(proxy, source); + } + /** * Inverts the integer result of every integer method. * @author Kristian */ - private class InvertedIntegerCallback implements MethodInterceptor { + private class InvertedIntegerCallback implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { + final Object delegate = delegateLookup.get(obj); + + if (delegate == null) { + throw new IllegalStateException("Unable to find delegate source for " + obj); + } + if (method.getReturnType().equals(int.class) && args.length == 0) { - Integer result = (Integer) proxy.invokeSuper(obj, args); + Integer result = (Integer) proxy.invoke(delegate, args); return -result; } else { - return proxy.invokeSuper(obj, args); + return proxy.invoke(delegate, args); } } }