upstream
This commit is contained in:
@@ -40,7 +40,7 @@ dependencies {
|
||||
implementation("com.google.guava:guava:29.0-jre")
|
||||
implementation(project(":deobfuscator"))
|
||||
|
||||
testCompileOnly("com.openosrs:injection-annotations:1.0")
|
||||
testCompileOnly(project(":injection-annotations"))
|
||||
testImplementation("junit:junit:4.13")
|
||||
}
|
||||
|
||||
|
||||
@@ -62,11 +62,10 @@ public interface InjectUtil
|
||||
/**
|
||||
* Finds a static method in deob and converts it to ob
|
||||
*
|
||||
* @param data InjectData instance
|
||||
* @param name The name of the method you want to find
|
||||
* @param data InjectData instance
|
||||
* @param name The name of the method you want to find
|
||||
* @param classHint The name of the class you expect the method to be in, or null
|
||||
* @param sig The signature the method has in deob, or null
|
||||
*
|
||||
* @param sig The signature the method has in deob, or null
|
||||
* @return The obfuscated version of the found method
|
||||
*/
|
||||
static Method findMethod(
|
||||
@@ -81,8 +80,8 @@ public interface InjectUtil
|
||||
/**
|
||||
* Finds a method in injectData's deobfuscated classes.
|
||||
*
|
||||
* @param data InjectData instance
|
||||
* @param name (Exported) method name
|
||||
* @param data InjectData instance
|
||||
* @param name (Exported) method name
|
||||
* @param classHint The (exported) name of a class you expect (or know) the method to be in, or null, if you're not sure
|
||||
* @throws InjectException If the hint class couldn't be found, or no method matching the settings was found
|
||||
*/
|
||||
@@ -90,7 +89,7 @@ public interface InjectUtil
|
||||
InjectData data,
|
||||
String name,
|
||||
@Nullable String classHint)
|
||||
throws InjectException
|
||||
throws InjectException
|
||||
{
|
||||
return findMethod(data, name, classHint, null, false, false);
|
||||
}
|
||||
@@ -98,13 +97,12 @@ public interface InjectUtil
|
||||
/**
|
||||
* Finds a method in injectData's deobfuscated classes.
|
||||
*
|
||||
* @param data InjectData instance
|
||||
* @param name (Exported) method name
|
||||
* @param classHint The (exported) name of a class you expect (or know) the method to be in, or null, if you're not sure
|
||||
* @param sig The deobfuscated methods' signature, or null, if you're unsure
|
||||
* @param notStatic If this is true, only check non-static methods. If classHint isn't null, check only subclasses
|
||||
* @param data InjectData instance
|
||||
* @param name (Exported) method name
|
||||
* @param classHint The (exported) name of a class you expect (or know) the method to be in, or null, if you're not sure
|
||||
* @param sig The deobfuscated methods' signature, or null, if you're unsure
|
||||
* @param notStatic If this is true, only check non-static methods. If classHint isn't null, check only subclasses
|
||||
* @param returnDeob If this is true, this method will return the deobfuscated method, instead of turning it into vanilla first
|
||||
*
|
||||
* @throws InjectException If the hint class couldn't be found, or no method matching the settings was found
|
||||
*/
|
||||
static Method findMethod(
|
||||
@@ -114,7 +112,7 @@ public interface InjectUtil
|
||||
@Nullable Predicate<Signature> sig,
|
||||
boolean notStatic,
|
||||
boolean returnDeob)
|
||||
throws InjectException
|
||||
throws InjectException
|
||||
{
|
||||
final ClassGroup deob = data.getDeobfuscated();
|
||||
if (classHint != null)
|
||||
@@ -125,23 +123,41 @@ public interface InjectUtil
|
||||
if (notStatic)
|
||||
{
|
||||
if (sig == null)
|
||||
{
|
||||
m = InjectUtil.findMethodDeep(cf, name, s -> true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m = InjectUtil.findMethodDeep(cf, name, sig);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m = cf.findMethod(name);
|
||||
}
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
return returnDeob ? m : data.toVanilla(m);
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassFile cf : deob)
|
||||
{
|
||||
for (Method m : cf.getMethods())
|
||||
{
|
||||
if (m.getName().equals(name))
|
||||
{
|
||||
if (!notStatic || !m.isStatic())
|
||||
{
|
||||
if (sig == null || sig.test(m.getDescriptor()))
|
||||
{
|
||||
return returnDeob ? m : data.toVanilla(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new InjectException(String.format("Couldn't find %s", name));
|
||||
}
|
||||
@@ -150,7 +166,9 @@ public interface InjectUtil
|
||||
{
|
||||
ClassFile clazz = group.findClass(name);
|
||||
if (clazz == null)
|
||||
{
|
||||
throw new InjectException("Hint class " + name + " doesn't exist");
|
||||
}
|
||||
|
||||
return clazz;
|
||||
}
|
||||
@@ -161,10 +179,18 @@ public interface InjectUtil
|
||||
static Method findMethodDeep(ClassFile clazz, String name, Predicate<Signature> type)
|
||||
{
|
||||
do
|
||||
{
|
||||
for (Method method : clazz.getMethods())
|
||||
{
|
||||
if (method.getName().equals(name))
|
||||
{
|
||||
if (type.test(method.getDescriptor()))
|
||||
{
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((clazz = clazz.getParent()) != null);
|
||||
|
||||
throw new InjectException(String.format("Method %s couldn't be found", name + type.toString()));
|
||||
@@ -172,7 +198,7 @@ public interface InjectUtil
|
||||
|
||||
/**
|
||||
* Fail-fast implementation of ClassGroup.findStaticField
|
||||
*
|
||||
* <p>
|
||||
* well...
|
||||
*/
|
||||
static Field findStaticField(ClassGroup group, String name)
|
||||
@@ -181,7 +207,9 @@ public interface InjectUtil
|
||||
{
|
||||
Field f = clazz.findField(name);
|
||||
if (f != null && f.isStatic())
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InjectException("Couldn't find static field " + name);
|
||||
@@ -190,11 +218,10 @@ public interface InjectUtil
|
||||
/**
|
||||
* Finds a static field in deob and converts it to ob
|
||||
*
|
||||
* @param data InjectData instance
|
||||
* @param name The name of the field you want to find
|
||||
* @param data InjectData instance
|
||||
* @param name The name of the field you want to find
|
||||
* @param classHint The name of the class you expect the field to be in, or null
|
||||
* @param type The type the method has in deob, or null
|
||||
*
|
||||
* @param type The type the method has in deob, or null
|
||||
* @return The obfuscated version of the found field
|
||||
*/
|
||||
static Field findStaticField(InjectData data, String name, String classHint, Type type)
|
||||
@@ -207,23 +234,35 @@ public interface InjectUtil
|
||||
ClassFile clazz = findClassOrThrow(deob, classHint);
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
field = clazz.findField(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
field = clazz.findField(name, type);
|
||||
}
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassFile clazz : deob)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
field = clazz.findField(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
field = clazz.findField(name, type);
|
||||
}
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InjectException(String.format("Static field %s doesn't exist", (type != null ? type + " " : "") + name));
|
||||
@@ -237,8 +276,12 @@ public interface InjectUtil
|
||||
Field f;
|
||||
|
||||
do
|
||||
{
|
||||
if ((f = clazz.findField(name)) != null)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
while ((clazz = clazz.getParent()) != null);
|
||||
|
||||
throw new InjectException("Couldn't find field " + name);
|
||||
@@ -259,12 +302,18 @@ public interface InjectUtil
|
||||
|
||||
field = clazz.findField(name);
|
||||
if (field != null)
|
||||
{
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassFile clazz : group)
|
||||
{
|
||||
if ((field = clazz.findField(name)) != null)
|
||||
{
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InjectException("Field " + name + " doesn't exist");
|
||||
}
|
||||
@@ -293,11 +342,15 @@ public interface InjectUtil
|
||||
static Type apiToDeob(InjectData data, Type api)
|
||||
{
|
||||
if (api.isPrimitive())
|
||||
{
|
||||
return api;
|
||||
}
|
||||
|
||||
final String internalName = api.getInternalName();
|
||||
if (internalName.startsWith(API_BASE))
|
||||
{
|
||||
return Type.getType("L" + api.getInternalName().substring(API_BASE.length()) + ";", api.getDimensions());
|
||||
}
|
||||
else if (internalName.startsWith(RL_API_BASE))
|
||||
{
|
||||
Class rlApiC = new Class(internalName);
|
||||
@@ -332,11 +385,15 @@ public interface InjectUtil
|
||||
static Type deobToVanilla(InjectData data, Type deobT)
|
||||
{
|
||||
if (deobT.isPrimitive())
|
||||
{
|
||||
return deobT;
|
||||
}
|
||||
|
||||
final ClassFile deobClass = data.getDeobfuscated().findClass(deobT.getInternalName());
|
||||
if (deobClass == null)
|
||||
{
|
||||
return deobT;
|
||||
}
|
||||
|
||||
return Type.getType("L" + data.toVanilla(deobClass).getName() + ";", deobT.getDimensions());
|
||||
}
|
||||
@@ -352,18 +409,24 @@ public interface InjectUtil
|
||||
List<Type> bb = b.getArguments();
|
||||
|
||||
if (aa.size() != bb.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < aa.size(); i++)
|
||||
{
|
||||
if (!aa.get(i).equals(bb.get(i)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the obfuscated name from something's annotations.
|
||||
*
|
||||
* <p>
|
||||
* If the annotation doesn't exist return the current name instead.
|
||||
*/
|
||||
static <T extends Annotated & Named> String getObfuscatedName(T from)
|
||||
@@ -387,7 +450,9 @@ public interface InjectUtil
|
||||
static Instruction createLoadForTypeIndex(Instructions instructions, Type type, int index)
|
||||
{
|
||||
if (type.getDimensions() > 0 || !type.isPrimitive())
|
||||
{
|
||||
return new ALoad(instructions, index);
|
||||
}
|
||||
|
||||
switch (type.toString())
|
||||
{
|
||||
@@ -414,7 +479,9 @@ public interface InjectUtil
|
||||
static Instruction createReturnForType(Instructions instructions, Type type)
|
||||
{
|
||||
if (!type.isPrimitive())
|
||||
{
|
||||
return new Return(instructions, InstructionType.ARETURN);
|
||||
}
|
||||
|
||||
switch (type.toString())
|
||||
{
|
||||
@@ -440,9 +507,13 @@ public interface InjectUtil
|
||||
static Instruction createInvokeFor(Instructions instructions, net.runelite.asm.pool.Method method, boolean isStatic)
|
||||
{
|
||||
if (isStatic)
|
||||
{
|
||||
return new InvokeStatic(instructions, method);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new InvokeVirtual(instructions, method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -463,9 +534,13 @@ public interface InjectUtil
|
||||
into.accept(new LDC(instrs, getter));
|
||||
|
||||
if (getter instanceof Integer)
|
||||
{
|
||||
into.accept(new IMul(instrs));
|
||||
}
|
||||
else if (getter instanceof Long)
|
||||
{
|
||||
into.accept(new LMul(instrs));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,7 +67,7 @@ public class Injection extends InjectData implements InjectTaskHandler
|
||||
|
||||
inject(new RSApiInjector(this));
|
||||
|
||||
inject(new DrawAfterWidgets(this));
|
||||
//inject(new DrawAfterWidgets(this));
|
||||
|
||||
inject(new ScriptVM(this));
|
||||
|
||||
@@ -107,7 +107,9 @@ public class Injection extends InjectData implements InjectTaskHandler
|
||||
log.lifecycle("{} {}", name, injector.getCompletionMsg());
|
||||
|
||||
if (injector instanceof Validator)
|
||||
{
|
||||
validate((Validator) injector);
|
||||
}
|
||||
}
|
||||
|
||||
private void validate(Validator validator)
|
||||
|
||||
@@ -35,7 +35,9 @@ public class InjectorValidator implements Validator
|
||||
for (Class intf : cf.getInterfaces())
|
||||
{
|
||||
if (!intf.getName().startsWith(API_BASE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RSApiClass apiC = rsApi.findClass(intf.getName());
|
||||
if (apiC == null)
|
||||
@@ -61,7 +63,9 @@ public class InjectorValidator implements Validator
|
||||
for (RSApiMethod apiMethod : apiClass)
|
||||
{
|
||||
if (apiMethod.isSynthetic() || apiMethod.isDefault())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clazz.findMethodDeep(apiMethod.getName(), apiMethod.getSignature()) == null)
|
||||
{
|
||||
|
||||
@@ -149,7 +149,7 @@ public abstract class InjectData
|
||||
|
||||
/**
|
||||
* Do something with all paired classes.
|
||||
*
|
||||
* <p>
|
||||
* Key = deobfuscated, Value = vanilla
|
||||
*/
|
||||
public void forEachPair(BiConsumer<ClassFile, ClassFile> action)
|
||||
|
||||
@@ -42,38 +42,40 @@ import net.runelite.deob.DeobAnnotations;
|
||||
public class CreateAnnotations extends AbstractInjector
|
||||
{
|
||||
|
||||
public CreateAnnotations(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
public CreateAnnotations(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
|
||||
public void inject()
|
||||
{
|
||||
for (final ClassFile deobClass : inject.getDeobfuscated())
|
||||
{
|
||||
injectFields(deobClass);
|
||||
injectMethods(deobClass);
|
||||
public void inject()
|
||||
{
|
||||
for (final ClassFile deobClass : inject.getDeobfuscated())
|
||||
{
|
||||
injectFields(deobClass);
|
||||
injectMethods(deobClass);
|
||||
|
||||
if (deobClass.getName().startsWith("class"))
|
||||
continue;
|
||||
if (deobClass.getName().startsWith("class"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
deobClass.addAnnotation(DeobAnnotations.IMPLEMENTS, deobClass.getName());
|
||||
}
|
||||
}
|
||||
deobClass.addAnnotation(DeobAnnotations.IMPLEMENTS, deobClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void injectFields(ClassFile deobClass)
|
||||
{
|
||||
for (Field deobField : deobClass.getFields())
|
||||
{
|
||||
deobField.addAnnotation(DeobAnnotations.EXPORT, deobField.getName());
|
||||
}
|
||||
}
|
||||
private void injectFields(ClassFile deobClass)
|
||||
{
|
||||
for (Field deobField : deobClass.getFields())
|
||||
{
|
||||
deobField.addAnnotation(DeobAnnotations.EXPORT, deobField.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void injectMethods(ClassFile deobClass)
|
||||
{
|
||||
for (Method deobMethod : deobClass.getMethods())
|
||||
{
|
||||
deobMethod.addAnnotation(DeobAnnotations.EXPORT, deobMethod.getName());
|
||||
}
|
||||
}
|
||||
private void injectMethods(ClassFile deobClass)
|
||||
{
|
||||
for (Method deobMethod : deobClass.getMethods())
|
||||
{
|
||||
deobMethod.addAnnotation(DeobAnnotations.EXPORT, deobMethod.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,9 @@ public class InjectConstruct extends AbstractInjector
|
||||
{
|
||||
Annotation construct = apiMethod.findAnnotation(CONSTRUCT);
|
||||
if (construct == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final Method method = apiMethod.getMethod();
|
||||
final Class clazz = method.getClazz();
|
||||
@@ -103,7 +105,9 @@ public class InjectConstruct extends AbstractInjector
|
||||
|
||||
final net.runelite.asm.Method constructor = classToConstruct.findMethod("<init>", constr);
|
||||
if (constructor == null)
|
||||
{
|
||||
throw new InjectException("Unable to find constructor for " + classToConstruct.getName() + ".<init>" + constr);
|
||||
}
|
||||
|
||||
|
||||
net.runelite.asm.Method setterMethod = new net.runelite.asm.Method(targetClass, apiMethod.getName(), apiMethod.getType());
|
||||
|
||||
@@ -86,7 +86,9 @@ public class InjectHook extends AbstractInjector
|
||||
public void inject()
|
||||
{
|
||||
for (Map.Entry<Provider<ClassFile>, List<ClassFile>> entry : mixinTargets.entrySet())
|
||||
{
|
||||
injectMethods(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
injectHooks();
|
||||
|
||||
@@ -103,7 +105,9 @@ public class InjectHook extends AbstractInjector
|
||||
{
|
||||
final Annotation fieldHook = mixinMethod.findAnnotation(FIELDHOOK);
|
||||
if (fieldHook == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final String hookName = fieldHook.getValueString();
|
||||
final boolean before = isBefore(fieldHook);
|
||||
@@ -141,7 +145,7 @@ public class InjectHook extends AbstractInjector
|
||||
Set<Instruction> doneIh = new HashSet<>();
|
||||
|
||||
e.addExecutionVisitor((
|
||||
InstructionContext ic) ->
|
||||
InstructionContext ic) ->
|
||||
{
|
||||
Instruction i = ic.getInstruction();
|
||||
Instructions ins = i.getInstructions();
|
||||
@@ -149,23 +153,33 @@ public class InjectHook extends AbstractInjector
|
||||
Method method = code.getMethod();
|
||||
|
||||
if (method.getName().equals(CLINIT))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(i instanceof SetFieldInstruction))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!done.add(i))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetFieldInstruction sfi = (SetFieldInstruction) i;
|
||||
Field fieldBeingSet = sfi.getMyField();
|
||||
|
||||
if (fieldBeingSet == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HookInfo hookInfo = hooked.get(fieldBeingSet);
|
||||
if (hookInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
log.trace("Found injection location for hook {} at instruction {}", hookInfo.method.getName(), sfi);
|
||||
++injectedHooks;
|
||||
@@ -174,7 +188,9 @@ public class InjectHook extends AbstractInjector
|
||||
|
||||
StackContext objectStackContext = null;
|
||||
if (sfi instanceof PutField)
|
||||
{
|
||||
objectStackContext = ic.getPops().get(1);
|
||||
}
|
||||
|
||||
int idx = ins.getInstructions().indexOf(sfi);
|
||||
assert idx != -1;
|
||||
@@ -182,10 +198,14 @@ public class InjectHook extends AbstractInjector
|
||||
try
|
||||
{
|
||||
if (hookInfo.before)
|
||||
{
|
||||
injectCallbackBefore(ins, idx, hookInfo, null, objectStackContext, value);
|
||||
}
|
||||
else
|
||||
// idx + 1 to insert after the set
|
||||
// idx + 1 to insert after the set
|
||||
{
|
||||
injectCallback(ins, idx + 1, hookInfo, null, objectStackContext);
|
||||
}
|
||||
}
|
||||
catch (InjectException ex)
|
||||
{
|
||||
@@ -206,23 +226,33 @@ public class InjectHook extends AbstractInjector
|
||||
Method method = code.getMethod();
|
||||
|
||||
if (method.getName().equals(CLINIT))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(i instanceof ArrayStore))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!doneIh.add(i))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayStore as = (ArrayStore) i;
|
||||
|
||||
Field fieldBeingSet = as.getMyField(ic);
|
||||
if (fieldBeingSet == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HookInfo hookInfo = hooked.get(fieldBeingSet);
|
||||
if (hookInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StackContext value = ic.getPops().get(0);
|
||||
StackContext index = ic.getPops().get(1);
|
||||
@@ -232,7 +262,9 @@ public class InjectHook extends AbstractInjector
|
||||
|
||||
StackContext objectStackContext = null;
|
||||
if (arrayReferencePushed.getInstruction().getType() == InstructionType.GETFIELD)
|
||||
{
|
||||
objectStackContext = arrayReferencePushed.getPops().get(0);
|
||||
}
|
||||
|
||||
// inject hook after 'i'
|
||||
log.debug("[DEBUG] Found array injection location for hook {} at instruction {}", hookInfo.method.getName(), i);
|
||||
@@ -244,9 +276,13 @@ public class InjectHook extends AbstractInjector
|
||||
try
|
||||
{
|
||||
if (hookInfo.before)
|
||||
{
|
||||
injectCallbackBefore(ins, idx, hookInfo, index, objectStackContext, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
injectCallback(ins, idx + 1, hookInfo, index, objectStackContext);
|
||||
}
|
||||
}
|
||||
catch (InjectException ex)
|
||||
{
|
||||
@@ -265,7 +301,9 @@ public class InjectHook extends AbstractInjector
|
||||
if (!hookInfo.method.isStatic())
|
||||
{
|
||||
if (object == null)
|
||||
{
|
||||
throw new InjectException("null object");
|
||||
}
|
||||
|
||||
ins.getInstructions().add(idx++, new Dup(ins)); // dup value
|
||||
idx = recursivelyPush(ins, idx, object);
|
||||
@@ -313,7 +351,9 @@ public class InjectHook extends AbstractInjector
|
||||
}
|
||||
|
||||
for (StackContext s : Lists.reverse(ctx.getPops()))
|
||||
{
|
||||
idx = recursivelyPush(ins, idx, s);
|
||||
}
|
||||
|
||||
ins.getInstructions().add(idx++, ctx.getInstruction().clone());
|
||||
return idx;
|
||||
@@ -324,15 +364,21 @@ public class InjectHook extends AbstractInjector
|
||||
if (!hookInfo.method.isStatic())
|
||||
{
|
||||
if (objectPusher == null)
|
||||
{
|
||||
throw new InjectException("Null object pusher");
|
||||
}
|
||||
|
||||
idx = recursivelyPush(ins, idx, objectPusher);
|
||||
}
|
||||
|
||||
if (index != null)
|
||||
{
|
||||
idx = recursivelyPush(ins, idx, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
ins.getInstructions().add(idx++, new LDC(ins, -1));
|
||||
}
|
||||
|
||||
Instruction invoke = hookInfo.getInvoke(ins);
|
||||
ins.getInstructions().add(idx, invoke);
|
||||
|
||||
@@ -65,7 +65,9 @@ public class InjectHookMethod extends AbstractInjector
|
||||
public void inject()
|
||||
{
|
||||
for (Map.Entry<Provider<ClassFile>, List<ClassFile>> entry : mixinTargets.entrySet())
|
||||
{
|
||||
injectMethods(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
log.info("[INFO] Injected {} method hooks", injected);
|
||||
}
|
||||
@@ -80,10 +82,14 @@ public class InjectHookMethod extends AbstractInjector
|
||||
{
|
||||
final Annotation methodHook = mixinMethod.findAnnotation(METHODHOOK);
|
||||
if (methodHook == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mixinMethod.getDescriptor().isVoid())
|
||||
{
|
||||
throw new InjectException("Method hook " + mixinMethod.getPoolMethod() + " doesn't have void return type");
|
||||
}
|
||||
|
||||
final String hookName = methodHook.getValueString();
|
||||
final boolean end = isEnd(methodHook);
|
||||
@@ -116,8 +122,12 @@ public class InjectHookMethod extends AbstractInjector
|
||||
{
|
||||
it = ins.listIterator(ins.size());
|
||||
while (it.hasPrevious())
|
||||
{
|
||||
if (it.previous() instanceof ReturnInstruction)
|
||||
{
|
||||
insertVoke(method, hookMethod, it);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -126,8 +136,12 @@ public class InjectHookMethod extends AbstractInjector
|
||||
if (method.getName().equals("<init>"))
|
||||
{
|
||||
while (it.hasNext())
|
||||
{
|
||||
if (it.next() instanceof InvokeSpecial)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert it.hasNext() : "Constructor without invokespecial";
|
||||
}
|
||||
@@ -141,7 +155,9 @@ public class InjectHookMethod extends AbstractInjector
|
||||
int varIdx = 0;
|
||||
|
||||
if (!method.isStatic())
|
||||
{
|
||||
iterator.add(new ALoad(instructions, varIdx++));
|
||||
}
|
||||
|
||||
for (Type type : hookMethod.getType().getArguments())
|
||||
{
|
||||
|
||||
@@ -36,7 +36,9 @@ public class InterfaceInjector extends AbstractInjector
|
||||
final String impls = DeobAnnotations.getImplements(deobCf);
|
||||
|
||||
if (impls == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final String fullName = API_BASE + impls;
|
||||
if (!inject.getRsApi().hasClass(fullName))
|
||||
|
||||
@@ -179,13 +179,19 @@ public class MixinInjector extends AbstractInjector
|
||||
copy.setValue(field.getValue());
|
||||
|
||||
for (Map.Entry<Type, Annotation> e : field.getAnnotations().entrySet())
|
||||
{
|
||||
if (!e.getKey().toString().startsWith("Lnet/runelite/api/mixins"))
|
||||
{
|
||||
copy.addAnnotation(e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
targetClass.addField(copy);
|
||||
|
||||
if (injectedFields.containsKey(field.getName()) && !ASSERTION_FIELD.equals(field.getName()))
|
||||
{
|
||||
throw new InjectException("Duplicate field: " + field.getName());
|
||||
}
|
||||
|
||||
injectedFields.put(field.getName(), copy);
|
||||
}
|
||||
@@ -207,10 +213,14 @@ public class MixinInjector extends AbstractInjector
|
||||
Annotation shadow = field.findAnnotation(SHADOW);
|
||||
|
||||
if (shadow == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!field.isStatic())
|
||||
{
|
||||
throw new InjectException("Shadowed fields must be static");
|
||||
}
|
||||
|
||||
String shadowed = shadow.getValueString();
|
||||
|
||||
@@ -226,7 +236,9 @@ public class MixinInjector extends AbstractInjector
|
||||
}
|
||||
|
||||
if ((targetField.getAccessFlags() & Opcodes.ACC_PRIVATE) != 0)
|
||||
{
|
||||
throw new InjectException("Shadowed fields can't be private");
|
||||
}
|
||||
|
||||
shadowFields.put(
|
||||
field.getPoolField(),
|
||||
@@ -249,7 +261,9 @@ public class MixinInjector extends AbstractInjector
|
||||
{
|
||||
Annotation copyA = mixinMethod.findAnnotation(COPY);
|
||||
if (copyA == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
String copiedName = copyA.getValueString();
|
||||
|
||||
Signature deobSig = InjectUtil.apiToDeob(inject, mixinMethod.getDescriptor());
|
||||
@@ -258,13 +272,17 @@ public class MixinInjector extends AbstractInjector
|
||||
Method deobSourceMethod = InjectUtil.findMethod(inject, copiedName, inject.toDeob(targetClass.getName()).getName(), deobSig::equals, notStat, true);
|
||||
|
||||
if (mixinMethod.isStatic() != deobSourceMethod.isStatic())
|
||||
{
|
||||
throw new InjectException("Mixin method " + mixinMethod + " should be " + (deobSourceMethod.isStatic() ? "static" : "non-static"));
|
||||
}
|
||||
|
||||
// The actual method we're copying, including code etc
|
||||
Method sourceMethod = inject.toVanilla(deobSourceMethod);
|
||||
|
||||
if (mixinMethod.getDescriptor().size() > sourceMethod.getDescriptor().size())
|
||||
{
|
||||
throw new InjectException("Mixin methods cannot have more parameters than their corresponding ob method");
|
||||
}
|
||||
|
||||
Method copy = new Method(targetClass, "copy$" + copiedName, sourceMethod.getDescriptor());
|
||||
moveCode(copy, sourceMethod.getCode());
|
||||
@@ -272,7 +290,9 @@ public class MixinInjector extends AbstractInjector
|
||||
copy.setPublic();
|
||||
copy.getExceptions().getExceptions().addAll(sourceMethod.getExceptions().getExceptions());
|
||||
for (var a : sourceMethod.getAnnotations().values())
|
||||
{
|
||||
copy.addAnnotation(a);
|
||||
}
|
||||
targetClass.addMethod(copy);
|
||||
++copied;
|
||||
|
||||
@@ -280,7 +300,7 @@ public class MixinInjector extends AbstractInjector
|
||||
* If the desc for the mixin method and the desc for the ob method
|
||||
* are the same in length, assume that the mixin method is taking
|
||||
* care of the garbage parameter itself.
|
||||
*/
|
||||
*/
|
||||
boolean hasGarbageValue = mixinMethod.getDescriptor().size() != sourceMethod.getDescriptor().size()
|
||||
&& deobSourceMethod.getDescriptor().size() < copy.getDescriptor().size();
|
||||
|
||||
@@ -298,7 +318,9 @@ public class MixinInjector extends AbstractInjector
|
||||
if ((hasInject && isInit) || isClinit)
|
||||
{
|
||||
if (!"()V".equals(mixinMethod.getDescriptor().toString()))
|
||||
{
|
||||
throw new InjectException("Injected constructors cannot have arguments");
|
||||
}
|
||||
|
||||
Method[] originalMethods = targetClass.getMethods().stream()
|
||||
.filter(m -> m.getName().equals(mixinMethod.getName()))
|
||||
@@ -309,11 +331,15 @@ public class MixinInjector extends AbstractInjector
|
||||
// If there isn't a <clinit> already just inject ours, otherwise rename it
|
||||
// This is always true for <init>
|
||||
if (originalMethods.length > 0)
|
||||
{
|
||||
name = "rl$$" + (isInit ? "init" : "clinit");
|
||||
}
|
||||
|
||||
String numberlessName = name;
|
||||
for (int i = 1; targetClass.findMethod(name, mixinMethod.getDescriptor()) != null; i++)
|
||||
{
|
||||
name = numberlessName + i;
|
||||
}
|
||||
|
||||
Method copy = new Method(targetClass, name, mixinMethod.getDescriptor());
|
||||
moveCode(copy, mixinMethod.getCode());
|
||||
@@ -337,7 +363,9 @@ public class MixinInjector extends AbstractInjector
|
||||
int pops = invoke.getMethod().getType().getArguments().size() + 1;
|
||||
|
||||
for (int i = 0; i < pops; i++)
|
||||
{
|
||||
listIter.add(new Pop(instructions));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -503,11 +531,15 @@ public class MixinInjector extends AbstractInjector
|
||||
|
||||
// Update instructions for each instruction
|
||||
for (Instruction i : newCode.getInstructions())
|
||||
{
|
||||
i.setInstructions(newCode.getInstructions());
|
||||
}
|
||||
|
||||
newCode.getExceptions().getExceptions().addAll(sourceCode.getExceptions().getExceptions());
|
||||
for (net.runelite.asm.attributes.code.Exception e : newCode.getExceptions().getExceptions())
|
||||
{
|
||||
e.setExceptions(newCode.getExceptions());
|
||||
}
|
||||
|
||||
targetMethod.setCode(newCode);
|
||||
}
|
||||
@@ -598,7 +630,9 @@ public class MixinInjector extends AbstractInjector
|
||||
PushConstantInstruction pi = (PushConstantInstruction) i;
|
||||
|
||||
if (mixinCf.getPoolClass().equals(pi.getConstant()))
|
||||
{
|
||||
pi.setConstant(cf.getPoolClass());
|
||||
}
|
||||
}
|
||||
|
||||
verify(mixinCf, i);
|
||||
@@ -614,11 +648,15 @@ public class MixinInjector extends AbstractInjector
|
||||
if (fi.getField().getClazz().getName().equals(mixinCf.getName()))
|
||||
{
|
||||
if (i instanceof PutField || i instanceof GetField)
|
||||
{
|
||||
throw new InjectException("Access to non static member field of mixin");
|
||||
}
|
||||
|
||||
Field field = fi.getMyField();
|
||||
if (field != null && !field.isPublic())
|
||||
{
|
||||
throw new InjectException("Static access to non public field " + field);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (i instanceof InvokeStatic)
|
||||
@@ -627,12 +665,16 @@ public class MixinInjector extends AbstractInjector
|
||||
|
||||
if (is.getMethod().getClazz() != mixinCf.getPoolClass()
|
||||
&& is.getMethod().getClazz().getName().startsWith(MIXIN_BASE))
|
||||
{
|
||||
throw new InjectException("Invoking static methods of other mixins is not supported");
|
||||
}
|
||||
}
|
||||
else if (i instanceof InvokeDynamic)
|
||||
// RS classes don't verify under java 7+ due to the
|
||||
// super() invokespecial being inside of a try{}
|
||||
// RS classes don't verify under java 7+ due to the
|
||||
// super() invokespecial being inside of a try{}
|
||||
{
|
||||
throw new InjectException("Injected bytecode must be Java 6 compatible");
|
||||
}
|
||||
}
|
||||
|
||||
private Method findDeobMatching(ClassFile deobClass, Method mixinMethod, String deobName)
|
||||
@@ -642,18 +684,26 @@ public class MixinInjector extends AbstractInjector
|
||||
for (Method method : deobClass.getMethods())
|
||||
{
|
||||
if (!deobName.equals(method.getName()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InjectUtil.apiToDeobSigEquals(inject, method.getDescriptor(), mixinMethod.getDescriptor()))
|
||||
{
|
||||
matching.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
if (matching.size() > 1)
|
||||
// this happens when it has found several deob methods for some mixin method,
|
||||
// to get rid of the error, refine your search by making your mixin method have more parameters
|
||||
// this happens when it has found several deob methods for some mixin method,
|
||||
// to get rid of the error, refine your search by making your mixin method have more parameters
|
||||
{
|
||||
throw new InjectException("There are several matching methods when there should only be one");
|
||||
}
|
||||
else if (matching.size() == 1)
|
||||
{
|
||||
return matching.get(0);
|
||||
}
|
||||
|
||||
return inject.getDeobfuscated().findStaticMethod(deobName);
|
||||
}
|
||||
@@ -695,15 +745,17 @@ public class MixinInjector extends AbstractInjector
|
||||
@Value
|
||||
private static class CopiedMethod
|
||||
{
|
||||
@Nonnull Method copy;
|
||||
@Nullable Integer garbage;
|
||||
@Nonnull
|
||||
Method copy;
|
||||
@Nullable Integer garbage;
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class ShadowField
|
||||
{
|
||||
@Nonnull Field targetField;
|
||||
@Nullable Number obfuscatedGetter;
|
||||
@Nonnull
|
||||
Field targetField;
|
||||
@Nullable Number obfuscatedGetter;
|
||||
}
|
||||
|
||||
private static Provider<ClassFile> mixinProvider(ClassFile mixin)
|
||||
@@ -716,7 +768,9 @@ public class MixinInjector extends AbstractInjector
|
||||
public ClassFile get()
|
||||
{
|
||||
if (bytes != null)
|
||||
{
|
||||
return JarUtil.loadClass(bytes);
|
||||
}
|
||||
|
||||
bytes = JarUtil.writeClass(mixin.getGroup(), mixin);
|
||||
return mixin;
|
||||
|
||||
@@ -84,7 +84,9 @@ public class RSApiInjector extends AbstractInjector
|
||||
final List<RSApiMethod> matching = findImportsFor(deobField, deobField.isStatic(), implementingClass);
|
||||
|
||||
if (matching == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final Type deobType = deobField.getType();
|
||||
|
||||
@@ -153,7 +155,9 @@ public class RSApiInjector extends AbstractInjector
|
||||
final Number getter = DeobAnnotations.getObfuscatedGetter(deobField);
|
||||
|
||||
if (deobField.isStatic() != vanillaField.isStatic()) // Can this even happen
|
||||
{
|
||||
throw new InjectException("Something went horribly wrong, and this should honestly never happen, but you never know. Btw it's the static-ness");
|
||||
}
|
||||
|
||||
inject(matching, deobField, vanillaField, getter);
|
||||
}
|
||||
@@ -166,7 +170,9 @@ public class RSApiInjector extends AbstractInjector
|
||||
final List<RSApiMethod> matching = findImportsFor(deobMethod, deobMethod.isStatic(), implementingClass);
|
||||
|
||||
if (matching == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final Signature deobSig = deobMethod.getDescriptor();
|
||||
|
||||
@@ -211,7 +217,9 @@ public class RSApiInjector extends AbstractInjector
|
||||
apiMethod.setInjected(true);
|
||||
}
|
||||
else if (matching.size() != 0)
|
||||
{
|
||||
throw new InjectException("Multiple api imports matching method " + deobMethod.getPoolMethod());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +233,9 @@ public class RSApiInjector extends AbstractInjector
|
||||
matched.removeIf(RSApiMethod::isInjected);
|
||||
|
||||
if (matched.size() > 2)
|
||||
{
|
||||
throw new InjectException("More than 2 imported api methods for field " + deobField.getPoolField());
|
||||
}
|
||||
|
||||
final Field vanillaField = inject.toVanilla(deobField);
|
||||
final Number getter = DeobAnnotations.getObfuscatedGetter(deobField);
|
||||
@@ -238,7 +248,9 @@ public class RSApiInjector extends AbstractInjector
|
||||
{
|
||||
final String exportedName = InjectUtil.getExportedName(object);
|
||||
if (exportedName == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<RSApiMethod> matching = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -271,10 +271,12 @@ public class DrawAfterWidgets extends AbstractInjector
|
||||
for (Field f : c.getFields())
|
||||
{
|
||||
if (f.isStatic())
|
||||
{
|
||||
if (f.getName().equals(s))
|
||||
{
|
||||
return inject.toVanilla(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -287,10 +289,12 @@ public class DrawAfterWidgets extends AbstractInjector
|
||||
for (Field f : c.getFields())
|
||||
{
|
||||
if (!f.isStatic())
|
||||
{
|
||||
if (f.getName().equals(s))
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -87,7 +87,9 @@ public class DrawMenu extends AbstractInjector
|
||||
{
|
||||
Instruction instruction = ic.getInstruction();
|
||||
if (!(instruction instanceof GetStatic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (((GetStatic) instruction).getField().equals(isMenuOpen))
|
||||
{
|
||||
@@ -100,25 +102,35 @@ public class DrawMenu extends AbstractInjector
|
||||
// If the popper is a IfNe the label it's pointing to is the drawMenu one and topLeft is directly after it
|
||||
// else it's the other way around, obviously
|
||||
if (isMenuOpenPopI instanceof IfNe)
|
||||
{
|
||||
injectInvokeAfter = ((IfNe) isMenuOpenPopI).getTo();
|
||||
}
|
||||
else
|
||||
{
|
||||
injectInvokeAfter = isMenuOpenPopI;
|
||||
}
|
||||
}
|
||||
else if (((GetStatic) instruction).getField().equals(gameDrawMode))
|
||||
{
|
||||
List<Instruction> instrL = instruction.getInstructions().getInstructions();
|
||||
for (int i = instrL.indexOf(instruction); !(instruction instanceof Label); i--)
|
||||
{
|
||||
instruction = instrL.get(i);
|
||||
}
|
||||
|
||||
labelToJumpTo = (Label) instruction;
|
||||
}
|
||||
|
||||
if (injectInvokeAfter != null && labelToJumpTo != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (injectInvokeAfter == null || labelToJumpTo == null)
|
||||
{
|
||||
throw new InjectException("Couldn't find the right location for DrawMenu to inject");
|
||||
}
|
||||
|
||||
final Instructions instrs = mc.getMethod().getCode().getInstructions();
|
||||
int idx = instrs.getInstructions().indexOf(injectInvokeAfter);
|
||||
|
||||
@@ -49,12 +49,16 @@ public class Occluder extends AbstractInjector
|
||||
Instruction i = it.next();
|
||||
|
||||
if (!(i instanceof BiPush))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean shouldChange = (byte) ((BiPush) i).getConstant() == OLDVALUE;
|
||||
|
||||
if (!shouldChange)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
replaced++;
|
||||
|
||||
@@ -64,6 +68,8 @@ public class Occluder extends AbstractInjector
|
||||
}
|
||||
|
||||
if (replaced != 10)
|
||||
{
|
||||
throw new InjectException("Only found " + replaced + " 25's to replace in occlude instead of expected 10");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,9 @@ public class RasterizerAlpha extends AbstractInjector
|
||||
{
|
||||
Instructions instrs = getInstrs(mc);
|
||||
if (instrs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
int orCount = 0;
|
||||
@@ -84,14 +86,18 @@ public class RasterizerAlpha extends AbstractInjector
|
||||
{
|
||||
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);
|
||||
@@ -111,15 +117,21 @@ public class RasterizerAlpha extends AbstractInjector
|
||||
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();
|
||||
@@ -168,12 +180,16 @@ public class RasterizerAlpha extends AbstractInjector
|
||||
// If we're copying from the same field we don't have to apply extra alpha again
|
||||
if (colPushI instanceof IALoad
|
||||
&& isSameField(r2dPx, colPusher.getPops().get(1)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the value is 0, it's supposed to be transparent, not black
|
||||
if (colPushI instanceof PushConstantInstruction
|
||||
&& ((PushConstantInstruction) colPushI).getConstant().equals(0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// rasterPx[idx] = color | 0xff000000 (the | 0xff000000 is what's added)
|
||||
int storeIdx = instrs.getInstructions().indexOf(instruction);
|
||||
@@ -217,7 +233,9 @@ public class RasterizerAlpha extends AbstractInjector
|
||||
{
|
||||
Code c = mc.getMethod().getCode();
|
||||
if (c == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return c.getInstructions();
|
||||
}
|
||||
@@ -226,11 +244,15 @@ public class RasterizerAlpha extends AbstractInjector
|
||||
{
|
||||
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();
|
||||
|
||||
@@ -245,7 +267,9 @@ public class RasterizerAlpha extends AbstractInjector
|
||||
InstructionContext ic = resolveFieldThroughInvokes(array);
|
||||
|
||||
if (ic == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((GetFieldInstruction) ic.getInstruction()).getMyField() == f;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ public class RenderDraw extends AbstractInjector
|
||||
}
|
||||
|
||||
if (replaced != EXPECTED)
|
||||
{
|
||||
throw new InjectException("Didn't replace the expected amount of method calls");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,9 @@ public class InjectGetter
|
||||
public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter)
|
||||
{
|
||||
if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null)
|
||||
{
|
||||
throw new InjectException("Duplicate getter method " + apiMethod.getMethod().toString());
|
||||
}
|
||||
|
||||
final String name = apiMethod.getName();
|
||||
final Signature sig = apiMethod.getSignature();
|
||||
@@ -75,7 +77,9 @@ public class InjectGetter
|
||||
}
|
||||
|
||||
if (getter != null)
|
||||
{
|
||||
InjectUtil.injectObfuscatedGetter(getter, instructions, ins::add);
|
||||
}
|
||||
|
||||
ins.add(InjectUtil.createReturnForType(instructions, field.getType()));
|
||||
|
||||
|
||||
@@ -53,7 +53,9 @@ public class InjectSetter
|
||||
public static void inject(ClassFile targetClass, RSApiMethod apiMethod, Field field, Number getter)
|
||||
{
|
||||
if (targetClass.findMethod(apiMethod.getName(), apiMethod.getSignature()) != null)
|
||||
{
|
||||
throw new InjectException("Duplicate setter method " + apiMethod.getMethod().toString());
|
||||
}
|
||||
|
||||
final String name = apiMethod.getName();
|
||||
final Signature sig = apiMethod.getSignature();
|
||||
@@ -69,7 +71,9 @@ public class InjectSetter
|
||||
|
||||
// load this
|
||||
if (!field.isStatic())
|
||||
{
|
||||
ins.add(new ALoad(instructions, 0));
|
||||
}
|
||||
|
||||
// load argument
|
||||
final Type argumentType = sig.getTypeOfArg(0);
|
||||
@@ -85,12 +89,18 @@ public class InjectSetter
|
||||
}
|
||||
|
||||
if (getter != null)
|
||||
{
|
||||
InjectUtil.injectObfuscatedSetter(getter, instructions, ins::add);
|
||||
}
|
||||
|
||||
if (field.isStatic())
|
||||
{
|
||||
ins.add(new PutStatic(instructions, field));
|
||||
}
|
||||
else
|
||||
{
|
||||
ins.add(new PutField(instructions, field));
|
||||
}
|
||||
|
||||
ins.add(new VReturn(instructions));
|
||||
|
||||
|
||||
@@ -45,7 +45,9 @@ public class RSApi implements Iterable<RSApiClass>
|
||||
for (File file : classes)
|
||||
{
|
||||
if (!file.getName().startsWith("RS"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try (InputStream is = new FileInputStream(file))
|
||||
{
|
||||
@@ -72,7 +74,9 @@ public class RSApi implements Iterable<RSApiClass>
|
||||
final ImmutableMap.Builder<String, RSApiClass> builder = ImmutableMap.builder();
|
||||
|
||||
for (RSApiClass clazz : this)
|
||||
{
|
||||
builder.put(clazz.getName(), clazz);
|
||||
}
|
||||
|
||||
this.map = builder.build();
|
||||
|
||||
@@ -112,11 +116,17 @@ public class RSApi implements Iterable<RSApiClass>
|
||||
{
|
||||
RSApiClass clazz = findClass(interf.getName());
|
||||
if (clazz != null)
|
||||
{
|
||||
return clazz;
|
||||
}
|
||||
|
||||
for (RSApiClass apiC : this)
|
||||
{
|
||||
if (apiC.getInterfaces().contains(interf))
|
||||
{
|
||||
return apiC;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,9 @@ public class RSApiClass extends ClassVisitor implements Iterable<RSApiMethod>
|
||||
for (RSApiMethod method : this)
|
||||
{
|
||||
if (method.isSynthetic())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.findAnnotation(CONSTRUCT) != null)
|
||||
{
|
||||
@@ -56,10 +58,12 @@ public class RSApiClass extends ClassVisitor implements Iterable<RSApiMethod>
|
||||
|
||||
final Annotation imported = method.findAnnotation(IMPORT);
|
||||
if (imported != null)
|
||||
{
|
||||
imports.computeIfAbsent(
|
||||
imported.getValueString(),
|
||||
(str) -> new ArrayList<>()
|
||||
).add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +83,9 @@ public class RSApiClass extends ClassVisitor implements Iterable<RSApiMethod>
|
||||
{
|
||||
List<RSApiMethod> imported = imports.get(str);
|
||||
if (imported == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
to.addAll(imported);
|
||||
}
|
||||
@@ -95,7 +101,9 @@ public class RSApiClass extends ClassVisitor implements Iterable<RSApiMethod>
|
||||
clazz = new Class(name);
|
||||
|
||||
for (String s : interfaces)
|
||||
{
|
||||
this.interfaces.add(new Class(s));
|
||||
}
|
||||
}
|
||||
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
|
||||
|
||||
@@ -9,9 +9,7 @@ package com.openosrs.injector.rsapi;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.runelite.asm.Annotation;
|
||||
import net.runelite.asm.Named;
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
@CacheableTask
|
||||
abstract class Inject: DefaultTask() {
|
||||
abstract class Inject : DefaultTask() {
|
||||
@get:Nested
|
||||
abstract val extension: InjectExtension
|
||||
|
||||
|
||||
@@ -15,10 +15,13 @@ import org.gradle.api.tasks.PathSensitivity
|
||||
interface InjectExtension {
|
||||
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
||||
val vanilla: RegularFileProperty
|
||||
|
||||
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
||||
val rsclient: RegularFileProperty
|
||||
|
||||
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
||||
val mixins: RegularFileProperty
|
||||
|
||||
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
|
||||
val rsapi: RegularFileProperty
|
||||
}
|
||||
|
||||
@@ -10,19 +10,21 @@ package com.openosrs.injector
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
class InjectPlugin: Plugin<Project> {
|
||||
override fun apply(project: Project) { with(project) {
|
||||
val task = tasks.create("inject", Inject::class.java)
|
||||
task.output.convention { file("$buildDir/libs/$name-$version.jar") }
|
||||
class InjectPlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
with(project) {
|
||||
val task = tasks.create("inject", Inject::class.java)
|
||||
task.output.convention { file("$buildDir/libs/$name-$version.jar") }
|
||||
|
||||
artifacts {
|
||||
it.add("runtimeElements", task.output)
|
||||
artifacts {
|
||||
it.add("runtimeElements", task.output)
|
||||
}
|
||||
|
||||
tasks.getByName("assemble") {
|
||||
it.finalizedBy("inject")
|
||||
}
|
||||
|
||||
extensions.add(InjectExtension::class.java, "injector", task.extension)
|
||||
}
|
||||
|
||||
tasks.getByName("assemble") {
|
||||
it.finalizedBy("inject")
|
||||
}
|
||||
|
||||
extensions.add(InjectExtension::class.java, "injector", task.extension)
|
||||
}}
|
||||
}
|
||||
}
|
||||
@@ -283,12 +283,15 @@ public class MixinInjectorTest
|
||||
Instruction i;
|
||||
while (it.hasNext() &&
|
||||
!((i = it.next()) instanceof GetStatic &&
|
||||
((GetStatic) i).getField().getName().equals(gottenField)));
|
||||
((GetStatic) i).getField().getName().equals(gottenField)))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
return
|
||||
(i = it.next()) instanceof LDC &&
|
||||
((LDC) i).getConstantAsInt() == 1157381415 &&
|
||||
it.next() instanceof IMul;
|
||||
((LDC) i).getConstantAsInt() == 1157381415 &&
|
||||
it.next() instanceof IMul;
|
||||
}
|
||||
|
||||
private static ClassFile loadClass(Class<?> clazz)
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
|
||||
* 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 com.openosrs.injector.injectors.raw;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.openosrs.injector.TestInjection;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.rsapi.RSApi;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.ClassGroup;
|
||||
import net.runelite.deob.util.JarUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DrawAfterWidgetsTest
|
||||
{
|
||||
@Test
|
||||
public void testInjectDrawWidgetsRev160() throws Exception
|
||||
{
|
||||
// Rev 160 does not have the drawWidgets call inlined
|
||||
|
||||
ClassFile deobClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_deob160.class")));
|
||||
ClassFile deobRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_deob160.class")));
|
||||
|
||||
ClassGroup deob = new ClassGroup();
|
||||
deob.addClass(deobClient);
|
||||
deob.addClass(deobRasterizer);
|
||||
|
||||
ClassFile obClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_ob160.class")));
|
||||
ClassFile obRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_ob160.class")));
|
||||
|
||||
ClassGroup vanilla = new ClassGroup();
|
||||
vanilla.addClass(obClient);
|
||||
vanilla.addClass(obRasterizer);
|
||||
|
||||
InjectData inject = new TestInjection(vanilla, deob, new ClassGroup(), new RSApi());
|
||||
new DrawAfterWidgets(inject).inject();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInjectDrawWidgetsRev180() throws Exception
|
||||
{
|
||||
// Rev 180 has the drawWidgets call inlined
|
||||
|
||||
ClassFile deobClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_deob180.class")));
|
||||
ClassFile deobRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_deob180.class")));
|
||||
|
||||
ClassGroup deob = new ClassGroup();
|
||||
deob.addClass(deobClient);
|
||||
deob.addClass(deobRasterizer);
|
||||
|
||||
ClassFile obClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_ob180.class")));
|
||||
ClassFile obRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_ob180.class")));
|
||||
|
||||
ClassGroup vanilla = new ClassGroup();
|
||||
vanilla.addClass(obClient);
|
||||
vanilla.addClass(obRasterizer);
|
||||
|
||||
InjectData inject = new TestInjection(vanilla, deob, new ClassGroup(), new RSApi());
|
||||
new DrawAfterWidgets(inject).inject();
|
||||
}
|
||||
}
|
||||
@@ -36,9 +36,11 @@ public class SourceChangerTest
|
||||
new ClassReader(PACKAGE + "OldName").accept(vann, ClassReader.SKIP_FRAMES);
|
||||
|
||||
new SourceChanger(
|
||||
new InjectData(new ClassGroup(), new ClassGroup(), null, null) {
|
||||
new InjectData(new ClassGroup(), new ClassGroup(), null, null)
|
||||
{
|
||||
public void runChildInjector(Injector injector) throws InjectException
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachPair(BiConsumer<ClassFile, ClassFile> consumer)
|
||||
@@ -54,8 +56,8 @@ public class SourceChangerTest
|
||||
vann.getClassFile().accept(cw);
|
||||
|
||||
OldName obj = (OldName) MethodHandles.privateLookupIn(
|
||||
NewName.class,
|
||||
MethodHandles.lookup())
|
||||
NewName.class,
|
||||
MethodHandles.lookup())
|
||||
.defineClass(cw.toByteArray())
|
||||
.getDeclaredConstructor()
|
||||
.newInstance();
|
||||
|
||||
Reference in New Issue
Block a user