Commit fba0e0ffc742dfd2c78a379dcdc7097c3cef12a2

Authored by Mumfrey
1 parent 0ec79e75

adding AccessorTransformer and replacing MinecraftOverlay with accessor injection

debug/obfuscation.properties
1 1 field_71424_I=mcProfiler
2   -field_78729_o=entityRenderMap field_110546_b=reloadListeners
  2 +field_78729_o=entityRenderMap
  3 +field_110546_b=reloadListeners
3 4 field_147393_d=networkManager
4   -field_82596_a=registryObjects field_148759_a=underlyingIntegerMap field_148749_a=identityMap
5   -field_148748_b=objectList field_147559_m=mapSpecialRenderers
  5 +field_82596_a=registryObjects
  6 +field_148759_a=underlyingIntegerMap
  7 +field_148749_a=identityMap
  8 +field_148748_b=objectList
  9 +field_147559_m=mapSpecialRenderers
6 10 field_145855_i=nameToClassMap
7   -field_145853_j=classToNameMap func_148833_a=processPacket func_71411_J=runGameLoop func_71407_l=runTick func_78480_b=updateCameraAndRender
8   -func_78471_a=renderWorld func_175180_a=renderGameOverlay func_76320_a=startSection
  11 +field_145853_j=classToNameMap
  12 +field_71428_T=timer
  13 +field_71424_I=mcProfiler
  14 +field_71425_J=running
  15 +field_110449_ao=defaultResourcePacks
  16 +field_71475_ae=serverName
  17 +field_71477_af=serverPort
  18 +func_148833_a=processPacket
  19 +func_71411_J=runGameLoop
  20 +func_71407_l=runTick
  21 +func_78480_b=updateCameraAndRender
  22 +func_78471_a=renderWorld
  23 +func_175180_a=renderGameOverlay
  24 +func_76320_a=startSection
9 25 func_76319_b=endSection
10 26 func_76318_c=endStartSection
11 27 func_148545_a=createPlayerForUser
... ... @@ -28,4 +44,5 @@ func_148256_e=getProfile
28 44 func_148260_a=saveScreenshot
29 45 func_148822_b=isFramebufferEnabled
30 46 func_147939_a=doRenderEntity
31   -func_76986_a=doRender
32 47 \ No newline at end of file
  48 +func_76986_a=doRender
  49 +func_71370_a=resize
33 50 \ No newline at end of file
... ...
java/client/com/mumfrey/liteloader/client/api/LiteLoaderCoreAPIClient.java
... ... @@ -35,7 +35,7 @@ public class LiteLoaderCoreAPIClient extends LiteLoaderCoreAPI
35 35 private static final String[] requiredDownstreamTransformers = {
36 36 LiteLoaderCoreAPI.PKG_LITELOADER_COMMON + ".transformers.LiteLoaderPacketTransformer",
37 37 LiteLoaderCoreAPIClient.PKG_LITELOADER_CLIENT + ".transformers.LiteLoaderEventInjectionTransformer",
38   - LiteLoaderCoreAPIClient.PKG_LITELOADER_CLIENT + ".transformers.MinecraftOverlayTransformer",
  38 + LiteLoaderCoreAPIClient.PKG_LITELOADER_CLIENT + ".transformers.MinecraftTransformer",
39 39 LiteLoaderCoreAPI.PKG_LITELOADER + ".transformers.event.json.ModEventInjectionTransformer"
40 40 };
41 41  
... ...
java/client/com/mumfrey/liteloader/client/overlays/IMinecraft.java
... ... @@ -5,43 +5,56 @@ import java.util.List;
5 5 import net.minecraft.client.resources.IResourcePack;
6 6 import net.minecraft.util.Timer;
7 7  
  8 +import com.mumfrey.liteloader.core.runtime.Obf;
  9 +import com.mumfrey.liteloader.transformers.access.Accessor;
  10 +import com.mumfrey.liteloader.transformers.access.Invoker;
  11 +import com.mumfrey.liteloader.transformers.access.ObfTableClass;
  12 +
8 13 /**
9   - * Interface containing injected accessors which are provided by MinecraftOverlay
  14 + * Interface containing injected accessors for Minecraft
10 15 *
11 16 * @author Adam Mummery-Smith
12 17 */
  18 +@ObfTableClass(Obf.class)
  19 +@Accessor("Minecraft")
