Ensure that the compiled structures respect the converter field.

In addition, fixed a bug that prevented client listeners from
receiving any packets.
This commit is contained in:
Kristian S. Stangeland 2012-10-01 02:17:13 +02:00
parent 46d9a6e975
commit c2b4b5fce3
8 changed files with 75 additions and 32 deletions

View File

@ -148,6 +148,8 @@ public class PacketEvent extends EventObject implements Cancellable {
/** /**
* Whether or not this packet was created by the server. * Whether or not this packet was created by the server.
* <p>
* 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. * @return TRUE if the packet was created by the server, FALSE if it was created by a client.
*/ */
public boolean isServerPacket() { public boolean isServerPacket() {

View File

@ -293,7 +293,7 @@ public final class PacketFilterManager implements ProtocolManager {
* @param event - the packet event to invoke. * @param event - the packet event to invoke.
*/ */
public void invokePacketRecieving(PacketEvent event) { 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. * @param event - the packet event to invoke.
*/ */
public void invokePacketSending(PacketEvent event) { 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 packetListeners - packet listeners that will receive this event.
* @param event - the evnet to broadcast. * @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 // By default, asynchronous packets are queued for processing
if (asyncFilterManager.hasAsynchronousListeners(event)) { if (asyncFilterManager.hasAsynchronousListeners(event)) {
@ -319,7 +319,10 @@ public final class PacketFilterManager implements ProtocolManager {
} }
// Process synchronous events // 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 // To cancel asynchronous processing, use the async marker
if (!event.isCancelled() && !hasAsyncCancelled(event.getAsyncMarker())) { if (!event.isCancelled() && !hasAsyncCancelled(event.getAsyncMarker())) {

View File

@ -57,7 +57,7 @@ class SortedPacketListenerList extends AbstractConcurrentListenerMultimap<Packet
} catch (Throwable e) { } catch (Throwable e) {
// Minecraft doesn't want your Exception. // Minecraft doesn't want your Exception.
logger.log(Level.SEVERE, logger.log(Level.SEVERE,
"Exception occured in onPacketReceiving() for " + "Exception occured in onPacketSending() for " +
PacketAdapter.getPluginName(element.getListener()), e); PacketAdapter.getPluginName(element.getListener()), e);
} }
} }

View File

@ -58,6 +58,9 @@ public class StructureModifier<TField> {
// Cache of previous types // Cache of previous types
protected Map<Class, StructureModifier> subtypeCache; protected Map<Class, StructureModifier> subtypeCache;
// Whether or subclasses should handle conversion
protected boolean customConvertHandling;
/** /**
* Creates a structure modifier. * Creates a structure modifier.
* @param targetType - the structure to modify. * @param targetType - the structure to modify.
@ -125,7 +128,7 @@ public class StructureModifier<TField> {
Object result = FieldUtils.readField(data.get(fieldIndex), target, true); Object result = FieldUtils.readField(data.get(fieldIndex), target, true);
// Use the converter, if we have it // Use the converter, if we have it
if (converter != null) if (needConversion())
return converter.getSpecific(result); return converter.getSpecific(result);
else else
return (TField) result; return (TField) result;
@ -164,7 +167,7 @@ public class StructureModifier<TField> {
throw new IllegalStateException("Cannot write to a NULL target."); throw new IllegalStateException("Cannot write to a NULL target.");
// Use the converter, if it exists // Use the converter, if it exists
Object obj = converter != null ? converter.getGeneric(value) : value; Object obj = needConversion() ? converter.getGeneric(value) : value;
try { try {
FieldUtils.writeField(data.get(fieldIndex), target, obj, true); FieldUtils.writeField(data.get(fieldIndex), target, obj, true);
@ -176,6 +179,14 @@ public class StructureModifier<TField> {
return this; 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. * Writes the value of a given field IF and ONLY if it exists.
* @param fieldIndex - index of the potential field. * @param fieldIndex - index of the potential field.
@ -362,7 +373,7 @@ public class StructureModifier<TField> {
/** /**
* Retrieves a structure modifier with the same type and target, but using a new object converter. * 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. * @return Structure modifier with the new converter.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -13,10 +13,15 @@ import com.comphenix.protocol.reflect.instances.DefaultInstances;
* @author Kristian * @author Kristian
* @param <TField> Field type. * @param <TField> Field type.
*/ */
public class CompiledStructureModifier<TField> extends StructureModifier<TField> { public abstract class CompiledStructureModifier<TField> extends StructureModifier<TField> {
// Used to compile instances of structure modifiers // Used to compile instances of structure modifiers
protected StructureCompiler compiler; protected StructureCompiler compiler;
public CompiledStructureModifier() {
super();
customConvertHandling = true;
}
// Speed up the default writer // Speed up the default writer
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
@ -35,6 +40,29 @@ public class CompiledStructureModifier<TField> extends StructureModifier<TField>
return this; 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<TField> write(int index, Object value) throws FieldAccessException {
if (converter != null)
value = converter.getGeneric((TField) value);
return writeGenerated(index, value);
}
protected abstract StructureModifier<TField> writeGenerated(int index, Object value) throws FieldAccessException;
@Override @Override
public StructureModifier<TField> withTarget(Object target) { public StructureModifier<TField> withTarget(Object target) {
if (compiler != null) if (compiler != null)

View File

@ -14,40 +14,39 @@ import com.google.common.base.Objects;
import net.sf.cglib.asm.*; import net.sf.cglib.asm.*;
// This class will automatically generate the following type of structure modifier: // public class CompiledStructureModifierPacket20<TField> extends CompiledStructureModifier<TField> {
//
// public class CompiledStructure$Packet20NamedEntitySpawnObject<TField> extends CompiledStructureModifier<TField> {
// //
// private Packet20NamedEntitySpawn typedTarget; // private Packet20NamedEntitySpawn typedTarget;
// //
// public CompiledStructure$Packet20NamedEntitySpawnObject(StructureModifier<TField> other, StructureCompiler compiler) { // public CompiledStructureModifierPacket20(StructureModifier<TField> other, StructureCompiler compiler) {
// super();
// initialize(other); // initialize(other);
// this.typedTarget = (Packet20NamedEntitySpawn) other.getTarget(); // this.target = other.getTarget();
// this.typedTarget = (Packet20NamedEntitySpawn) target;
// this.compiler = compiler; // this.compiler = compiler;
// } // }
// //
// @SuppressWarnings("unchecked")
// @Override // @Override
// public TField read(int fieldIndex) throws FieldAccessException { // protected Object readGenerated(int fieldIndex) throws FieldAccessException {
// //
// Packet20NamedEntitySpawn target = typedTarget; // Packet20NamedEntitySpawn target = typedTarget;
// //
// switch (fieldIndex) { // switch (fieldIndex) {
// case 0: return (TField) (Object) target.a; // case 0: return (Object) target.a;
// case 1: return (TField) (Object) target.b; // case 1: return (Object) target.b;
// case 2: return (TField) (Object) target.c; // case 2: return (Object) target.c;
// case 3: return (TField) (Object) target.d; // case 3: return super.read(fieldIndex);
// case 4: return (TField) (Object) target.e; // case 4: return super.read(fieldIndex);
// case 5: return (TField) (Object) target.f; // case 5: return (Object) target.f;
// case 6: return (TField) (Object) target.g; // case 6: return (Object) target.g;
// case 7: return (TField) (Object) target.h; // case 7: return (Object) target.h;
// default: // default:
// throw new FieldAccessException("Invalid index " + fieldIndex); // throw new FieldAccessException("Invalid index " + fieldIndex);
// } // }
// } // }
// //
// @Override // @Override
// public StructureModifier<TField> write(int index, Object value) { // protected StructureModifier<TField> writeGenerated(int index, Object value) throws FieldAccessException {
// //
// Packet20NamedEntitySpawn target = typedTarget; // Packet20NamedEntitySpawn target = typedTarget;
// //
@ -56,8 +55,8 @@ import net.sf.cglib.asm.*;
// case 1: target.b = (String) value; break; // case 1: target.b = (String) value; break;
// case 2: target.c = (Integer) value; break; // case 2: target.c = (Integer) value; break;
// case 3: target.d = (Integer) value; break; // case 3: target.d = (Integer) value; break;
// case 4: target.e = (Integer) value; break; // case 4: super.write(index, value); break;
// case 5: target.f = (Byte) value; break; // case 5: super.write(index, value); break;
// case 6: target.g = (Byte) value; break; // case 6: target.g = (Byte) value; break;
// case 7: target.h = (Integer) value; break; // case 7: target.h = (Integer) value; break;
// default: // default:
@ -265,7 +264,7 @@ public final class StructureCompiler {
String methodDescriptor = "(ILjava/lang/Object;)L" + SUPER_CLASS + ";"; String methodDescriptor = "(ILjava/lang/Object;)L" + SUPER_CLASS + ";";
String methodSignature = "(ITTField;)L" + SUPER_CLASS + "<TTField;>;"; String methodSignature = "(ITTField;)L" + SUPER_CLASS + "<TTField;>;";
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 }); new String[] { FIELD_EXCEPTION_CLASS });
BoxingHelper boxingHelper = new BoxingHelper(mv); BoxingHelper boxingHelper = new BoxingHelper(mv);
@ -349,7 +348,7 @@ public final class StructureCompiler {
} }
private void createReadMethod(ClassWriter cw, String className, List<Field> fields, String targetSignature, String targetName) { private void createReadMethod(ClassWriter cw, String className, List<Field> 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" }); new String[] { "com/comphenix/protocol/reflect/FieldAccessException" });
BoxingHelper boxingHelper = new BoxingHelper(mv); BoxingHelper boxingHelper = new BoxingHelper(mv);