Merge pull request #1869 from Lucwousin/nice
Injector: Change rasterizer raw injector from depending on hardcoded values
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
*/
|
||||
package net.runelite.asm.attributes.code.instructions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import net.runelite.asm.ClassFile;
|
||||
@@ -86,7 +85,7 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<net.runelite.asm.Method> getMethods()
|
||||
{
|
||||
return myMethod != null ? Arrays.asList(myMethod) : Collections.EMPTY_LIST;
|
||||
return myMethod != null ? Collections.singletonList(myMethod) : Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -70,10 +70,9 @@ public class MethodContext
|
||||
return contexts.get(i);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<InstructionContext> getInstructionContexts()
|
||||
{
|
||||
return (Collection) contexts.values();
|
||||
return contexts.values();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Lucas <https://github.com/Lucwousin>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -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<Integer> 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<Integer> 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<Integer> 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<Instruction> 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<Integer> 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user