13 20 public interface IMinecraft
14 21 {
15 22 /**
16 23 * Get the timer instance
17 24 */
  25 + @Accessor("timer")
18 26 public abstract Timer getTimer();
19 27  
20 28 /**
21 29 * Get the "running" flag
22 30 */
  31 + @Accessor("running")
23 32 public abstract boolean isRunning();
24 33  
25 34 /**
26 35 * Get the default resource packs set
27 36 */
  37 + @Accessor("defaultResourcePacks")
28 38 public abstract List<IResourcePack> getDefaultResourcePacks();
29   -
30   - /**
31   - * Resize the window
32   - *
33   - * @param width
34   - * @param height
35   - */
36   - public abstract void setSize(int width, int height);
37 39  
38 40 /**
39 41 * Get the current server address (from connection)
40 42 */
  43 + @Accessor("serverName")
41 44 public abstract String getServerName();
42 45  
43 46 /**
44 47 * Get the current server port (from connection)
45 48 */
  49 + @Accessor("serverPort")
46 50 public abstract int getServerPort();
  51 +
  52 + /**
  53 + * Notify the client that the window was resized
  54 + *
  55 + * @param width
  56 + * @param height
  57 + */
  58 + @Invoker("resize")
  59 + public abstract void onResizeWindow(int width, int height);
47 60 }
... ...
java/client/com/mumfrey/liteloader/client/overlays/MinecraftOverlay.java deleted 100644 โ†’ 0
1   -package com.mumfrey.liteloader.client.overlays;
2   -
3   -import java.util.List;
4   -
5   -import org.lwjgl.LWJGLException;
6   -import org.lwjgl.opengl.Display;
7   -import org.lwjgl.opengl.DisplayMode;
8   -
9   -import net.minecraft.client.Minecraft;
10   -import net.minecraft.client.resources.IResourcePack;
11   -import net.minecraft.profiler.Profiler;
12   -import net.minecraft.util.Timer;
13   -
14   -import com.google.common.collect.Lists;
15   -import com.mumfrey.liteloader.transformers.Obfuscated;
16   -import com.mumfrey.liteloader.transformers.Stub;
17   -
18   -/**
19   - * Overlay to inject accessors into Minecraft main class
20   - *
21   - * @author Adam Mummery-Smith
22   - */
23   -public abstract class MinecraftOverlay implements IMinecraft
24   -{
25   - @SuppressWarnings("unused")
26   - private static Minecraft __TARGET;
27   -
28   - // TODO Obfuscation 1.8
29   - // Fields
30   - @Obfuscated({"field_71428_T", "U"}) private Timer timer;
31   - @Obfuscated({"field_71424_I", "y"}) private Profiler mcProfiler;
32   - @Obfuscated({"field_71425_J", "z"}) private boolean running;
33   - @Obfuscated({"field_110449_ao", "aw"}) private List<?> defaultResourcePacks = Lists.newArrayList();
34   - @Obfuscated({"field_71475_ae", "am"}) private String serverName;
35   - @Obfuscated({"field_71477_af", "an"}) private int serverPort;
36   -
37   - // Methods
38   - @Obfuscated({"func_71370_a", "a"}) @Stub abstract void resize(int width, int height);
39   -
40   - /* (non-Javadoc)
41   - * @see com.mumfrey.liteloader.client.overlays.IMinecraft#getTimer()
42   - */
43   - @Override
44   - public Timer getTimer()
45   - {
46   - return this.timer;
47   - }
48   -
49   - /* (non-Javadoc)
50   - * @see com.mumfrey.liteloader.client.overlays.IMinecraft#isRunning()
51   - */
52   - @Override
53   - public boolean isRunning()
54   - {
55   - return this.running;
56   - }
57   -
58   - /* (non-Javadoc)
59   - * @see com.mumfrey.liteloader.client.overlays.IMinecraft#getDefaultResourcePacks()
60   - */
61   - @Override
62   - @SuppressWarnings("unchecked")
63   - public List<IResourcePack> getDefaultResourcePacks()
64   - {
65   - return (List<IResourcePack>)this.defaultResourcePacks;
66   - }
67   -
68   - /* (non-Javadoc)
69   - * @see com.mumfrey.liteloader.client.overlays.IMinecraft#setSize(int, int)
70   - */
71   - @Override
72   - public void setSize(int width, int height)
73   - {
74   - try
75   - {
76   - Display.setDisplayMode(new DisplayMode(width, height));
77   - this.resize(width, height);
78   - Display.setVSyncEnabled(Minecraft.getMinecraft().gameSettings.enableVsync);
79   - }
80   - catch (LWJGLException ex)
81   - {
82   - ex.printStackTrace();
83   - }
84   - }
85   -
86   - /* (non-Javadoc)
87   - * @see com.mumfrey.liteloader.client.overlays.IMinecraft#getServerName()
88   - */
89   - @Override
90   - public String getServerName()
91   - {
92   - return this.serverName;
93   - }
94   -
95   - /* (non-Javadoc)
96   - * @see com.mumfrey.liteloader.client.overlays.IMinecraft#getServerPort()
97   - */
98   - @Override
99   - public int getServerPort()
100   - {
101   - return this.serverPort;
102   - }
103   -}
java/client/com/mumfrey/liteloader/client/transformers/MinecraftOverlayTransformer.java renamed to java/client/com/mumfrey/liteloader/client/transformers/MinecraftTransformer.java
... ... @@ -13,30 +13,25 @@ import org.objectweb.asm.tree.TypeInsnNode;
13 13  
14 14 import com.mumfrey.liteloader.core.runtime.Obf;
15 15 import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
16   -import com.mumfrey.liteloader.transformers.ClassOverlayTransformer;
  16 +import com.mumfrey.liteloader.transformers.access.AccessorTransformer;
17 17 import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
18 18  
19   -public class MinecraftOverlayTransformer extends ClassOverlayTransformer
  19 +public class MinecraftTransformer extends AccessorTransformer
20 20 {
21   - private static final String overlayClassName = "com.mumfrey.liteloader.client.overlays.MinecraftOverlay";
  21 + private static final String TWEAKCLASS = LiteLoaderTweaker.class.getName().replace('.', '/');
22 22  
23   - private static final String LITELOADER_TWEAKER_CLASS = LiteLoaderTweaker.class.getName().replace('.', '/');
24   -
25   - private static final String METHOD_INIT = "init";
26   - private static final String METHOD_POSTINIT = "postInit";
27   -
28   - public MinecraftOverlayTransformer()
  23 + @Override
  24 + protected void addAccessors()
29 25 {
30   - super(MinecraftOverlayTransformer.overlayClassName);
31   - this.setSourceFile = false;
  26 + this.addAccessor(Obf.IMinecraft.name);
32 27 }
33 28  
34 29 @Override
35   - protected void postOverlayTransform(String transformedName, ClassNode targetClass, ClassNode overlayClass)
  30 + protected void postTransform(String name, String transformedName, ClassNode classNode)
36 31 {
37 32 if ((Obf.Minecraft.name.equals(transformedName) || Obf.Minecraft.obf.equals(transformedName)))
38 33 {
39   - for (MethodNode method : targetClass.methods)
  34 + for (MethodNode method : classNode.methods)
40 35 {
41 36 if (Obf.startGame.obf.equals(method.name) || Obf.startGame.srg.equals(method.name) || Obf.startGame.name.equals(method.name))
42 37 {
... ... @@ -63,11 +58,11 @@ public class MinecraftOverlayTransformer extends ClassOverlayTransformer
63 58 TypeInsnNode typeNode = (TypeInsnNode)insn;
64 59 if (!found && (Obf.EntityRenderer.obf.equals(typeNode.desc) || Obf.EntityRenderer.ref.equals(typeNode.desc)))
65 60 {
66   - LiteLoaderLogger.info("MinecraftOverlayTransformer found INIT injection point, this is good.");
  61 + LiteLoaderLogger.info("MinecraftTransformer found INIT injection point, this is good.");
67 62 found = true;
68 63  
69   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftOverlayTransformer.LITELOADER_TWEAKER_CLASS, MinecraftOverlayTransformer.METHOD_INIT, "()V", false));
70   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftOverlayTransformer.LITELOADER_TWEAKER_CLASS, MinecraftOverlayTransformer.METHOD_POSTINIT, "()V", false));
  64 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftTransformer.TWEAKCLASS, Obf.init.name, "()V", false));
  65 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftTransformer.TWEAKCLASS, Obf.postInit.name, "()V", false));
71 66 }
72 67 }
73 68  
... ... @@ -88,6 +83,6 @@ public class MinecraftOverlayTransformer extends ClassOverlayTransformer
88 83  
89 84 method.instructions = insns;
90 85  
91   - if (!found) LiteLoaderLogger.severe("MinecraftOverlayTransformer failed to find the INIT injection point, the game will probably crash pretty soon.");
  86 + if (!found) LiteLoaderLogger.severe("MinecraftTransformer failed to find the INIT injection point, the game will probably crash pretty soon.");
