From c2b4b5fce3ba6c65dc06be1dfe4c99276f4770b7 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Mon, 1 Oct 2012 02:17:13 +0200 Subject: [PATCH] Ensure that the compiled structures respect the converter field. In addition, fixed a bug that prevented client listeners from receiving any packets. --- .../protocol/events/PacketEvent.java | 2 + .../injector/PacketFilterManager.java | 11 +++-- .../protocol/injector/PlayerInjector.java | 2 +- .../protocol/injector/ReadPacketModifier.java | 2 +- .../injector/SortedPacketListenerList.java | 2 +- .../protocol/reflect/StructureModifier.java | 17 ++++++-- .../compiler/CompiledStructureModifier.java | 30 +++++++++++++- .../reflect/compiler/StructureCompiler.java | 41 +++++++++---------- 8 files changed, 75 insertions(+), 32 deletions(-) diff --git a/ProtocolLib/src/com/comphenix/protocol/events/PacketEvent.java b/ProtocolLib/src/com/comphenix/protocol/events/PacketEvent.java index 799154f3..92b039fa 100644 --- a/ProtocolLib/src/com/comphenix/protocol/events/PacketEvent.java +++ b/ProtocolLib/src/com/comphenix/protocol/events/PacketEvent.java @@ -148,6 +148,8 @@ public class PacketEvent extends EventObject implements Cancellable { /** * Whether or not this packet was created by the server. + *

+ * Most listeners can deduce this by noting which listener method was invoked. * @return TRUE if the packet was created by the server, FALSE if it was created by a client. */ public boolean isServerPacket() { diff --git a/ProtocolLib/src/com/comphenix/protocol/injector/PacketFilterManager.java b/ProtocolLib/src/com/comphenix/protocol/injector/PacketFilterManager.java index 6d854ccb..e9009586 100644 --- a/ProtocolLib/src/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/ProtocolLib/src/com/comphenix/protocol/injector/PacketFilterManager.java @@ -293,7 +293,7 @@ public final class PacketFilterManager implements ProtocolManager { * @param event - the packet event to invoke. */ public void invokePacketRecieving(PacketEvent event) { - handlePacket(recievedListeners, event); + handlePacket(recievedListeners, event, false); } /** @@ -301,7 +301,7 @@ public final class PacketFilterManager implements ProtocolManager { * @param event - the packet event to invoke. */ public void invokePacketSending(PacketEvent event) { - handlePacket(sendingListeners, event); + handlePacket(sendingListeners, event, true); } /** @@ -311,7 +311,7 @@ public final class PacketFilterManager implements ProtocolManager { * @param packetListeners - packet listeners that will receive this event. * @param event - the evnet to broadcast. */ - private void handlePacket(SortedPacketListenerList packetListeners, PacketEvent event) { + private void handlePacket(SortedPacketListenerList packetListeners, PacketEvent event, boolean sending) { // By default, asynchronous packets are queued for processing if (asyncFilterManager.hasAsynchronousListeners(event)) { @@ -319,7 +319,10 @@ public final class PacketFilterManager implements ProtocolManager { } // Process synchronous events - packetListeners.invokePacketRecieving(logger, event); + if (sending) + packetListeners.invokePacketSending(logger, event); + else + packetListeners.invokePacketRecieving(logger, event); // To cancel asynchronous processing, use the async marker if (!event.isCancelled() && !hasAsyncCancelled(event.getAsyncMarker())) { diff --git a/ProtocolLib/src/com/comphenix/protocol/injector/PlayerInjector.java b/ProtocolLib/src/com/comphenix/protocol/injector/PlayerInjector.java index b92fd3c0..2ae2976d 100644 --- a/ProtocolLib/src/com/comphenix/protocol/injector/PlayerInjector.java +++ b/ProtocolLib/src/com/comphenix/protocol/injector/PlayerInjector.java @@ -223,7 +223,7 @@ abstract class PlayerInjector { Integer id = MinecraftRegistry.getPacketToID().get(packet.getClass()); // Make sure we're listening - if (id != null && sendingFilters.contains(id)) { + if (id != null && sendingFilters.contains(id)) { // A packet has been sent guys! PacketContainer container = new PacketContainer(id, packet); PacketEvent event = PacketEvent.fromServer(manager, container, player); diff --git a/ProtocolLib/src/com/comphenix/protocol/injector/ReadPacketModifier.java b/ProtocolLib/src/com/comphenix/protocol/injector/ReadPacketModifier.java index d2e71c60..d5b84bbe 100644 --- a/ProtocolLib/src/com/comphenix/protocol/injector/ReadPacketModifier.java +++ b/ProtocolLib/src/com/comphenix/protocol/injector/ReadPacketModifier.java @@ -97,7 +97,7 @@ class ReadPacketModifier implements MethodInterceptor { // We need this in order to get the correct player DataInputStream input = (DataInputStream) args[0]; - + // Let the people know PacketContainer container = new PacketContainer(packetID, (Packet) thisObj); PacketEvent event = packetInjector.packetRecieved(container, input); diff --git a/ProtocolLib/src/com/comphenix/protocol/injector/SortedPacketListenerList.java b/ProtocolLib/src/com/comphenix/protocol/injector/SortedPacketListenerList.java index 27df4585..7ff8cddd 100644 --- a/ProtocolLib/src/com/comphenix/protocol/injector/SortedPacketListenerList.java +++ b/ProtocolLib/src/com/comphenix/protocol/injector/SortedPacketListenerList.java @@ -57,7 +57,7 @@ class SortedPacketListenerList extends AbstractConcurrentListenerMultimap { // Cache of previous types protected Map subtypeCache; + // Whether or subclasses should handle conversion + protected boolean customConvertHandling; + /** * Creates a structure modifier. * @param targetType - the structure to modify. @@ -125,7 +128,7 @@ public class StructureModifier { Object result = FieldUtils.readField(data.get(fieldIndex), target, true); // Use the converter, if we have it - if (converter != null) + if (needConversion()) return converter.getSpecific(result); else return (TField) result; @@ -164,7 +167,7 @@ public class StructureModifier { throw new IllegalStateException("Cannot write to a NULL target."); // Use the converter, if it exists - Object obj = converter != null ? converter.getGeneric(value) : value; + Object obj = needConversion() ? converter.getGeneric(value) : value; try { FieldUtils.writeField(data.get(fieldIndex), target, obj, true); @@ -176,6 +179,14 @@ public class StructureModifier { return this; } + /** + * Whether or not we should use the converter instance. + * @return TRUE if we should, FALSE otherwise. + */ + private final boolean needConversion() { + return converter != null && !customConvertHandling; + } + /** * Writes the value of a given field IF and ONLY if it exists. * @param fieldIndex - index of the potential field. @@ -362,7 +373,7 @@ public class StructureModifier { /** * Retrieves a structure modifier with the same type and target, but using a new object converter. - * @param converter- the object converter to use. + * @param converter - the object converter to use. * @return Structure modifier with the new converter. */ @SuppressWarnings("unchecked") diff --git a/ProtocolLib/src/com/comphenix/protocol/reflect/compiler/CompiledStructureModifier.java b/ProtocolLib/src/com/comphenix/protocol/reflect/compiler/CompiledStructureModifier.java index 5ddb19f8..d96236f7 100644 --- a/ProtocolLib/src/com/comphenix/protocol/reflect/compiler/CompiledStructureModifier.java +++ b/ProtocolLib/src/com/comphenix/protocol/reflect/compiler/CompiledStructureModifier.java @@ -13,10 +13,15 @@ import com.comphenix.protocol.reflect.instances.DefaultInstances; * @author Kristian * @param Field type. */ -public class CompiledStructureModifier extends StructureModifier { +public abstract class CompiledStructureModifier extends StructureModifier { // Used to compile instances of structure modifiers protected StructureCompiler compiler; + public CompiledStructureModifier() { + super(); + customConvertHandling = true; + } + // Speed up the default writer @SuppressWarnings("unchecked") @Override @@ -35,6 +40,29 @@ public class CompiledStructureModifier extends StructureModifier return this; } + @SuppressWarnings("unchecked") + @Override + public final TField read(int fieldIndex) throws FieldAccessException { + Object result = readGenerated(fieldIndex); + + if (converter != null) + return converter.getSpecific(result); + else + return (TField) result; + } + + protected abstract Object readGenerated(int fieldIndex) throws FieldAccessException; + + @SuppressWarnings("unchecked") + @Override + public StructureModifier write(int index, Object value) throws FieldAccessException { + if (converter != null) + value = converter.getGeneric((TField) value); + return writeGenerated(index, value); + } + + protected abstract StructureModifier writeGenerated(int index, Object value) throws FieldAccessException; + @Override public StructureModifier withTarget(Object target) { if (compiler != null) diff --git a/ProtocolLib/src/com/comphenix/protocol/reflect/compiler/StructureCompiler.java b/ProtocolLib/src/com/comphenix/protocol/reflect/compiler/StructureCompiler.java index 837aa778..24477dff 100644 --- a/ProtocolLib/src/com/comphenix/protocol/reflect/compiler/StructureCompiler.java +++ b/ProtocolLib/src/com/comphenix/protocol/reflect/compiler/StructureCompiler.java @@ -14,40 +14,39 @@ import com.google.common.base.Objects; import net.sf.cglib.asm.*; -// This class will automatically generate the following type of structure modifier: -// -// public class CompiledStructure$Packet20NamedEntitySpawnObject extends CompiledStructureModifier { +// public class CompiledStructureModifierPacket20 extends CompiledStructureModifier { // // private Packet20NamedEntitySpawn typedTarget; -// -// public CompiledStructure$Packet20NamedEntitySpawnObject(StructureModifier other, StructureCompiler compiler) { +// +// public CompiledStructureModifierPacket20(StructureModifier other, StructureCompiler compiler) { +// super(); // initialize(other); -// this.typedTarget = (Packet20NamedEntitySpawn) other.getTarget(); +// this.target = other.getTarget(); +// this.typedTarget = (Packet20NamedEntitySpawn) target; // this.compiler = compiler; // } // -// @SuppressWarnings("unchecked") // @Override -// public TField read(int fieldIndex) throws FieldAccessException { +// protected Object readGenerated(int fieldIndex) throws FieldAccessException { // // Packet20NamedEntitySpawn target = typedTarget; // // switch (fieldIndex) { -// case 0: return (TField) (Object) target.a; -// case 1: return (TField) (Object) target.b; -// case 2: return (TField) (Object) target.c; -// case 3: return (TField) (Object) target.d; -// case 4: return (TField) (Object) target.e; -// case 5: return (TField) (Object) target.f; -// case 6: return (TField) (Object) target.g; -// case 7: return (TField) (Object) target.h; +// case 0: return (Object) target.a; +// case 1: return (Object) target.b; +// case 2: return (Object) target.c; +// case 3: return super.read(fieldIndex); +// case 4: return super.read(fieldIndex); +// case 5: return (Object) target.f; +// case 6: return (Object) target.g; +// case 7: return (Object) target.h; // default: // throw new FieldAccessException("Invalid index " + fieldIndex); // } // } // // @Override -// public StructureModifier write(int index, Object value) { +// protected StructureModifier writeGenerated(int index, Object value) throws FieldAccessException { // // Packet20NamedEntitySpawn target = typedTarget; // @@ -56,8 +55,8 @@ import net.sf.cglib.asm.*; // case 1: target.b = (String) value; break; // case 2: target.c = (Integer) value; break; // case 3: target.d = (Integer) value; break; -// case 4: target.e = (Integer) value; break; -// case 5: target.f = (Byte) value; break; +// case 4: super.write(index, value); break; +// case 5: super.write(index, value); break; // case 6: target.g = (Byte) value; break; // case 7: target.h = (Integer) value; break; // default: @@ -265,7 +264,7 @@ public final class StructureCompiler { String methodDescriptor = "(ILjava/lang/Object;)L" + SUPER_CLASS + ";"; String methodSignature = "(ITTField;)L" + SUPER_CLASS + ";"; - MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, "write", methodDescriptor, methodSignature, + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PROTECTED, "writeGenerated", methodDescriptor, methodSignature, new String[] { FIELD_EXCEPTION_CLASS }); BoxingHelper boxingHelper = new BoxingHelper(mv); @@ -349,7 +348,7 @@ public final class StructureCompiler { } private void createReadMethod(ClassWriter cw, String className, List fields, String targetSignature, String targetName) { - MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, "read", "(I)Ljava/lang/Object;", "(I)TTField;", + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PROTECTED, "readGenerated", "(I)Ljava/lang/Object;", null, new String[] { "com/comphenix/protocol/reflect/FieldAccessException" }); BoxingHelper boxingHelper = new BoxingHelper(mv);