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 | } | ... | ... |