92 87 }
93 88 }
... ...
java/client/com/mumfrey/liteloader/util/ModUtilities.java
... ... @@ -6,6 +6,10 @@ import java.util.IdentityHashMap;
6 6 import java.util.List;
7 7 import java.util.Map;
8 8  
  9 +import org.lwjgl.LWJGLException;
  10 +import org.lwjgl.opengl.Display;
  11 +import org.lwjgl.opengl.DisplayMode;
  12 +
9 13 import net.minecraft.block.Block;
10 14 import net.minecraft.client.Minecraft;
11 15 import net.minecraft.client.renderer.Tessellator;
... ... @@ -25,6 +29,7 @@ import net.minecraft.util.RegistryNamespaced;
25 29 import net.minecraft.util.RegistrySimple;
26 30 import net.minecraft.util.ResourceLocation;
27 31  
  32 +import com.mumfrey.liteloader.client.overlays.IMinecraft;
28 33 import com.mumfrey.liteloader.client.util.PrivateFields;
29 34 import com.mumfrey.liteloader.core.runtime.Obf;
30 35 import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
... ... @@ -74,6 +79,21 @@ public abstract class ModUtilities
74 79 return false;
75 80 }
76 81  
  82 + public static void setWindowSize(int width, int height)
  83 + {
  84 + try
  85 + {
  86 + Minecraft mc = Minecraft.getMinecraft();
  87 + Display.setDisplayMode(new DisplayMode(width, height));
  88 + ((IMinecraft)mc).onResizeWindow(width, height);
  89 + Display.setVSyncEnabled(mc.gameSettings.enableVsync);
  90 + }
  91 + catch (LWJGLException ex)
  92 + {
  93 + ex.printStackTrace();
  94 + }
  95 + }
  96 +
77 97 /**
78 98 * Add a renderer map entry for the specified entity class
79 99 *
... ...
java/common/com/mumfrey/liteloader/core/runtime/Obf.java
... ... @@ -25,11 +25,14 @@ public class Obf
25 25 public static final Obf PacketEvents = new Obf("com.mumfrey.liteloader.core.PacketEvents" );
26 26 public static final Obf PacketEventsClient = new Obf("com.mumfrey.liteloader.client.PacketEventsClient" );
27 27 public static final Obf LoadingBar = new Obf("com.mumfrey.liteloader.client.gui.startup.LoadingBar" );
  28 + public static final Obf IMinecraft = new Obf("com.mumfrey.liteloader.client.overlays.IMinecraft" );
28 29 public static final Obf GameProfile = new Obf("com.mojang.authlib.GameProfile" );
29 30 public static final Obf MinecraftMain = new Obf("net.minecraft.client.main.Main" );
30 31 public static final Obf MinecraftServer = new Obf("net.minecraft.server.MinecraftServer" );
31 32 public static final Obf GL11 = new Obf("org.lwjgl.opengl.GL11" );
32 33 public static final Obf RealmsMainScreen = new Obf("com.mojang.realmsclient.RealmsMainScreen" );
  34 + public static final Obf init = new Obf("init" );
  35 + public static final Obf postInit = new Obf("postInit" );
33 36 public static final Obf constructor = new Obf("<init>" );
34 37  
35 38 // Classes
... ... @@ -73,6 +76,12 @@ public class Obf
73 76 public static final Obf mapSpecialRenderers = new Obf("field_147559_m", "m" );
74 77 public static final Obf tileEntityNameToClassMap = new Obf("field_145855_i", "f" );
75 78 public static final Obf tileEntityClassToNameMap = new Obf("field_145853_j", "g" );
  79 + public static final Obf timer = new Obf("field_71428_T", "U" );
  80 + public static final Obf mcProfiler = new Obf("field_71424_I", "y" );
  81 + public static final Obf running = new Obf("field_71425_J", "z" );
  82 + public static final Obf defaultResourcePacks = new Obf("field_110449_ao", "aw" );
  83 + public static final Obf serverName = new Obf("field_71475_ae", "am" );
  84 + public static final Obf serverPort = new Obf("field_71477_af", "an" );
76 85  
77 86 // Methods
78 87 // -----------------------------------------------------------------------------------------
... ... @@ -107,6 +116,7 @@ public class Obf
107 116 public static final Obf doRenderEntity = new Obf("func_147939_a", "a" );
108 117 public static final Obf doRender = new Obf("func_76986_a", "a" );
109 118 public static final Obf doRenderShadowAndFire = new Obf("func_76979_b", "b" );
  119 + public static final Obf resize = new Obf("func_71370_a", "a" );
110 120  
111 121 public static final int MCP = 0;
112 122 public static final int SRG = 1;
... ... @@ -239,4 +249,24 @@ public class Obf
239 249 {
240 250 return Obf.obfs.get(name);
241 251 }
  252 +
  253 + public static Obf getByName(Class<? extends Obf> obf, String name)
  254 + {
  255 + try
  256 + {
  257 + for (Field fd : obf.getFields())
  258 + {
  259 + if (fd.getType().equals(Obf.class))
  260 + {
  261 + String fieldName = fd.getName();
  262 + Obf entry = (Obf)fd.get(null);
  263 + if (name.equals(fieldName) || name.equals(entry.name))
  264 + return entry;
  265 + }
  266 + }
  267 + }
  268 + catch (Exception ex) {}
  269 +
  270 + return Obf.getByName(name);
  271 + }
242 272 }
... ...
java/common/com/mumfrey/liteloader/transformers/ByteCodeUtilities.java
1 1 package com.mumfrey.liteloader.transformers;
2 2  
  3 +import java.io.IOException;
3 4 import java.lang.annotation.Annotation;
4 5 import java.util.ArrayList;
5 6 import java.util.HashMap;
... ... @@ -7,6 +8,10 @@ import java.util.Iterator;
7 8 import java.util.List;
8 9 import java.util.Map;
9 10  
  11 +import net.minecraft.launchwrapper.IClassTransformer;
  12 +import net.minecraft.launchwrapper.Launch;
  13 +
  14 +import org.objectweb.asm.ClassReader;
10 15 import org.objectweb.asm.Opcodes;
11 16 import org.objectweb.asm.Type;
12 17 import org.objectweb.asm.tree.*;
... ... @@ -476,7 +481,7 @@ public abstract class ByteCodeUtilities
476 481 return target;
477 482 }
478 483  
479   - AnnotationNode obfuscatedAnnotation = ByteCodeUtilities.getAnnotation(searchFor, Obfuscated.class);
  484 + AnnotationNode obfuscatedAnnotation = ByteCodeUtilities.getVisibleAnnotation(searchFor, Obfuscated.class);
480 485 if (obfuscatedAnnotation != null)
481 486 {
482 487 for (String obfuscatedName : ByteCodeUtilities.<List<String>>getAnnotationValue(obfuscatedAnnotation))
... ... @@ -506,7 +511,7 @@ public abstract class ByteCodeUtilities
506 511 return target;
507 512 }
508 513  
509   - AnnotationNode obfuscatedAnnotation = ByteCodeUtilities.getAnnotation(searchFor, Obfuscated.class);
  514 + AnnotationNode obfuscatedAnnotation = ByteCodeUtilities.getVisibleAnnotation(searchFor, Obfuscated.class);
510 515 if (obfuscatedAnnotation != null)
511 516 {
512 517 for (String obfuscatedName : ByteCodeUtilities.<List<String>>getAnnotationValue(obfuscatedAnnotation))
... ... @@ -521,24 +526,111 @@ public abstract class ByteCodeUtilities
521 526  
522 527 return null;
523 528 }
  529 +
  530 + public static ClassNode loadClass(String className) throws IOException
  531 + {
  532 + return ByteCodeUtilities.loadClass(className, true, null);
  533 + }
  534 +
  535 + public static ClassNode loadClass(String className, boolean runTransformers) throws IOException
  536 + {
  537 + return ByteCodeUtilities.loadClass(className, runTransformers, null);
  538 + }
  539 +
  540 + public static ClassNode loadClass(String className, IClassTransformer source) throws IOException
  541 + {
  542 + return ByteCodeUtilities.loadClass(className, source != null, source);
  543 + }
  544 +
  545 + public static ClassNode loadClass(String className, boolean runTransformers, IClassTransformer source) throws IOException
  546 + {
  547 + byte[] bytes = Launch.classLoader.getClassBytes(className);
  548 +
  549 + if (runTransformers)
  550 + {
  551 + bytes = ByteCodeUtilities.applyTransformers(className, bytes, source);
  552 + }
  553 +
  554 + return ByteCodeUtilities.readClass(bytes);
  555 + }
  556 +
  557 + public static ClassNode readClass(byte[] basicClass)
  558 + {
  559 + ClassReader classReader = new ClassReader(basicClass);
  560 + ClassNode classNode = new ClassNode();
  561 + classReader.accept(classNode, ClassReader.EXPAND_FRAMES);
  562 + return classNode;
  563 + }
  564 +
  565 + public static byte[] applyTransformers(String className, byte[] basicClass)
  566 + {
  567 + return ByteCodeUtilities.applyTransformers(className, basicClass, null);
  568 + }
  569 +
  570 + public static byte[] applyTransformers(String className, byte[] basicClass, IClassTransformer source)
  571 + {
  572 + final List<IClassTransformer> transformers = Launch.classLoader.getTransformers();
  573 +
  574 + for (final IClassTransformer transformer : transformers)
  575 + {
  576 + if (transformer != source)
  577 + {
  578 + basicClass = transformer.transform(className, className, basicClass);
  579 + }
  580 + }
  581 +
  582 + return basicClass;
  583 + }
524 584  
525 585 /**
526 586 * Get an annotation of the specified class from the supplied field node
527 587 */
528   - public static AnnotationNode getAnnotation(FieldNode field, Class<? extends Annotation> annotationClass)
  588 + public static AnnotationNode getVisibleAnnotation(FieldNode field, Class<? extends Annotation> annotationClass)
