diff --git a/fml/src/main/java/net/minecraftforge/fml/common/asm/transformers/EventSubscriptionTransformer.java b/fml/src/main/java/net/minecraftforge/fml/common/asm/transformers/EventSubscriptionTransformer.java index 86a9f11db..6f2c1172b 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/asm/transformers/EventSubscriptionTransformer.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/asm/transformers/EventSubscriptionTransformer.java @@ -17,7 +17,10 @@ import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.NEW; import static org.objectweb.asm.Opcodes.PUTSTATIC; import static org.objectweb.asm.Opcodes.RETURN; +import static org.objectweb.asm.Opcodes.IRETURN; +import static org.objectweb.asm.Opcodes.ICONST_1; import static org.objectweb.asm.Type.VOID_TYPE; +import static org.objectweb.asm.Type.BOOLEAN_TYPE; import static org.objectweb.asm.Type.getMethodDescriptor; import java.util.List; @@ -28,6 +31,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldNode; @@ -81,56 +85,87 @@ public class EventSubscriptionTransformer implements IClassTransformer private boolean buildEvents(ClassNode classNode) throws Exception { + // Yes, this recursively loads classes until we get this base class. THIS IS NOT A ISSUE. Coremods should handle re-entry just fine. + // If they do not this a COREMOD issue NOT a Forge/LaunchWrapper issue. Class parent = this.getClass().getClassLoader().loadClass(classNode.superName.replace('/', '.')); if (!Event.class.isAssignableFrom(parent)) { return false; } - boolean hasSetup = false; - boolean hasGetListenerList = false; - boolean hasDefaultCtr = false; + //Class listenerListClazz = Class.forName("net.minecraftforge.fml.common.eventhandler.ListenerList", false, getClass().getClassLoader()); + Type tList = Type.getType("Lnet/minecraftforge/fml/common/eventhandler/ListenerList;"); - Class listenerListClazz = Class.forName("net.minecraftforge.fml.common.eventhandler.ListenerList", false, getClass().getClassLoader()); - Type tList = Type.getType(listenerListClazz); + boolean edited = false; + boolean hasSetup = false; + boolean hasGetListenerList = false; + boolean hasDefaultCtr = false; + boolean hasCancelable = false; + boolean hasResult = false; + String voidDesc = Type.getMethodDescriptor(VOID_TYPE); + String boolDesc = Type.getMethodDescriptor(BOOLEAN_TYPE); + String listDesc = tList.getDescriptor(); + String listDescM = Type.getMethodDescriptor(tList); for (MethodNode method : (List)classNode.methods) { - if (method.name.equals("setup") && - method.desc.equals(Type.getMethodDescriptor(VOID_TYPE)) && - (method.access & ACC_PROTECTED) == ACC_PROTECTED) + if (method.name.equals("setup") && method.desc.equals(voidDesc) && (method.access & ACC_PROTECTED) == ACC_PROTECTED) hasSetup = true; + if ((method.access & ACC_PUBLIC) == ACC_PUBLIC) + { + if (method.name.equals("getListenerList") && method.desc.equals(listDescM)) hasGetListenerList = true; + if (method.name.equals("isCancelable") && method.desc.equals(boolDesc)) hasCancelable = true; + if (method.name.equals("hasResult") && method.desc.equals(boolDesc)) hasResult = true; + } + if (method.name.equals("") && method.desc.equals(voidDesc)) hasDefaultCtr = true; + } + + if (classNode.visibleAnnotations != null) + { + for (AnnotationNode node : classNode.visibleAnnotations) + { + if (!hasResult && node.desc.equals("Lnet/minecraftforge/fml/common/eventhandler/Event$HasResult;")) { - hasSetup = true; + /* Add: + * public boolean hasResult() + * { + * return true; + * } + */ + MethodNode method = new MethodNode(ACC_PUBLIC, "hasResult", boolDesc, null, null); + method.instructions.add(new InsnNode(ICONST_1)); + method.instructions.add(new InsnNode(IRETURN)); + classNode.methods.add(method); + edited = true; } - if (method.name.equals("getListenerList") && - method.desc.equals(Type.getMethodDescriptor(tList)) && - (method.access & ACC_PUBLIC) == ACC_PUBLIC) + else if (!hasCancelable && node.desc.equals("Lnet/minecraftforge/fml/common/eventhandler/Cancelable;")) { - hasGetListenerList = true; - } - if (method.name.equals("") && - method.desc.equals(Type.getMethodDescriptor(VOID_TYPE))) - { - hasDefaultCtr = true; + /* Add: + * public boolean isCancelable() + * { + * return true; + * } + */ + MethodNode method = new MethodNode(ACC_PUBLIC, "isCancelable", boolDesc, null, null); + method.instructions.add(new InsnNode(ICONST_1)); + method.instructions.add(new InsnNode(IRETURN)); + classNode.methods.add(method); + edited = true; } + } } if (hasSetup) { - if (!hasGetListenerList) - { - throw new RuntimeException("Event class defines setup() but does not define getListenerList! " + classNode.name); - } - else - { - return false; - } + if (!hasGetListenerList) + throw new RuntimeException("Event class defines setup() but does not define getListenerList! " + classNode.name); + else + return edited; } Type tSuper = Type.getType(classNode.superName); //Add private static ListenerList LISTENER_LIST - classNode.fields.add(new FieldNode(ACC_PRIVATE | ACC_STATIC, "LISTENER_LIST", tList.getDescriptor(), null, null)); + classNode.fields.add(new FieldNode(ACC_PRIVATE | ACC_STATIC, "LISTENER_LIST", listDesc, null, null)); /*Add: * public () @@ -138,12 +173,12 @@ public class EventSubscriptionTransformer implements IClassTransformer * super(); * } */ - MethodNode method = new MethodNode(ASM5, ACC_PUBLIC, "", getMethodDescriptor(VOID_TYPE), null, null); - method.instructions.add(new VarInsnNode(ALOAD, 0)); - method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "", getMethodDescriptor(VOID_TYPE), false)); - method.instructions.add(new InsnNode(RETURN)); if (!hasDefaultCtr) { + MethodNode method = new MethodNode(ACC_PUBLIC, "", voidDesc, null, null); + method.instructions.add(new VarInsnNode(ALOAD, 0)); + method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "", voidDesc, false)); + method.instructions.add(new InsnNode(RETURN)); classNode.methods.add(method); } @@ -158,10 +193,10 @@ public class EventSubscriptionTransformer implements IClassTransformer * LISTENER_LIST = new ListenerList(super.getListenerList()); * } */ - method = new MethodNode(ASM5, ACC_PROTECTED, "setup", getMethodDescriptor(VOID_TYPE), null, null); + MethodNode method = new MethodNode(ACC_PROTECTED, "setup", voidDesc, null, null); method.instructions.add(new VarInsnNode(ALOAD, 0)); - method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "setup", getMethodDescriptor(VOID_TYPE), false)); - method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", tList.getDescriptor())); + method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "setup", voidDesc, false)); + method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", listDesc)); LabelNode initLisitener = new LabelNode(); method.instructions.add(new JumpInsnNode(IFNULL, initLisitener)); method.instructions.add(new InsnNode(RETURN)); @@ -170,9 +205,9 @@ public class EventSubscriptionTransformer implements IClassTransformer method.instructions.add(new TypeInsnNode(NEW, tList.getInternalName())); method.instructions.add(new InsnNode(DUP)); method.instructions.add(new VarInsnNode(ALOAD, 0)); - method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "getListenerList", getMethodDescriptor(tList), false)); + method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "getListenerList", listDescM, false)); method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tList.getInternalName(), "", getMethodDescriptor(VOID_TYPE, tList), false)); - method.instructions.add(new FieldInsnNode(PUTSTATIC, classNode.name, "LISTENER_LIST", tList.getDescriptor())); + method.instructions.add(new FieldInsnNode(PUTSTATIC, classNode.name, "LISTENER_LIST", listDesc)); method.instructions.add(new InsnNode(RETURN)); classNode.methods.add(method); @@ -182,8 +217,8 @@ public class EventSubscriptionTransformer implements IClassTransformer * return this.LISTENER_LIST; * } */ - method = new MethodNode(ASM5, ACC_PUBLIC, "getListenerList", getMethodDescriptor(tList), null, null); - method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", tList.getDescriptor())); + method = new MethodNode(ACC_PUBLIC, "getListenerList", listDescM, null, null); + method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", listDesc)); method.instructions.add(new InsnNode(ARETURN)); classNode.methods.add(method); return true; diff --git a/fml/src/main/java/net/minecraftforge/fml/common/eventhandler/Event.java b/fml/src/main/java/net/minecraftforge/fml/common/eventhandler/Event.java index a1a60df07..e02f9f629 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/eventhandler/Event.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/eventhandler/Event.java @@ -32,9 +32,7 @@ public class Event } private boolean isCanceled = false; - private final boolean isCancelable; private Result result = Result.DEFAULT; - private final boolean hasResult; private static ListenerList listeners = new ListenerList(); private EventPriority phase = null; @@ -43,48 +41,18 @@ public class Event public Event() { setup(); - isCancelable = hasAnnotation(Cancelable.class); - hasResult = hasAnnotation(HasResult.class); - } - - private boolean hasAnnotation(Class annotation) - { - Class me = this.getClass(); - Map, Boolean> list = annotationMap.get(me); - if (list == null) - { - list = new ConcurrentHashMap, Boolean>(); - annotationMap.put(me, list); - } - - Boolean cached = list.get(annotation); - if (cached != null) - { - return cached; - } - - Class cls = me; - while (cls != Event.class) - { - if (cls.isAnnotationPresent(annotation)) - { - list.put(annotation, true); - return true; - } - cls = cls.getSuperclass(); - } - - list.put(annotation, false); - return false; } /** * Determine if this function is cancelable at all. * @return If access to setCanceled should be allowed + * + * Note: + * Events with the Cancelable annotation will have this method automatically added to return true. */ public boolean isCancelable() { - return isCancelable; + return false; } /** @@ -115,10 +83,13 @@ public class Event /** * Determines if this event expects a significant result value. + * + * Note: + * Events with the HasResult annotation will have this method automatically added to return true. */ public boolean hasResult() { - return hasResult; + return false; } /**