Commit fba0e0ffc742dfd2c78a379dcdc7097c3cef12a2
1 parent
0ec79e75
adding AccessorTransformer and replacing MinecraftOverlay with accessor injection
Showing
17 changed files
with
724 additions
and
170 deletions
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 | } | ... | ... |