529 589 {
530 590 return ByteCodeUtilities.getAnnotation(field.visibleAnnotations, Type.getDescriptor(annotationClass));
531 591 }
  592 +
  593 + /**
  594 + * Get an annotation of the specified class from the supplied field node
  595 + */
  596 + public static AnnotationNode getInvisibleAnnotation(FieldNode field, Class<? extends Annotation> annotationClass)
  597 + {
  598 + return ByteCodeUtilities.getAnnotation(field.invisibleAnnotations, Type.getDescriptor(annotationClass));
  599 + }
532 600  
533 601 /**
534 602 * Get an annotation of the specified class from the supplied method node
535 603 */
536   - public static AnnotationNode getAnnotation(MethodNode method, Class<? extends Annotation> annotationClass)
  604 + public static AnnotationNode getVisibleAnnotation(MethodNode method, Class<? extends Annotation> annotationClass)
537 605 {
538 606 return ByteCodeUtilities.getAnnotation(method.visibleAnnotations, Type.getDescriptor(annotationClass));
539 607 }
  608 +
  609 + /**
  610 + * Get an annotation of the specified class from the supplied method node
  611 + */
  612 + public static AnnotationNode getInvisibleAnnotation(MethodNode method, Class<? extends Annotation> annotationClass)
  613 + {
  614 + return ByteCodeUtilities.getAnnotation(method.invisibleAnnotations, Type.getDescriptor(annotationClass));
  615 + }
