From a980aa660ce0731ef62f99cdf4dbd6472a67ce2f Mon Sep 17 00:00:00 2001 From: Lucwousin Date: Fri, 1 Nov 2019 07:43:48 +0100 Subject: [PATCH] Change rasterizer raw injector from depending on hardcoded values --- .../code/instructions/ArrayStore.java | 5 +- .../code/instructions/InvokeStatic.java | 2 +- .../runelite/asm/execution/MethodContext.java | 3 +- .../java/net/runelite/injector/Inject.java | 6 +- .../injector/raw/RasterizerAlpha.java | 268 +++++++++++++ .../runelite/injector/raw/RasterizerHook.java | 371 ------------------ 6 files changed, 274 insertions(+), 381 deletions(-) create mode 100644 injector-plugin/src/main/java/net/runelite/injector/raw/RasterizerAlpha.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/raw/RasterizerHook.java diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/ArrayStore.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/ArrayStore.java index 266cd7f1b1..7acb82c1e5 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/ArrayStore.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/ArrayStore.java @@ -52,8 +52,7 @@ public abstract class ArrayStore extends Instruction implements ArrayStoreInstru if (r.getInstruction() instanceof GetFieldInstruction) { GetFieldInstruction gf = (GetFieldInstruction) r.getInstruction(); - Field f = gf.getMyField(); - return f; + return gf.getMyField(); } return null; @@ -89,7 +88,7 @@ public abstract class ArrayStore extends Instruction implements ArrayStoreInstru Field f1 = gf1.getMyField(), f2 = gf2.getMyField(); - + assert MappingExecutorUtil.isMaybeEqual(f1, f2); if (f1 != null && f2 != null) diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeStatic.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeStatic.java index f992fb6621..1ad5ea2088 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeStatic.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeStatic.java @@ -86,7 +86,7 @@ public class InvokeStatic extends Instruction implements InvokeInstruction @SuppressWarnings("unchecked") public List getMethods() { - return myMethod != null ? Arrays.asList(myMethod) : Collections.EMPTY_LIST; + return myMethod != null ? Collections.singletonList(myMethod) : Collections.EMPTY_LIST; } @Override diff --git a/deobfuscator/src/main/java/net/runelite/asm/execution/MethodContext.java b/deobfuscator/src/main/java/net/runelite/asm/execution/MethodContext.java index e55d5e6aeb..4615200f72 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/execution/MethodContext.java +++ b/deobfuscator/src/main/java/net/runelite/asm/execution/MethodContext.java @@ -70,10 +70,9 @@ public class MethodContext return contexts.get(i); } - @SuppressWarnings("unchecked") public Collection getInstructionContexts() { - return (Collection) contexts.values(); + return contexts.values(); } public void reset() diff --git a/injector-plugin/src/main/java/net/runelite/injector/Inject.java b/injector-plugin/src/main/java/net/runelite/injector/Inject.java index 9d9b372f07..4a87466311 100644 --- a/injector-plugin/src/main/java/net/runelite/injector/Inject.java +++ b/injector-plugin/src/main/java/net/runelite/injector/Inject.java @@ -49,7 +49,7 @@ import static net.runelite.injector.InjectUtil.getFieldType; import net.runelite.injector.raw.ClearColorBuffer; import net.runelite.injector.raw.DrawAfterWidgets; import net.runelite.injector.raw.Occluder; -import net.runelite.injector.raw.RasterizerHook; +import net.runelite.injector.raw.RasterizerAlpha; import net.runelite.injector.raw.RenderDraw; import net.runelite.injector.raw.ScriptVM; import net.runelite.mapping.Import; @@ -58,8 +58,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.runelite.injector.raw.HidePlayerAttacks; -// import net.runelite.injector.raw.DrawMenu; - public class Inject { public static final java.lang.Class CLIENT_CLASS = RSClient.class; @@ -207,7 +205,7 @@ public class Inject // Has to be done before mixins // well, can be done after really // but why do that when you can do it before - new RasterizerHook(this).inject(); + new RasterizerAlpha(this).inject(); // requires interfaces to be injected mixinInjector.inject(); diff --git a/injector-plugin/src/main/java/net/runelite/injector/raw/RasterizerAlpha.java b/injector-plugin/src/main/java/net/runelite/injector/raw/RasterizerAlpha.java new file mode 100644 index 0000000000..724d5769eb --- /dev/null +++ b/injector-plugin/src/main/java/net/runelite/injector/raw/RasterizerAlpha.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2018, Lucas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.injector.raw; + +import com.google.common.collect.Lists; +import net.runelite.asm.ClassFile; +import net.runelite.asm.Field; +import net.runelite.asm.Method; +import net.runelite.asm.attributes.Code; +import net.runelite.asm.attributes.code.Instruction; +import net.runelite.asm.attributes.code.InstructionType; +import net.runelite.asm.attributes.code.Instructions; +import net.runelite.asm.attributes.code.instruction.types.FieldInstruction; +import net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction; +import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; +import net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction; +import net.runelite.asm.attributes.code.instructions.GetStatic; +import net.runelite.asm.attributes.code.instructions.IALoad; +import net.runelite.asm.attributes.code.instructions.IAStore; +import net.runelite.asm.attributes.code.instructions.IAdd; +import net.runelite.asm.attributes.code.instructions.ILoad; +import net.runelite.asm.attributes.code.instructions.IOr; +import net.runelite.asm.attributes.code.instructions.IShR; +import net.runelite.asm.attributes.code.instructions.ISub; +import net.runelite.asm.attributes.code.instructions.IUShR; +import net.runelite.asm.attributes.code.instructions.InvokeStatic; +import net.runelite.asm.attributes.code.instructions.LDC; +import net.runelite.asm.attributes.code.instructions.SiPush; +import net.runelite.asm.execution.Execution; +import net.runelite.asm.execution.InstructionContext; +import net.runelite.asm.execution.MethodContext; +import net.runelite.asm.execution.StackContext; +import net.runelite.asm.execution.VariableContext; +import net.runelite.asm.pool.Class; +import net.runelite.asm.signature.Signature; +import net.runelite.injector.Inject; +import net.runelite.injector.InjectUtil; +import net.runelite.injector.InjectionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RasterizerAlpha +{ + private static final Logger logger = LoggerFactory.getLogger(RasterizerAlpha.class); + private static final net.runelite.asm.pool.Method DRAWALPHA = new net.runelite.asm.pool.Method( + new Class("client"), + "drawAlpha", + new Signature("([IIII)V") + ); + private static final int ALPHA = 0xff000000; + + private final Inject inject; + + public RasterizerAlpha(Inject inject) + { + this.inject = inject; + } + + /* + * This class exists cause of removing colour banding. + * + * Push array on stack + * Push array index on stack + * Push colour on stack -> we're interested in where the colour comes from + * Put colour in array, popping array, index and colour + * + * + * + */ + public void inject() throws InjectionException + { + final Field r2dPx = InjectUtil.findDeobField(inject, "Rasterizer2D_pixels", "Rasterizer2D"); + final Method draw = InjectUtil.findMethod(inject, "draw", "Client"); + final ClassFile rasterizer2D = r2dPx.getClassFile(); + final Execution ex = new Execution(rasterizer2D.getGroup()); + ex.staticStep = false; + ex.step = false; + ex.addMethod(draw); + + int[] counts = new int[2]; + + ex.addMethodContextVisitor((MethodContext mc) -> + { + Instructions instrs = getInstrs(mc); + if (instrs == null) + return; + + int count = 0; + int orCount = 0; + + for (InstructionContext ic : mc.getInstructionContexts()) + { + Instruction instruction = ic.getInstruction(); + if (!(instruction instanceof IAStore)) + continue; + + // Field field = astore.getMyField(ic); + // doesn't track into methods so doing it here + StackContext array = ic.getPops().get(2); + + if (!isSameField(r2dPx, array)) + continue; + + // This is the colour that's being set + StackContext colour = ic.getPops().get(0); + + // resolve gets the original value pusher + InstructionContext colPusher = colour.getPushed().resolve(colour); + Instruction colPushI = colPusher.getInstruction(); + + // If it's not a >> or a | we're not interested + if (colPushI instanceof LVTInstruction // when called from a method we didn't execute + || colPushI instanceof PushConstantInstruction && + !((PushConstantInstruction) colPushI).getConstant().equals(0) + || colPushI instanceof IALoad) + { + // OR with 0xFF000000, unless 0 + int storeIdx = instrs.getInstructions().indexOf(instruction); + + instrs.addInstruction(storeIdx++, new LDC(instrs, ALPHA)); + instrs.addInstruction(storeIdx, new IOr(instrs, InstructionType.IOR)); + ++orCount; + continue; + } + else if (!( + colPushI instanceof IShR || + colPushI instanceof IUShR || + colPushI instanceof IAdd)) + { + continue; + } + + // So we know we're dealing with alpha here, now we need the alpha value + // earlier on in the method there's been a 256 - XXX, where xxx is alpha + + for (InstructionContext ins : mc.getInstructionContexts()) + { + if (!(ins.getInstruction() instanceof SiPush)) + continue; + + SiPush pci = (SiPush) ins.getInstruction(); + if ((short) pci.getConstant() != (short) 256) + continue; + + InstructionContext isub = ins.getPushes().get(0).getPopped().get(0); + if (!(isub.getInstruction() instanceof ISub)) + continue; + + StackContext alphaPop = isub.getPops().get(0); + InstructionContext alphaPusher = alphaPop.getPushed().resolve(alphaPop); + InstructionContext isubResult = isub.getPushes().get(0).getPopped().get(0); + + if (pushesToSameField(isubResult, alphaPusher)) + { + alphaPusher = resolveFieldThroughInvokes(alphaPop); + + if (alphaPusher == null) + throw new RuntimeException("Alpha var is overwritten and we don't know what pushed it"); // cheeky unchecked + } + + int storeIdx = instrs.getInstructions().indexOf(instruction); + + Instruction alphaPushI = alphaPusher.getInstruction(); + if (alphaPushI instanceof GetStatic) + { + instrs.addInstruction(storeIdx++, new LDC(instrs, 255)); + instrs.addInstruction(storeIdx++, new GetStatic(instrs, ((GetStatic) alphaPushI).getField())); + instrs.addInstruction(storeIdx++, new ISub(instrs, InstructionType.ISUB)); + } + else if (alphaPushI instanceof LVTInstruction) + { + instrs.addInstruction(storeIdx++, new ILoad(instrs, ((LVTInstruction) alphaPushI).getVariableIndex())); + } + + instrs.getInstructions().set(storeIdx, new InvokeStatic(instrs, DRAWALPHA)); + ++count; + break; + } + } + + if (orCount != 0) + { + counts[0] += orCount; + logger.info("Added {} OR's into {}", orCount, mc.getMethod()); + } + if (count != 0) + { + counts[1] += count; + logger.info("Injected {} DrawAlpha invokes into {}", count, mc.getMethod()); + } + }); + + ex.run(); + logger.info("Injected {} DrawAlpha invokes and {} ors", counts[1], counts[0]); + } + + private static boolean pushesToSameField(InstructionContext cA, InstructionContext cB) + { + if (cA.getInstruction() instanceof FieldInstruction && cB instanceof FieldInstruction) + { + Field a = ((FieldInstruction) cA.getInstruction()).getMyField(); + Field b = ((FieldInstruction) cB.getInstruction()).getMyField(); + + return a == b; + } + + return false; + } + + private static Instructions getInstrs(MethodContext mc) + { + Code c = mc.getMethod().getCode(); + if (c == null) + return null; + + return c.getInstructions(); + } + + private static InstructionContext resolveFieldThroughInvokes(StackContext stackContext) + { + InstructionContext pusher = stackContext.getPushed().resolve(stackContext); + if (pusher.getInstruction() instanceof GetFieldInstruction) + return pusher; + + // No field I wanna trace, rn at least + if (!(pusher.getInstruction() instanceof LVTInstruction)) + return null; + + int vidx = ((LVTInstruction) pusher.getInstruction()).getVariableIndex(); + + VariableContext vc = pusher.getVariables().get(vidx); + stackContext = Lists.reverse(vc.getInstructionWhichStored().getPops()).get(vidx); + + return resolveFieldThroughInvokes(stackContext); + } + + private static boolean isSameField(Field f, StackContext array) + { + InstructionContext ic = resolveFieldThroughInvokes(array); + + if (ic == null) + return false; + + return ((GetFieldInstruction) ic.getInstruction()).getMyField() == f; + } +} diff --git a/injector-plugin/src/main/java/net/runelite/injector/raw/RasterizerHook.java b/injector-plugin/src/main/java/net/runelite/injector/raw/RasterizerHook.java deleted file mode 100644 index df671fff40..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/raw/RasterizerHook.java +++ /dev/null @@ -1,371 +0,0 @@ -package net.runelite.injector.raw; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.ArrayStore; -import net.runelite.asm.attributes.code.instructions.GetField; -import net.runelite.asm.attributes.code.instructions.GetStatic; -import net.runelite.asm.attributes.code.instructions.IALoad; -import net.runelite.asm.attributes.code.instructions.IAStore; -import net.runelite.asm.attributes.code.instructions.ILoad; -import net.runelite.asm.attributes.code.instructions.IOr; -import net.runelite.asm.attributes.code.instructions.ISub; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.execution.Execution; -import net.runelite.asm.execution.InstructionContext; -import net.runelite.asm.pool.Class; -import net.runelite.asm.signature.Signature; -import net.runelite.injector.Inject; -import static net.runelite.injector.InjectUtil.findDeobField; -import static net.runelite.injector.InjectUtil.findStaticMethod; -import net.runelite.injector.InjectionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RasterizerHook -{ - // TODO: Should probably make this better - private static final Logger logger = LoggerFactory.getLogger(ClearColorBuffer.class); - private static final int val = -16777216; - - private static final String font_alpha = "AbstractFont_placeGlyphAlpha"; - private static final String circle_alpha = "Rasterizer2D_drawCircleAlpha"; - private static final String line_alpha = "Rasterizer2D_drawHorizontalLineAlpha"; - private static final String line_alpha2 = "Rasterizer2D_drawVerticalLineAlpha"; - private static final String fill_rect_alpha = "Rasterizer2D_fillRectangleAlpha"; - private static final String r3d_vert = "Rasterizer3D_vertAlpha"; - private static final String r3d_horiz = "Rasterizer3D_horizAlpha"; - private static final String r3d_field = "Rasterizer3D_alpha"; - private static final String sprite_alpha1 = "Sprite_drawTransparent"; - private static final String sprite_alpha2 = "Sprite_drawTransScaled"; - - private static final String font = "AbstractFont_placeGlyph"; - private static final String rast3D = "Rasterizer3D_iDontKnow"; - private static final String rast3D2 = "Rasterizer3D_textureAlpha"; - private static final String sprite = "Sprite_draw"; - private static final String sprite2 = "Sprite_drawScaled"; - private static final String sprite3 = "Sprite_drawTransOverlay"; - private static final String sprite4 = "Sprite_drawTransBg"; - private static final String indexedSprite = "IndexedSprite_something"; - private static final String indexedSprite2 = "IndexedSprite_two"; - - private static final net.runelite.asm.pool.Method drawAlpha = new net.runelite.asm.pool.Method( - new Class("client"), - "drawAlpha", - new Signature("([IIII)V") - ); - private final Inject inject; - private int count; - - public RasterizerHook(Inject inject) - { - this.inject = inject; - } - - public void inject() throws InjectionException - { - runDrawAlpha(); - - logger.info("Injected {} drawAlpha's", count); - assert count == 35 : "Either too many or not enough drawAlpha's were injected"; - - count = 0; - - runVars(); - - run(); - } - - private void runDrawAlpha() throws InjectionException - { - runR3DAlpha(r3d_horiz, 15, r3d_field); - runR3DAlpha(r3d_vert, 12, r3d_field); - runFontAlpha(font_alpha, 1, 9); // speshul cause 255 - var9 - runAlpha(circle_alpha, 2, 4); - runAlpha(line_alpha, 1, 4); - runAlpha(line_alpha2, 1, 4); - runAlpha(fill_rect_alpha, 1, 5); - runAlpha(sprite_alpha1, 1, 9, 0); - runAlpha(sprite_alpha2, 1, 12, 0); - } - - private void runR3DAlpha(String methodName, int req, String fieldName) throws InjectionException - { - Method meth = findStaticMethod(inject, methodName); - Field field = findDeobField(inject, fieldName); - Instructions ins = meth.getCode().getInstructions(); - int varIdx = 0; // This is obviously dumb but I cba making this better - int added = 0; - - List indices = new ArrayList<>(); - for (Instruction i : meth.findLVTInstructionsForVariable(varIdx)) - { - indices.add(ins.getInstructions().indexOf(i)); - } - - if (indices.isEmpty()) - { - throw new InjectionException("Couldn't find hook location in " + methodName); - } - - for (int i : indices) - { - for (int codeIndex = i + added; codeIndex < ins.getInstructions().size(); codeIndex++) - { - if (ins.getInstructions().get(codeIndex) instanceof IAStore) - { - ins.getInstructions().set(codeIndex, new InvokeStatic(ins, drawAlpha)); - - ins.getInstructions().add(codeIndex, new ISub(ins, InstructionType.ISUB)); - ins.getInstructions().add(codeIndex, new GetStatic(ins, field.getPoolField())); - ins.getInstructions().add(codeIndex, new LDC(ins, 255)); - added++; - count++; - break; - } - } - } - } - - private void runAlpha(String methodName, int req, int extraArg) throws InjectionException - { - runAlpha(methodName, req, extraArg, -1); - } - - private void runAlpha(String methodName, int req, int extraArg, int varIndex) throws InjectionException - { - final net.runelite.asm.pool.Field pixels = findDeobField(inject, "Rasterizer2D_pixels").getPoolField(); - Method meth = findStaticMethod(inject, methodName); - if (meth == null) - { - throw new InjectionException(methodName + " couldnt be found"); - } - - Code code = meth.getCode(); - Instructions ins = code.getInstructions(); - int added = 0; - - List indices = new ArrayList<>(); - for (Instruction i : ins.getInstructions()) - { - if (!(i instanceof IALoad) && !(i instanceof GetField) && !(i instanceof ALoad)) - { - continue; - } - - if (i instanceof GetField) - { - if (((GetField) i).getField().equals(pixels)) - { - indices.add(ins.getInstructions().indexOf(i)); - } - } - else if ((i instanceof ALoad) && varIndex >= 0 && ((LVTInstruction) i).getVariableIndex() == varIndex) - { - indices.add(ins.getInstructions().indexOf(i)); - } - else if (varIndex == -1) - { - indices.add(ins.getInstructions().indexOf(i)); - } - } - - if (indices.isEmpty()) - { - throw new InjectionException("Couldn't find hook location in " + methodName); - } - - int oldCount = count; - - for (int i : indices) - { - for (int codeIndex = i + added; codeIndex < ins.getInstructions().size(); codeIndex++) - { - if (ins.getInstructions().get(codeIndex) instanceof IAStore) - { - ins.getInstructions().set(codeIndex, new InvokeStatic(ins, drawAlpha)); - if (extraArg != -1) - { - ins.getInstructions().add(codeIndex, new ILoad(ins, extraArg)); - added++; - } - count++; - break; - } - } - } - - if (count - oldCount > req) - { - throw new InjectionException("Too many drawAlpha's were injected into " + methodName); - } - } - - private void runFontAlpha(String methodName, int req, int extraArg) throws InjectionException - { - Method meth = findStaticMethod(inject, methodName); - Instructions ins = meth.getCode().getInstructions(); - int varIdx = 0; // This is obviously dumb but I cba making this better - int added = 0; - - List indices = new ArrayList<>(); - for (Instruction i : meth.findLVTInstructionsForVariable(varIdx)) - { - indices.add(ins.getInstructions().indexOf(i)); - } - - if (indices.isEmpty()) - { - throw new InjectionException("Couldn't find hook location in " + methodName); - } - - int oldCount = count; - - for (int i : indices) - { - for (int codeIndex = i + added; codeIndex < ins.getInstructions().size(); codeIndex++) - { - if (ins.getInstructions().get(codeIndex) instanceof IAStore) - { - ins.getInstructions().set(codeIndex, new InvokeStatic(ins, drawAlpha)); - - ins.getInstructions().add(codeIndex, new ISub(ins, InstructionType.ISUB)); - ins.getInstructions().add(codeIndex, new ILoad(ins, extraArg)); - ins.getInstructions().add(codeIndex, new LDC(ins, 255)); - added++; - count++; - break; - } - } - } - - if (count - req != oldCount) - { - throw new InjectionException(req != oldCount ? req > count - oldCount ? "Not enough" : "Too many" : "No" + " drawAlpha's were injected into " + methodName); - } - } - - private void runVars() throws InjectionException - { - runOnMethodWithVar(rast3D, 0); - runOnMethodWithVar(rast3D2, 0); - // 36 expected - runOnMethodWithVar(font, 0); - // 5 expected - runOnMethodWithVar(sprite, 1); - runOnMethodWithVar(sprite2, 0); - runOnMethodWithVar(sprite3, 0); - runOnMethodWithVar(sprite4, 0); - // 12 expected - runOnMethodWithVar(indexedSprite, 0); - runOnMethodWithVar(indexedSprite2, 0); - // 6 expected - } - - private void run() throws InjectionException - { - final int startCount = count; // Cause you can't just count shit ty - final net.runelite.asm.pool.Field pixels = findDeobField(inject, "Rasterizer2D_pixels").getPoolField(); - - Execution ex = new Execution(inject.getVanilla()); - ex.populateInitialMethods(); - - Set done = new HashSet<>(); - ex.addExecutionVisitor((InstructionContext ic) -> - { - Instruction i = ic.getInstruction(); - Instructions ins = i.getInstructions(); - Code code = ins.getCode(); - Method method = code.getMethod(); - //logger.debug(i.toString()); - - if (!(i instanceof IAStore)) - { - return; - } - - if (!done.add(i)) - { - return; - } - - ArrayStore as = (ArrayStore) i; - Field fieldBeingSet = as.getMyField(ic); - - if (fieldBeingSet == null) - { - return; - } - - if (!fieldBeingSet.getPoolField().equals(pixels)) - { - return; - } - - int index = ins.getInstructions().indexOf(i); - - if (!(ins.getInstructions().get(index - 1) instanceof ILoad) && !ic.getPops().get(0).getValue().isUnknownOrNull()) - { - if ((int) ic.getPops().get(0).getValue().getValue() == 0) - { - logger.debug("Didn't add hook in method {}.{}. {} added, {} total, value 0", method.getClassFile().getClassName(), method.getName(), count - startCount, count); - return; - } - } - - ins.getInstructions().add(index, new IOr(ins, InstructionType.IOR)); // Add instructions backwards - ins.getInstructions().add(index, new LDC(ins, val)); - count++; - logger.debug("Added hook in method {}.{}. {} added, {} total", method.getClassFile().getClassName(), method.getName(), count - startCount, count); - }); - - ex.run(); - } - - private void runOnMethodWithVar(String meth, int varIndex) throws InjectionException - { - Method method = findStaticMethod(inject, meth); - - Instructions ins = method.getCode().getInstructions(); - List indices = new ArrayList<>(); - - for (Instruction i : method.findLVTInstructionsForVariable(varIndex)) - { - int index = ins.getInstructions().indexOf(i); - - assert index != -1; - assert ins.getInstructions().get(index + 1) instanceof ILoad; // Index in the array - - indices.add(index); - } - - int added = 0; - for (int i : indices) - { - for (int codeIndex = i + added; codeIndex < ins.getInstructions().size(); codeIndex++) - { - if (ins.getInstructions().get(codeIndex) instanceof IAStore) - { - added += 2; - count++; - ins.addInstruction(codeIndex, new IOr(ins, InstructionType.IOR)); // Add instructions backwards - ins.addInstruction(codeIndex, new LDC(ins, val)); - break; - } - } - } - - logger.info("Added {} instructions in {}. {} total", added >>> 1, meth, count); - } -}