540 616  
541 617 /**
  618 + * Get an annotation of the specified class from the supplied class node
  619 + */
  620 + public static AnnotationNode getVisibleAnnotation(ClassNode classNode, Class<? extends Annotation> annotationClass)
  621 + {
  622 + return ByteCodeUtilities.getAnnotation(classNode.visibleAnnotations, Type.getDescriptor(annotationClass));
  623 + }
  624 +
  625 + /**
  626 + * Get an annotation of the specified class from the supplied class node
  627 + */
  628 + public static AnnotationNode getInvisibleAnnotation(ClassNode classNode, Class<? extends Annotation> annotationClass)
  629 + {
  630 + return ByteCodeUtilities.getAnnotation(classNode.invisibleAnnotations, Type.getDescriptor(annotationClass));
  631 + }
  632 +
  633 + /**
542 634 * Get an annotation of the specified class from the supplied list of annotations, returns null if no matching annotation was found
543 635 */
544 636 public static AnnotationNode getAnnotation(List<AnnotationNode> annotations, String annotationType)
... ... @@ -574,6 +666,9 @@ public abstract class ByteCodeUtilities
574 666 @SuppressWarnings("unchecked")
575 667 public static <T> T getAnnotationValue(AnnotationNode annotation, String key)
576 668 {
  669 + if (annotation == null || annotation.values == null)
  670 + return null;
  671 +
577 672 boolean getNextValue = false;
578 673 for (Object value : annotation.values)
579 674 {
... ...
java/common/com/mumfrey/liteloader/transformers/ClassOverlayTransformer.java
... ... @@ -8,7 +8,6 @@ import java.util.List;
8 8 import java.util.Map;
9 9 import java.util.Set;
10 10  
11   -import net.minecraft.launchwrapper.IClassTransformer;
12 11 import net.minecraft.launchwrapper.Launch;
13 12  
14 13 import org.objectweb.asm.ClassReader;
... ... @@ -314,7 +313,7 @@ public abstract class ClassOverlayTransformer extends ClassTransformer
314 313 {
315 314 for (MethodNode overlayMethod : overlayClass.methods)
316 315 {
317   - if (ByteCodeUtilities.getAnnotation(overlayMethod, Stub.class) != null || (ByteCodeUtilities.getAnnotation(overlayMethod, AppendInsns.class) == null && !overlayMethod.name.startsWith("<")))
  316 + if (ByteCodeUtilities.getVisibleAnnotation(overlayMethod, Stub.class) != null || (ByteCodeUtilities.getVisibleAnnotation(overlayMethod, AppendInsns.class) == null && !overlayMethod.name.startsWith("<")))
318 317 {
319 318 this.checkRenameMethod(targetClass, overlayMethod);
320 319 }
... ... @@ -333,8 +332,8 @@ public abstract class ClassOverlayTransformer extends ClassTransformer
333 332 {
334 333 this.transformMethod(overlayMethod, overlayClass.name, targetClass.name);
335 334  
336   - AnnotationNode appendAnnotation = ByteCodeUtilities.getAnnotation(overlayMethod, AppendInsns.class);
337   - AnnotationNode stubAnnotation = ByteCodeUtilities.getAnnotation(overlayMethod, Stub.class);
  335 + AnnotationNode appendAnnotation = ByteCodeUtilities.getVisibleAnnotation(overlayMethod, AppendInsns.class);
  336 + AnnotationNode stubAnnotation = ByteCodeUtilities.getVisibleAnnotation(overlayMethod, Stub.class);
338 337  
339 338 if (stubAnnotation != null)
340 339 {
... ... @@ -428,7 +427,7 @@ public abstract class ClassOverlayTransformer extends ClassTransformer
428 427 if (targetMethodName == null || targetMethodName.length() == 0) targetMethodName = sourceMethod.name;
429 428  
430 429 Set<String> obfuscatedNames = new HashSet<String>();
431   - AnnotationNode obfuscatedAnnotation = ByteCodeUtilities.getAnnotation(sourceMethod, Obfuscated.class);
  430 + AnnotationNode obfuscatedAnnotation = ByteCodeUtilities.getVisibleAnnotation(sourceMethod, Obfuscated.class);
432 431 if (obfuscatedAnnotation != null)
433 432 {
434 433 obfuscatedNames.addAll(ByteCodeUtilities.<List<String>>getAnnotationValue(obfuscatedAnnotation));
... ... @@ -495,7 +494,7 @@ public abstract class ClassOverlayTransformer extends ClassTransformer
495 494  
496 495 if (runTransformers)
497 496 {
498   - overlayBytes = this.applyTransformers(this.overlayClassName, overlayBytes);
  497 + overlayBytes = ByteCodeUtilities.applyTransformers(this.overlayClassName, overlayBytes, this);
499 498 }
500 499 }
501 500 catch (IOException ex)
... ... @@ -506,25 +505,4 @@ public abstract class ClassOverlayTransformer extends ClassTransformer
506 505  
507 506 return this.readClass(overlayBytes, false);
508 507 }
509   -
510   - /**
511   - * Since we obtain the overlay class bytes with getClassBytes(), we need to apply the transformers ourself
512   - *
513   - * @param name
514   - * @param basicClass
515   - */
516   - private byte[] applyTransformers(String name, byte[] basicClass)
517   - {
518   - final List<IClassTransformer> transformers = Launch.classLoader.getTransformers();
519   -
520   - for (final IClassTransformer transformer : transformers)
521   - {
522   - if (transformer != this)
523   - {
524   - basicClass = transformer.transform(name, name, basicClass);
525   - }
526   - }
527   -
528   - return basicClass;
529   - }
530 508 }
... ...
java/common/com/mumfrey/liteloader/transformers/access/Accessor.java 0 โ†’ 100644
  1 +package com.mumfrey.liteloader.transformers.access;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * Defines an accessor method within an accessor injection interface, or an accessor interface itself
  10 + *
  11 + * @author Adam Mummery-Smith
  12 + */
  13 +@Target({ElementType.METHOD, ElementType.TYPE})
  14 +@Retention(RetentionPolicy.CLASS)
  15 +public @interface Accessor
  16 +{
  17 + public String value();
  18 +}
... ...
java/common/com/mumfrey/liteloader/transformers/access/AccessorTransformer.java 0 โ†’ 100644
  1 +package com.mumfrey.liteloader.transformers.access;
  2 +
  3 +import java.io.IOException;
  4 +import java.util.ArrayList;
  5 +import java.util.Iterator;
  6 +import java.util.List;
  7 +
  8 +import net.minecraft.launchwrapper.Launch;
  9 +
  10 +import org.objectweb.asm.ClassReader;
  11 +import org.objectweb.asm.Opcodes;
  12 +import org.objectweb.asm.Type;
  13 +import org.objectweb.asm.tree.AnnotationNode;
  14 +import org.objectweb.asm.tree.ClassNode;
  15 +import org.objectweb.asm.tree.FieldInsnNode;
  16 +import org.objectweb.asm.tree.FieldNode;
  17 +import org.objectweb.asm.tree.InsnNode;
  18 +import org.objectweb.asm.tree.MethodInsnNode;
  19 +import org.objectweb.asm.tree.MethodNode;
  20 +import org.objectweb.asm.tree.VarInsnNode;
  21 +
  22 +import com.mumfrey.liteloader.core.runtime.Obf;
  23 +import com.mumfrey.liteloader.transformers.ByteCodeUtilities;
  24 +import com.mumfrey.liteloader.transformers.ClassTransformer;
  25 +import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
  26 +
  27 +/**
  28 + * Transformer which can inject accessor methods into a target class
  29 + *
  30 + * @author Adam Mummery-Smith
  31 + */
  32 +public abstract class AccessorTransformer extends ClassTransformer
  33 +{
  34 + /**
  35 + * An injection record
  36 + *
  37 + * @author Adam Mummery-Smith
  38 + */
  39 + class AccessorInjection
  40 + {
  41 + /**
  42 + * Full name of the interface to inject
  43 + */
  44 + private final String iface;
  45 +
  46 + /**
  47 + * Obfuscation table class specified by the interface
  48 + */
  49 + private final Class<? extends Obf> table;
  50 +
  51 + /**
  52 + * Target class to inject into
  53 + */
  54 + private final Obf target;
  55 +
  56 + protected AccessorInjection(String iface) throws IOException
  57 + {
  58 + ClassNode ifaceNode = this.loadClass(iface);
  59 + this.table = this.setupTable(ifaceNode);
  60 + this.target = this.setupTarget(ifaceNode);
  61 + this.iface = iface;
  62 + }
  63 +
  64 + private ClassNode loadClass(String iface) throws IOException
  65 + {
  66 + byte[] bytes = this.getClassBytes(iface);
  67 + ClassReader classReader = new ClassReader(bytes);
  68 + ClassNode classNode = new ClassNode();
  69 + classReader.accept(classNode, 0);
  70 + return classNode;
  71 + }
  72 +
  73 + private byte[] getClassBytes(String iface) throws IOException
  74 + {
  75 + return Launch.classLoader.getClassBytes(iface);
  76 + }
  77 +
  78 + private Obf getObf(String name)
  79 + {
  80 + return Obf.getByName(this.table, name);
  81 + }
  82 +
  83 + protected Obf getTarget()
  84 + {
  85 + return this.target;
  86 + }
  87 +
  88 + @SuppressWarnings("unchecked")
  89 + private Class<? extends Obf> setupTable(ClassNode ifaceNode)
  90 + {
  91 + AnnotationNode annotation = ByteCodeUtilities.getInvisibleAnnotation(ifaceNode, ObfTableClass.class);
  92 + if (annotation != null)
  93 + {
  94 + try
  95 + {
  96 + Type obfTableType = ByteCodeUtilities.getAnnotationValue(annotation);
  97 + return (Class<? extends Obf>)Class.forName(obfTableType.getClassName(), true, Launch.classLoader);
  98 + }
  99 + catch (ClassNotFoundException ex)
  100 + {
  101 + ex.printStackTrace();
  102 + }
  103 + }
  104 +
  105 + return Obf.class;
  106 + }
  107 +
  108 + private Obf setupTarget(ClassNode ifaceNode)
  109 + {
  110 + AnnotationNode annotation = ByteCodeUtilities.getInvisibleAnnotation(ifaceNode, Accessor.class);
  111 + return this.getObf(ByteCodeUtilities.<String>getAnnotationValue(annotation));
  112 + }
  113 +
  114 + protected void apply(ClassNode classNode)
  115 + {
  116 + String ifaceRef = this.iface.replace('.', '/');
  117 +
  118 + if (classNode.interfaces.contains(ifaceRef))
  119 + {
  120 + LiteLoaderLogger.debug("[AccessorTransformer] Skipping %s because %s was already applied", classNode.name, this.iface);
  121 + return;
  122 + }
  123 +
  124 + classNode.interfaces.add(ifaceRef);
  125 +
  126 + try
  127 + {
  128 + LiteLoaderLogger.debug("[AccessorTransformer] Loading %s", this.iface);
  129 + ClassNode ifaceNode = ByteCodeUtilities.loadClass(this.iface, AccessorTransformer.this);
  130 +
  131 + for (MethodNode method : ifaceNode.methods)
  132 + {
  133 + this.addMethod(classNode, method);
  134 + }
  135 + }
  136 + catch (Exception ex)
  137 + {
  138 + ex.printStackTrace();
  139 + }
  140 + }
  141 +
  142 + private void addMethod(ClassNode classNode, MethodNode method)
  143 + {
  144 + if (!this.addMethodToClass(classNode, method))
  145 + {
  146 + LiteLoaderLogger.debug("[AccessorTransformer] Method %s already exists in %s", method.name, classNode.name);
  147 + return;
  148 + }
  149 +
  150 + LiteLoaderLogger.debug("[AccessorTransformer] Attempting to add %s to %s", method.name, classNode.name);
  151 +
  152 + AnnotationNode accessor = ByteCodeUtilities.getInvisibleAnnotation(method, Accessor.class);
  153 + AnnotationNode invoker = ByteCodeUtilities.getInvisibleAnnotation(method, Invoker.class);
  154 + if (accessor != null)
  155 + {
  156 + Obf targetName = this.getObf(ByteCodeUtilities.<String>getAnnotationValue(accessor));
  157 + if (this.injectAccessor(classNode, method, targetName)) return;
  158 + }
  159 + else if (invoker != null)
  160 + {
  161 + Obf targetName = this.getObf(ByteCodeUtilities.<String>getAnnotationValue(invoker));
  162 + if (this.injectInvoker(classNode, method, targetName)) return;
  163 + }
  164 + else
  165 + {
  166 + LiteLoaderLogger.severe("[AccessorTransformer] Method %s for %s has no @Accessor or @Invoker annotation, the method will be ABSTRACT!", method.name, this.iface);
  167 + }
  168 +
  169 + LiteLoaderLogger.severe("[AccessorTransformer] Method %s for %s could not locate target member, the method will be ABSTRACT!", method.name, this.iface);
  170 + }
  171 +
  172 + private boolean injectAccessor(ClassNode classNode, MethodNode method, Obf targetName)
  173 + {
  174 + FieldNode targetField = this.findField(classNode, targetName);
  175 + if (targetField != null)
  176 + {
  177 + LiteLoaderLogger.debug("[AccessorTransformer] Found field %s for %s", targetField.name, method.name);
  178 + if (Type.getReturnType(method.desc) != Type.VOID_TYPE)
  179 + {
  180 + this.populateGetter(classNode, method, targetField);
  181 + }
  182 + else
  183 + {
  184 + this.populateSetter(classNode, method, targetField);
  185 + }
  186 +
  187 + return true;
  188 + }
  189 +
  190 + return false;
  191 + }
  192 +
  193 + private boolean injectInvoker(ClassNode classNode, MethodNode method, Obf targetName)
  194 + {
  195 + MethodNode targetMethod = this.findMethod(classNode, targetName, method.desc);
  196 + if (targetMethod != null)
  197 + {
  198 + LiteLoaderLogger.debug("[AccessorTransformer] Found method %s for %s", targetMethod.name, method.name);
  199 + this.populateInvoker(classNode, method, targetMethod);
  200 + return true;
  201 + }
  202 +
  203 + return false;
  204 + }
  205 +
  206 + private void populateGetter(ClassNode classNode, MethodNode method, FieldNode field)
  207 + {
  208 + Type returnType = Type.getReturnType(method.desc);
  209 + Type fieldType = Type.getType(field.desc);
  210 + if (!returnType.equals(fieldType))
  211 + {
  212 + throw new RuntimeException("Incompatible types! Field type: " + fieldType + " Method type: " + returnType);
  213 + }
  214 +
  215 + method.instructions.clear();
  216 + method.maxLocals = ByteCodeUtilities.getFirstNonArgLocalIndex(method);
  217 + method.maxStack = fieldType.getSize();
  218 +
  219 + if ((field.access & Opcodes.ACC_STATIC) == 0)
  220 + {
  221 + method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
  222 + method.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, field.name, field.desc));
  223 + }
  224 + else
  225 + {
  226 + method.instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, field.name, field.desc));
  227 + }
  228 +
  229 + method.instructions.add(new InsnNode(returnType.getOpcode(Opcodes.IRETURN)));
  230 + }
  231 +
  232 + private void populateSetter(ClassNode classNode, MethodNode method, FieldNode field)
  233 + {
  234 + Type[] argTypes = Type.getArgumentTypes(method.desc);
  235 + if (argTypes.length != 1)
  236 + {
  237 + throw new RuntimeException("Invalid setter! " + method.name + " must take exactly one argument");
  238 + }
  239 + Type argType = argTypes[0];
  240 + Type fieldType = Type.getType(field.desc);
  241 + if (!argType.equals(fieldType))
  242 + {
  243 + throw new RuntimeException("Incompatible types! Field type: " + fieldType + " Method type: " + argType);
  244 + }
  245 +
  246 + method.instructions.clear();
  247 + method.maxLocals = ByteCodeUtilities.getFirstNonArgLocalIndex(method);
  248 + method.maxStack = fieldType.getSize();
  249 +
  250 + if ((field.access & Opcodes.ACC_STATIC) == 0)
  251 + {
  252 + method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
  253 + method.instructions.add(new VarInsnNode(argType.getOpcode(Opcodes.ILOAD), 1));
  254 + method.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, field.name, field.desc));
  255 + }
  256 + else
  257 + {
  258 + method.instructions.add(new VarInsnNode(argType.getOpcode(Opcodes.ILOAD), 0));
  259 + method.instructions.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, field.name, field.desc));
  260 + }
  261 +
  262 + method.instructions.add(new InsnNode(Opcodes.RETURN));
  263 + }
  264 +
  265 + private void populateInvoker(ClassNode classNode, MethodNode method, MethodNode targetMethod)
  266 + {
  267 + Type[] args = Type.getArgumentTypes(targetMethod.desc);
  268 + Type returnType = Type.getReturnType(targetMethod.desc);
  269 + boolean isStatic = (targetMethod.access & Opcodes.ACC_STATIC) != 0;
  270 +
  271 + method.instructions.clear();
  272 + method.maxStack = (method.maxLocals = ByteCodeUtilities.getFirstNonArgLocalIndex(method)) + 1;
  273 +
  274 + if (isStatic)
  275 + {
  276 + ByteCodeUtilities.loadArgs(args, method.instructions, 0);
  277 + method.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, classNode.name, targetMethod.name, targetMethod.desc, false));
  278 + }
  279 + else
  280 + {
  281 + method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
  282 + ByteCodeUtilities.loadArgs(args, method.instructions, 1);
  283 + method.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, classNode.name, targetMethod.name, targetMethod.desc, false));
  284 + }
  285 +
  286 + method.instructions.add(new InsnNode(returnType.getOpcode(Opcodes.IRETURN)));
  287 + }
  288 +
  289 + private FieldNode findField(ClassNode classNode, Obf fieldName)
  290 + {
  291 + for (FieldNode field : classNode.fields)
  292 + {
  293 + if (fieldName.obf.equals(field.name) || fieldName.srg.equals(field.name)|| fieldName.name.equals(field.name))
  294 + return field;
  295 + }
  296 +
  297 + return null;
  298 + }
  299 +
  300 + private MethodNode findMethod(ClassNode classNode, Obf methodName, String desc)
  301 + {
  302 + for (MethodNode method : classNode.methods)
  303 + {
  304 + if ((methodName.obf.equals(method.name) || methodName.srg.equals(method.name)|| methodName.name.equals(method.name)) && method.desc.equals(desc))
  305 + return method;
  306 + }
  307 +
  308 + return null;
  309 + }
  310 +
  311 + private boolean addMethodToClass(ClassNode classNode, MethodNode method)
  312 + {
  313 + MethodNode existingMethod = ByteCodeUtilities.findTargetMethod(classNode, method);
  314 + if (existingMethod != null) return false;
  315 + classNode.methods.add(method);
  316 + method.access = method.access & ~Opcodes.ACC_ABSTRACT;
  317 + return true;
  318 + }
  319 + }
  320 +
  321 + private List<AccessorInjection> accessors = new ArrayList<AccessorInjection>();
  322 +
  323 + public AccessorTransformer()
  324 + {
  325 + this.addAccessors();
  326 + }
  327 +
  328 + public void addAccessor(String interfaceName)
  329 + {
  330 + try
  331 + {
  332 + this.accessors.add(new AccessorInjection(interfaceName));
  333 + }
  334 + catch (Exception ex)
  335 + {
  336 + LiteLoaderLogger.debug(ex);
  337 + }
  338 + }
  339 +
  340 + @Override
  341 + public byte[] transform(String name, String transformedName, byte[] basicClass)
  342 + {
  343 + ClassNode classNode = null;
  344 +
  345 + classNode = this.apply(name, transformedName, basicClass, classNode);
  346 +
  347 + if (classNode != null)
  348 + {
  349 + this.postTransform(name, transformedName, classNode);
  350 + return this.writeClass(classNode);
  351 + }
  352 +
  353 + return basicClass;
  354 + }
  355 +
  356 + public ClassNode apply(String name, String transformedName, byte[] basicClass, ClassNode classNode)
  357 + {
  358 + for (Iterator<AccessorInjection> iter = this.accessors.iterator(); iter.hasNext(); )
  359 + {
  360 + AccessorInjection accessor = iter.next();
  361 + Obf target = accessor.getTarget();
  362 + if (target.obf.equals(transformedName) || target.name.equals(transformedName))
  363 + {
  364 + LiteLoaderLogger.debug("[AccessorTransformer] Processing access injections in %s", transformedName);
  365 + if (classNode == null) classNode = this.readClass(basicClass, true);
  366 + accessor.apply(classNode);
  367 + iter.remove();
  368 + }
  369 + }
  370 +
  371 + return classNode;
  372 + }
  373 +
  374 + protected void addAccessors()
  375 + {
  376 + }
  377 +
  378 + protected void postTransform(String name, String transformedName, ClassNode classNode)
  379 + {
  380 + }
  381 +}
... ...
java/common/com/mumfrey/liteloader/transformers/access/Invoker.java 0 โ†’ 100644
  1 +package com.mumfrey.liteloader.transformers.access;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * Defines an invoker method within an accessor injection interface
  10 + *
  11 + * @author Adam Mummery-Smith
  12 + */
  13 +@Target({ElementType.METHOD, ElementType.TYPE})
  14 +@Retention(RetentionPolicy.CLASS)
  15 +public @interface Invoker
  16 +{
  17 + public String value();
  18 +}
... ...
java/common/com/mumfrey/liteloader/transformers/access/ObfTableClass.java 0 โ†’ 100644
  1 +package com.mumfrey.liteloader.transformers.access;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +import com.mumfrey.liteloader.core.runtime.Obf;
  9 +
  10 +/**
  11 + * Defines the obfuscation table class to use for an accessor injection interface
  12 + *
  13 + * @author Adam Mummery-Smith
  14 + */
  15 +@Target(ElementType.TYPE)
  16 +@Retention(RetentionPolicy.CLASS)
  17 +public @interface ObfTableClass
  18 +{
  19 + public Class<? extends Obf> value();
  20 +}
... ...
java/common/com/mumfrey/liteloader/transformers/event/EventInjectionTransformer.java
... ... @@ -75,4 +75,14 @@ public abstract class EventInjectionTransformer implements IClassTransformer
75 75  
76 76 return event;
77 77 }
  78 +
  79 + /**
  80 + * Register an access injection interface
  81 + *
  82 + * @param interfaceName
  83 + */
  84 + protected final void addAccessor(String interfaceName)
  85 + {
  86 + EventTransformer.addAccessor(interfaceName);
  87 + }
78 88 }
... ...
java/common/com/mumfrey/liteloader/transformers/event/EventTransformer.java
... ... @@ -19,6 +19,7 @@ import org.objectweb.asm.util.CheckClassAdapter;
19 19  
20 20 import com.mumfrey.liteloader.transformers.ByteCodeUtilities;
21 21 import com.mumfrey.liteloader.transformers.ClassTransformer;
  22 +import com.mumfrey.liteloader.transformers.access.AccessorTransformer;
22 23 import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
23 24  
24 25 /**
... ... @@ -55,12 +56,14 @@ public final class EventTransformer extends ClassTransformer
55 56 */
56 57 private static Map<String, Map<String, Map<Event, InjectionPoint>>> eventMappings = new HashMap<String, Map<String, Map<Event, InjectionPoint>>>();
57 58  
  59 + private static AccessorTransformer accessorTransformer;
  60 +
58 61 /**
59 62 * Runs the validator on the generated classes, only for debugging purposes
60 63 */
61 64 private final boolean runValidator = false;
62 65  
63   - private int globalEventID = 0;
  66 + private int globalEventID = 0;
64 67  
65 68 static class Injection
66 69 {
... ... @@ -186,18 +189,37 @@ public final class EventTransformer extends ClassTransformer
186 189 events.put(event, injectionPoint);
187 190 }
188 191  
  192 + static void addAccessor(String interfaceName)
  193 + {
  194 + if (EventTransformer.accessorTransformer == null)
  195 + {
  196 + EventTransformer.accessorTransformer = new AccessorTransformer()
  197 + {
  198 + @Override
  199 + protected void addAccessors() {}
  200 + };
  201 + }
  202 +
  203 + EventTransformer.accessorTransformer.addAccessor(interfaceName);
  204 + }
  205 +
189 206 @Override
190 207 public final byte[] transform(String name, String transformedName, byte[] basicClass)
191 208 {
192 209 if (basicClass != null && EventTransformer.eventMappings.containsKey(transformedName))
193 210 {
194   - return this.injectEvents(basicClass, EventTransformer.eventMappings.get(transformedName));
  211 + return this.injectEvents(name, transformedName, basicClass, EventTransformer.eventMappings.get(transformedName));
  212 + }
  213 +
  214 + if (EventTransformer.accessorTransformer != null)
  215 + {
  216 + return EventTransformer.accessorTransformer.transform(name, transformedName, basicClass);
195 217 }
196 218  
197 219 return basicClass;
198 220 }
199 221  
200   - private byte[] injectEvents(byte[] basicClass, Map<String, Map<Event, InjectionPoint>> mappings)
  222 + private byte[] injectEvents(String name, String transformedName, byte[] basicClass, Map<String, Map<Event, InjectionPoint>> mappings)
201 223 {
202 224 if (mappings == null) return basicClass;
203 225  
... ... @@ -213,6 +235,11 @@ public final class EventTransformer extends ClassTransformer
213 235 }
214 236 }
215 237  
  238 + if (EventTransformer.accessorTransformer != null)
  239 + {
  240 + EventTransformer.accessorTransformer.apply(name, transformedName, basicClass, classNode);
  241 + }
  242 +
216 243 if (this.runValidator)
217 244 {
218 245 ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
... ...
java/common/com/mumfrey/liteloader/transformers/event/json/JsonEvents.java
1 1 package com.mumfrey.liteloader.transformers.event.json;
2 2  
3 3 import java.io.Serializable;
  4 +import java.util.ArrayList;
4 5 import java.util.List;
5 6 import java.util.regex.Matcher;
6 7 import java.util.regex.Pattern;
... ... @@ -8,6 +9,7 @@ import java.util.regex.Pattern;
8 9 import com.google.gson.Gson;
9 10 import com.google.gson.GsonBuilder;
10 11 import com.google.gson.annotations.SerializedName;
  12 +import com.mumfrey.liteloader.core.runtime.Obf;
11 13  
12 14 /**
13 15 * Serialisable class which represents a set of event injection definitions. Instances of this class are
... ... @@ -49,11 +51,22 @@ public class JsonEvents implements Serializable
49 51 private List<JsonEvent> events;
50 52  
51 53 /**
  54 + * List of accessor interfaces
  55 + */
  56 + @SerializedName("accessors")
  57 + private List<String> accessors;
  58 +
  59 + /**
52 60 * Parsed method descriptors
53 61 */
54 62 private transient JsonMethods methods;
55 63  
56 64 /**
  65 + * Parsed accessors
  66 + */
  67 + private transient List<String> accessorInterfaces = new ArrayList<String>();
  68 +
  69 + /**
57 70 * Attempts to parse the information in this object
58 71 */
59 72 private void parse()
... ... @@ -76,6 +89,18 @@ public class JsonEvents implements Serializable
76 89 {
77 90 event.parse(this.methods);
78 91 }
  92 +
  93 + if (this.accessors != null)
  94 + {
  95 + for (String accessor : this.accessors)
  96 + {
  97 + if (accessor != null)
  98 + {
  99 + Obf accessorName = this.obfuscation.parseClass(accessor);
  100 + this.accessorInterfaces.add(accessorName.name);
  101 + }
  102 + }
  103 + }
79 104 }
80 105 catch (InvalidEventJsonException ex)
81 106 {
... ... @@ -116,6 +141,11 @@ public class JsonEvents implements Serializable
116 141 {
117 142 event.register(transformer);
118 143 }
  144 +
  145 + for (String interfaceName : this.accessorInterfaces)
  146 + {
  147 + transformer.registerAccessor(interfaceName);
  148 + }
119 149 }
120 150  
121 151 // public String toJson()
... ...
java/common/com/mumfrey/liteloader/transformers/event/json/ModEventInjectionTransformer.java
... ... @@ -74,4 +74,9 @@ public class ModEventInjectionTransformer extends EventInjectionTransformer
74 74 {
75 75 return super.addEvent(event, targetMethod, injectionPoint);
76 76 }
  77 +
  78 + protected void registerAccessor(String interfaceName)
  79 + {
  80 + super.addAccessor(interfaceName);
  81 + }
77 82 }
... ...