Compare commits
10 Commits
923acf99e6
...
ccb7c86741
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccb7c86741 | ||
|
|
dcfe05d2af | ||
|
|
318b03ec58 | ||
|
|
e7dc8fd2c9 | ||
|
|
50f415e8ba | ||
|
|
313bee84e6 | ||
|
|
f714312bcc | ||
|
|
91972a7ed3 | ||
|
|
a1c9346233 | ||
|
|
c984198dd2 |
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Lucas <https://github.com/Lucwousin>
|
||||
* 2022, Owain van Brakel <https://github.com/Owain94>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
@@ -9,16 +10,14 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
id("java-gradle-plugin")
|
||||
kotlin("jvm") version "1.3.72"
|
||||
kotlin("jvm") version "1.7.0"
|
||||
`maven-publish`
|
||||
id("com.github.ben-manes.versions") version "0.28.0"
|
||||
id("se.patrikerdes.use-latest-versions") version "0.2.14"
|
||||
}
|
||||
|
||||
val oprsver = "3.4.0"
|
||||
val oprsver = "4.31.1"
|
||||
|
||||
group = "com.openosrs"
|
||||
version = "1.1.5"
|
||||
version = "2.0.2"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@@ -31,19 +30,24 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.12")
|
||||
compileOnly("org.projectlombok:lombok:1.18.12")
|
||||
annotationProcessor(group = "org.projectlombok", name = "lombok", version = "1.18.20")
|
||||
compileOnly(group = "org.projectlombok", name = "lombok", version = "1.18.20")
|
||||
|
||||
implementation("org.ow2.asm:asm:8.0.1")
|
||||
implementation("org.ow2.asm:asm-util:8.0.1")
|
||||
implementation("org.jetbrains:annotations:19.0.0")
|
||||
implementation("com.google.guava:guava:29.0-jre")
|
||||
implementation(group = "org.ow2.asm", name = "asm", version = "9.0")
|
||||
implementation(group = "org.ow2.asm", name = "asm-util", version = "9.0")
|
||||
implementation(group = "org.jetbrains", name = "annotations", version = "22.0.0")
|
||||
implementation(group = "com.google.guava", name = "guava", version = "30.1.1-jre") {
|
||||
exclude(group = "com.google.code.findbugs", module = "jsr305")
|
||||
exclude(group = "com.google.errorprone", module = "error_prone_annotations")
|
||||
exclude(group = "com.google.j2objc", module = "j2objc-annotations")
|
||||
exclude(group = "org.codehaus.mojo", module = "animal-sniffer-annotations")
|
||||
}
|
||||
implementation("com.openosrs:deobfuscator:${oprsver}") {
|
||||
isTransitive = false
|
||||
}
|
||||
|
||||
testCompileOnly("com.openosrs:injection-annotations:1.0")
|
||||
testImplementation("junit:junit:4.13")
|
||||
testCompileOnly(group = "com.openosrs", name = "injection-annotations", version = "1.1")
|
||||
testImplementation(group = "junit", name = "junit", version = "4.12")
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
@@ -55,7 +59,7 @@ gradlePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
configure<JavaPluginConvention> {
|
||||
configure<JavaPluginExtension> {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector;
|
||||
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import static com.openosrs.injector.rsapi.RSApi.API_BASE;
|
||||
import static com.openosrs.injector.rsapi.RSApi.RL_API_BASE;
|
||||
import com.openosrs.injector.rsapi.RSApiClass;
|
||||
import com.openosrs.injector.rsapi.RSApiMethod;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -42,8 +45,6 @@ import net.runelite.asm.signature.Signature;
|
||||
import net.runelite.deob.DeobAnnotations;
|
||||
import net.runelite.deob.deobfuscators.arithmetic.DMath;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import static com.openosrs.injector.rsapi.RSApi.API_BASE;
|
||||
import static com.openosrs.injector.rsapi.RSApi.RL_API_BASE;
|
||||
|
||||
public interface InjectUtil
|
||||
{
|
||||
@@ -66,7 +67,6 @@ public interface InjectUtil
|
||||
* @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
|
||||
*
|
||||
* @return The obfuscated version of the found method
|
||||
*/
|
||||
static Method findMethod(
|
||||
@@ -104,7 +104,6 @@ public interface InjectUtil
|
||||
* @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(
|
||||
@@ -125,23 +124,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 = 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 +167,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 +180,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 +199,7 @@ public interface InjectUtil
|
||||
|
||||
/**
|
||||
* Fail-fast implementation of ClassGroup.findStaticField
|
||||
*
|
||||
* <p>
|
||||
* well...
|
||||
*/
|
||||
static Field findStaticField(ClassGroup group, String name)
|
||||
@@ -181,8 +208,10 @@ public interface InjectUtil
|
||||
{
|
||||
Field f = clazz.findField(name);
|
||||
if (f != null && f.isStatic())
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InjectException("Couldn't find static field " + name);
|
||||
}
|
||||
@@ -194,7 +223,6 @@ public interface InjectUtil
|
||||
* @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
|
||||
*
|
||||
* @return The obfuscated version of the found field
|
||||
*/
|
||||
static Field findStaticField(InjectData data, String name, String classHint, Type type)
|
||||
@@ -207,24 +235,36 @@ 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 +277,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 +303,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");
|
||||
}
|
||||
@@ -291,21 +341,33 @@ public interface InjectUtil
|
||||
}
|
||||
|
||||
static Type apiToDeob(InjectData data, Type api)
|
||||
{
|
||||
return apiToDeob(data, api, null);
|
||||
}
|
||||
|
||||
static Type apiToDeob(InjectData data, Type api, Type deobType)
|
||||
{
|
||||
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);
|
||||
RSApiClass highestKnown = data.getRsApi().withInterface(rlApiC);
|
||||
Set<RSApiClass> allClasses = data.getRsApi().withInterface(rlApiC);
|
||||
|
||||
// Cheeky unchecked exception
|
||||
assert highestKnown != null : "No rs api class implements rl api class " + rlApiC.toString();
|
||||
assert allClasses.size() > 0 : "No rs api class implements rl api class " + rlApiC;
|
||||
|
||||
if (allClasses.size() == 1)
|
||||
{
|
||||
RSApiClass highestKnown = allClasses.stream().findFirst().get();
|
||||
boolean changed;
|
||||
do
|
||||
{
|
||||
@@ -325,6 +387,17 @@ public interface InjectUtil
|
||||
|
||||
return apiToDeob(data, Type.getType(highestKnown.getName(), api.getDimensions()));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (RSApiClass rsApiClass : allClasses)
|
||||
{
|
||||
if (rsApiClass.getName().contains(deobType.getInternalName()))
|
||||
{
|
||||
return apiToDeob(data, Type.getType(rsApiClass.getName(), api.getDimensions()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return api;
|
||||
}
|
||||
@@ -332,11 +405,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 +429,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 +470,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 +499,9 @@ public interface InjectUtil
|
||||
static Instruction createReturnForType(Instructions instructions, Type type)
|
||||
{
|
||||
if (!type.isPrimitive())
|
||||
{
|
||||
return new Return(instructions, InstructionType.ARETURN);
|
||||
}
|
||||
|
||||
switch (type.toString())
|
||||
{
|
||||
@@ -440,10 +527,14 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Legit fuck annotations
|
||||
@@ -463,10 +554,14 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add IN FRONT of the put
|
||||
@@ -477,4 +572,27 @@ public interface InjectUtil
|
||||
{
|
||||
injectObfuscatedGetter(DMath.modInverse(getter), instrs, into);
|
||||
}
|
||||
|
||||
private static List<Type> findArgs(final String str, final List<Type> ret, final int from, final int to)
|
||||
{
|
||||
if (from >= to)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
int i = from;
|
||||
while (str.charAt(i) == '[')
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
if (str.charAt(i) == 'L')
|
||||
{
|
||||
i = str.indexOf(';', i);
|
||||
}
|
||||
|
||||
ret.add(new Type(str.substring(from, ++i)));
|
||||
|
||||
return findArgs(str, ret, i, to);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
*/
|
||||
package com.openosrs.injector;
|
||||
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injection.InjectTaskHandler;
|
||||
import com.openosrs.injector.injectors.CreateAnnotations;
|
||||
import com.openosrs.injector.injectors.InjectConstruct;
|
||||
import com.openosrs.injector.injectors.Injector;
|
||||
import com.openosrs.injector.injectors.InterfaceInjector;
|
||||
@@ -16,18 +18,27 @@ import com.openosrs.injector.injectors.MixinInjector;
|
||||
import com.openosrs.injector.injectors.RSApiInjector;
|
||||
import com.openosrs.injector.injectors.raw.AddPlayerToMenu;
|
||||
import com.openosrs.injector.injectors.raw.ClearColorBuffer;
|
||||
import com.openosrs.injector.injectors.raw.DrawAfterWidgets;
|
||||
import com.openosrs.injector.injectors.raw.CopyRuneLiteClasses;
|
||||
import com.openosrs.injector.injectors.raw.DrawMenu;
|
||||
import com.openosrs.injector.injectors.raw.GameDrawingMode;
|
||||
import com.openosrs.injector.injectors.raw.GraphicsObject;
|
||||
import com.openosrs.injector.injectors.raw.Occluder;
|
||||
import com.openosrs.injector.injectors.raw.RasterizerAlpha;
|
||||
import com.openosrs.injector.injectors.raw.RenderDraw;
|
||||
import com.openosrs.injector.injectors.raw.RuneLiteIterables;
|
||||
import com.openosrs.injector.injectors.raw.RuneliteMenuEntry;
|
||||
import com.openosrs.injector.injectors.raw.RuneliteObject;
|
||||
import com.openosrs.injector.injectors.raw.ScriptVM;
|
||||
import com.openosrs.injector.rsapi.RSApi;
|
||||
import com.openosrs.injector.transformers.InjectTransformer;
|
||||
import com.openosrs.injector.transformers.Java8Ifier;
|
||||
import com.openosrs.injector.transformers.SourceChanger;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import net.runelite.deob.util.JarUtil;
|
||||
import static net.runelite.deob.util.JarUtil.load;
|
||||
import org.gradle.api.file.FileTree;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.logging.Logging;
|
||||
@@ -35,21 +46,38 @@ import org.gradle.api.logging.Logging;
|
||||
public class Injection extends InjectData implements InjectTaskHandler
|
||||
{
|
||||
private static final Logger log = Logging.getLogger(Injection.class);
|
||||
public static boolean development = true;
|
||||
public static String skips = "";
|
||||
|
||||
public Injection(File vanilla, File rsclient, File mixins, FileTree rsapi) throws IOException
|
||||
public Injection(File vanilla, File rsclient, File mixins, FileTree rsapi, boolean development, String skip)
|
||||
{
|
||||
super(
|
||||
JarUtil.loadJar(vanilla),
|
||||
JarUtil.loadJar(rsclient),
|
||||
JarUtil.loadJar(mixins),
|
||||
load(vanilla),
|
||||
load(rsclient),
|
||||
load(mixins),
|
||||
new RSApi(rsapi)
|
||||
);
|
||||
|
||||
Injection.development = development;
|
||||
Injection.skips = skip;
|
||||
}
|
||||
|
||||
public void inject()
|
||||
{
|
||||
log.debug("[DEBUG] Starting injection");
|
||||
|
||||
transform(new Java8Ifier(this));
|
||||
|
||||
inject(new CreateAnnotations(this));
|
||||
|
||||
inject(new GraphicsObject(this));
|
||||
|
||||
inject(new CopyRuneLiteClasses(this));
|
||||
|
||||
inject(new RuneLiteIterables(this));
|
||||
|
||||
inject(new RuneliteObject(this));
|
||||
|
||||
inject(new InterfaceInjector(this));
|
||||
|
||||
inject(new RasterizerAlpha(this));
|
||||
@@ -64,7 +92,7 @@ public class Injection extends InjectData implements InjectTaskHandler
|
||||
|
||||
inject(new RSApiInjector(this));
|
||||
|
||||
inject(new DrawAfterWidgets(this));
|
||||
//inject(new DrawAfterWidgets(this));
|
||||
|
||||
inject(new ScriptVM(this));
|
||||
|
||||
@@ -77,35 +105,64 @@ public class Injection extends InjectData implements InjectTaskHandler
|
||||
|
||||
inject(new DrawMenu(this));
|
||||
|
||||
inject(new GameDrawingMode(this));
|
||||
|
||||
inject(new AddPlayerToMenu(this));
|
||||
|
||||
inject(new RuneliteMenuEntry(this));
|
||||
|
||||
validate(new InjectorValidator(this));
|
||||
|
||||
transform(new SourceChanger(this));
|
||||
}
|
||||
|
||||
public void save(File outputJar) throws IOException
|
||||
public void save(File outputJar)
|
||||
{
|
||||
log.info("[INFO] Saving jar to {}", outputJar.toString());
|
||||
|
||||
JarUtil.saveJar(this.getVanilla(), outputJar);
|
||||
JarUtil.save(this.getVanilla(), outputJar);
|
||||
}
|
||||
|
||||
public void hash(File output, File vanilla)
|
||||
{
|
||||
log.info("[INFO] Saving hash to {}", output.toString());
|
||||
|
||||
try
|
||||
{
|
||||
String hash = com.google.common.io.Files.asByteSource(vanilla).hash(Hashing.sha256()).toString();
|
||||
log.lifecycle("Writing vanilla hash: {}", hash);
|
||||
Files.write(output.toPath(), hash.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.lifecycle("Failed to write vanilla hash file");
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void inject(Injector injector)
|
||||
{
|
||||
final String name = injector.getName();
|
||||
|
||||
log.info("[INFO] Starting {}", name);
|
||||
|
||||
if (injector.shouldRun())
|
||||
{
|
||||
injector.start();
|
||||
|
||||
injector.inject();
|
||||
|
||||
log.lifecycle("{} {}", name, injector.getCompletionMsg());
|
||||
String completionMsg = injector.getCompletionMsg();
|
||||
|
||||
if (completionMsg != null)
|
||||
{
|
||||
log.lifecycle("{} {}", name, completionMsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (injector instanceof Validator)
|
||||
{
|
||||
validate((Validator) injector);
|
||||
}
|
||||
}
|
||||
|
||||
private void validate(Validator validator)
|
||||
{
|
||||
@@ -121,8 +178,6 @@ public class Injection extends InjectData implements InjectTaskHandler
|
||||
{
|
||||
final String name = transformer.getName();
|
||||
|
||||
log.info("[INFO] Starting {}", name);
|
||||
|
||||
transformer.transform();
|
||||
|
||||
log.lifecycle("{} {}", name, transformer.getCompletionMsg());
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector;
|
||||
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.rsapi.RSApi;
|
||||
import static com.openosrs.injector.rsapi.RSApi.API_BASE;
|
||||
import com.openosrs.injector.rsapi.RSApiClass;
|
||||
import com.openosrs.injector.rsapi.RSApiMethod;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -16,7 +17,6 @@ import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.pool.Class;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.logging.Logging;
|
||||
import static com.openosrs.injector.rsapi.RSApi.API_BASE;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class InjectorValidator implements 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,11 +63,13 @@ public class InjectorValidator implements Validator
|
||||
for (RSApiMethod apiMethod : apiClass)
|
||||
{
|
||||
if (apiMethod.isSynthetic() || apiMethod.isDefault())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clazz.findMethodDeep(apiMethod.getName(), apiMethod.getSignature()) == null)
|
||||
{
|
||||
log.warn("[WARN] Class {} implements interface {} but doesn't implement {}",
|
||||
log.error("[WARN] Class {} implements interface {} but doesn't implement {}",
|
||||
clazz.getPoolClass(), apiClass.getClazz(), apiMethod.getMethod());
|
||||
++missing;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector;
|
||||
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injection;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.openosrs.injector.InjectUtil;
|
||||
import com.openosrs.injector.injectors.Injector;
|
||||
import com.openosrs.injector.rsapi.RSApi;
|
||||
@@ -27,7 +26,7 @@ import net.runelite.asm.signature.Signature;
|
||||
*/
|
||||
public abstract class InjectData
|
||||
{
|
||||
public static final String HOOKS = "net/runelite/client/callback/Hooks";
|
||||
public static final String CALLBACKS = "net/runelite/api/hooks/Callbacks";
|
||||
|
||||
@Getter
|
||||
private final ClassGroup vanilla;
|
||||
@@ -41,10 +40,21 @@ public abstract class InjectData
|
||||
@Getter
|
||||
private final RSApi rsApi;
|
||||
|
||||
public InjectData(ClassGroup vanilla, ClassGroup deobfuscated, ClassGroup mixins, RSApi rsApi)
|
||||
{
|
||||
this.vanilla = vanilla;
|
||||
this.deobfuscated = deobfuscated;
|
||||
this.rsApi = rsApi;
|
||||
this.mixins = mixins;
|
||||
|
||||
initToVanilla();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deobfuscated ClassFiles -> Vanilla ClassFiles
|
||||
*/
|
||||
private final Map<ClassFile, ClassFile> toVanilla;
|
||||
@Getter
|
||||
private final Map<ClassFile, ClassFile> toVanilla = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Strings -> Deobfuscated ClassFiles
|
||||
@@ -52,26 +62,15 @@ public abstract class InjectData
|
||||
* - Obfuscated name
|
||||
* - RSApi implementing name
|
||||
*/
|
||||
private final Map<String, ClassFile> toDeob = new HashMap<>();
|
||||
|
||||
public InjectData(ClassGroup vanilla, ClassGroup deobfuscated, ClassGroup mixins, RSApi rsApi)
|
||||
{
|
||||
this.vanilla = vanilla;
|
||||
this.deobfuscated = deobfuscated;
|
||||
this.rsApi = rsApi;
|
||||
this.mixins = mixins;
|
||||
this.toVanilla = initToVanilla();
|
||||
}
|
||||
public final Map<String, ClassFile> toDeob = new HashMap<>();
|
||||
|
||||
public abstract void runChildInjector(Injector injector);
|
||||
|
||||
private Map<ClassFile, ClassFile> initToVanilla()
|
||||
public void initToVanilla()
|
||||
{
|
||||
ImmutableMap.Builder<ClassFile, ClassFile> toVanillaB = ImmutableMap.builder();
|
||||
|
||||
for (final ClassFile deobClass : deobfuscated)
|
||||
{
|
||||
if (deobClass.getName().startsWith("net/runelite/"))
|
||||
if (deobClass.getName().startsWith("net/runelite/") || deobClass.getName().startsWith("netscape"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -81,13 +80,14 @@ public abstract class InjectData
|
||||
{
|
||||
toDeob.put(obName, deobClass);
|
||||
|
||||
// Can't be null
|
||||
final ClassFile obClass = this.vanilla.findClass(obName);
|
||||
toVanillaB.put(deobClass, obClass);
|
||||
}
|
||||
}
|
||||
|
||||
return toVanillaB.build();
|
||||
if (obClass != null)
|
||||
{
|
||||
toVanilla.put(deobClass, obClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,6 +95,7 @@ public abstract class InjectData
|
||||
*/
|
||||
public ClassFile toVanilla(ClassFile deobClass)
|
||||
{
|
||||
|
||||
return toVanilla.get(deobClass);
|
||||
}
|
||||
|
||||
@@ -148,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)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
package com.openosrs.injector.injection;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Interface containing all the methods gradle needs to know about
|
||||
@@ -23,5 +22,10 @@ public interface InjectTaskHandler
|
||||
/**
|
||||
* Call this to save the injected jar to outputJar
|
||||
*/
|
||||
void save(File outputJar) throws IOException;
|
||||
void save(File outputJar);
|
||||
|
||||
/**
|
||||
* Call this to save the vanilla hash
|
||||
*/
|
||||
void hash(File outputFile, File vanilla);
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.openosrs.injector.Injection;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.gradle.api.logging.Logger;
|
||||
@@ -25,8 +26,13 @@ public abstract class AbstractInjector implements Injector
|
||||
stopwatch = Stopwatch.createStarted();
|
||||
}
|
||||
|
||||
public final String getCompletionMsg()
|
||||
public String getCompletionMsg()
|
||||
{
|
||||
return "finished in " + stopwatch.toString();
|
||||
}
|
||||
|
||||
public boolean shouldRun()
|
||||
{
|
||||
return !Injection.skips.contains(this.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Lucas <https://github.com/Lucwousin>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* 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;
|
||||
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.Field;
|
||||
import net.runelite.asm.Method;
|
||||
import net.runelite.deob.DeobAnnotations;
|
||||
|
||||
/*
|
||||
* This handles creating "virtual" annotations to clean up rs-client in the main project
|
||||
*/
|
||||
public class CreateAnnotations extends AbstractInjector
|
||||
{
|
||||
|
||||
public CreateAnnotations(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
|
||||
public void inject()
|
||||
{
|
||||
for (final ClassFile deobClass : inject.getDeobfuscated())
|
||||
{
|
||||
injectFields(deobClass);
|
||||
injectMethods(deobClass);
|
||||
|
||||
if (deobClass.getName().startsWith("class"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
deobClass.addAnnotation(DeobAnnotations.IMPLEMENTS, deobClass.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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
@@ -33,6 +33,7 @@ package com.openosrs.injector.injectors;
|
||||
import com.openosrs.injector.InjectException;
|
||||
import com.openosrs.injector.InjectUtil;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import static com.openosrs.injector.rsapi.RSApi.CONSTRUCT;
|
||||
import com.openosrs.injector.rsapi.RSApiMethod;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -50,7 +51,6 @@ import net.runelite.asm.attributes.code.instructions.Return;
|
||||
import net.runelite.asm.pool.Class;
|
||||
import net.runelite.asm.pool.Method;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import static com.openosrs.injector.rsapi.RSApi.CONSTRUCT;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
|
||||
public class InjectConstruct extends AbstractInjector
|
||||
@@ -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());
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
* * Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -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,10 +105,17 @@ public class InjectHook extends AbstractInjector
|
||||
{
|
||||
final Annotation fieldHook = mixinMethod.findAnnotation(FIELDHOOK);
|
||||
if (fieldHook == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final boolean before = isBefore(fieldHook);
|
||||
if (!before && !mixinMethod.getDescriptor().toString().equals("(I)V"))
|
||||
{
|
||||
throw new InjectException(String.format("FieldHook method `%s` has a bad signature `%s` (expected `(I)V`)", mixinMethod.getName(), mixinMethod.getDescriptor().rsApiToRsClient()));
|
||||
}
|
||||
|
||||
final String hookName = fieldHook.getValueString();
|
||||
final boolean before = isBefore(fieldHook);
|
||||
|
||||
final ClassFile deobTarget = inject.toDeob(targetClass.getName());
|
||||
final Field deobField;
|
||||
@@ -149,23 +158,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 +193,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,11 +203,15 @@ public class InjectHook extends AbstractInjector
|
||||
try
|
||||
{
|
||||
if (hookInfo.before)
|
||||
{
|
||||
injectCallbackBefore(ins, idx, hookInfo, null, objectStackContext, value);
|
||||
}
|
||||
else
|
||||
// idx + 1 to insert after the set
|
||||
{
|
||||
injectCallback(ins, idx + 1, hookInfo, null, objectStackContext);
|
||||
}
|
||||
}
|
||||
catch (InjectException ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
@@ -206,23 +231,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 +267,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,10 +281,14 @@ 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)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
@@ -265,7 +306,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 +356,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 +369,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);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors;
|
||||
|
||||
@@ -33,4 +33,9 @@ public interface Injector extends Named
|
||||
* Gets a message logged at quiet level when the injector ends
|
||||
*/
|
||||
String getCompletionMsg();
|
||||
|
||||
/**
|
||||
* Checks if this injector is in the skip list
|
||||
*/
|
||||
boolean shouldRun();
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors;
|
||||
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import static com.openosrs.injector.rsapi.RSApi.API_BASE;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.Interfaces;
|
||||
import net.runelite.asm.pool.Class;
|
||||
import net.runelite.deob.DeobAnnotations;
|
||||
import static com.openosrs.injector.rsapi.RSApi.API_BASE;
|
||||
|
||||
public class InterfaceInjector extends AbstractInjector
|
||||
{
|
||||
@@ -36,12 +36,14 @@ 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))
|
||||
{
|
||||
log.debug("[DEBUG] Class {} implements nonexistent interface {}, skipping interface injection",
|
||||
log.error("[DEBUG] Class {} implements nonexistent interface {}, skipping interface injection",
|
||||
deobCf.getName(),
|
||||
fullName
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
@@ -87,6 +87,7 @@ public class MixinInjector extends AbstractInjector
|
||||
private static final String ASSERTION_FIELD = "$assertionsDisabled";
|
||||
private static final String MIXIN_BASE = "net/runelite/mixins/";
|
||||
|
||||
private int injectedInterfaces = 0;
|
||||
private final Map<String, Field> injectedFields = new HashMap<>();
|
||||
private final Map<net.runelite.asm.pool.Field, ShadowField> shadowFields = new HashMap<>();
|
||||
private int copied = 0, replaced = 0, injected = 0;
|
||||
@@ -106,6 +107,13 @@ public class MixinInjector extends AbstractInjector
|
||||
@VisibleForTesting
|
||||
void inject(Map<Provider<ClassFile>, List<ClassFile>> mixinTargets)
|
||||
{
|
||||
for (Map.Entry<Provider<ClassFile>, List<ClassFile>> entry : mixinTargets.entrySet())
|
||||
{
|
||||
injectInterfaces(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
log.info("[INFO] Injected {} interfaces", injectedInterfaces);
|
||||
|
||||
for (Map.Entry<Provider<ClassFile>, List<ClassFile>> entry : mixinTargets.entrySet())
|
||||
{
|
||||
injectFields(entry.getKey(), entry.getValue());
|
||||
@@ -136,6 +144,8 @@ public class MixinInjector extends AbstractInjector
|
||||
{
|
||||
ImmutableMap.Builder<Provider<ClassFile>, List<ClassFile>> builder = ImmutableMap.builder();
|
||||
|
||||
try
|
||||
{
|
||||
for (ClassFile mixinClass : inject.getMixins())
|
||||
{
|
||||
final List<ClassFile> ret = getMixins(mixinClass);
|
||||
@@ -144,11 +154,41 @@ public class MixinInjector extends AbstractInjector
|
||||
ret
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void injectInterfaces(Provider<ClassFile> mixinProvider, List<ClassFile> targetClasses)
|
||||
{
|
||||
try
|
||||
{
|
||||
final ClassFile mixinClass = mixinProvider.get();
|
||||
|
||||
for (final ClassFile targetClass : targetClasses)
|
||||
{
|
||||
mixinClass.getInterfaces().getInterfaces().forEach((itf) ->
|
||||
{
|
||||
if (targetClass.getInterfaces().addInterface(itf))
|
||||
{
|
||||
injectedInterfaces++;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void injectFields(Provider<ClassFile> mixinProvider, List<ClassFile> targetClasses)
|
||||
{
|
||||
try
|
||||
{
|
||||
final ClassFile mixinClass = mixinProvider.get();
|
||||
|
||||
@@ -168,18 +208,40 @@ 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());
|
||||
}
|
||||
}
|
||||
|
||||
if (targetClass.findField(field.getName(), field.getType()) != null && !ASSERTION_FIELD.equals(field.getName()))
|
||||
{
|
||||
throw new InjectException("Duplicate field: " + field.getName());
|
||||
}
|
||||
|
||||
targetClass.addField(copy);
|
||||
|
||||
// We only need to save static fields in injected fields, cause only static fields can be shadowed
|
||||
if (!field.isStatic())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (injectedFields.containsKey(field.getName()) && !ASSERTION_FIELD.equals(field.getName()))
|
||||
throw new InjectException("Duplicate field: " + field.getName());
|
||||
{
|
||||
throw new InjectException("Duplicate static field: " + field.getName());
|
||||
}
|
||||
|
||||
injectedFields.put(field.getName(), copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void findShadowFields(Provider<ClassFile> mixinProvider)
|
||||
{
|
||||
@@ -190,10 +252,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();
|
||||
|
||||
@@ -209,7 +275,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(),
|
||||
@@ -232,7 +300,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());
|
||||
@@ -241,13 +311,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());
|
||||
@@ -255,7 +329,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;
|
||||
|
||||
@@ -281,7 +357,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()))
|
||||
@@ -292,11 +370,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());
|
||||
@@ -320,7 +402,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;
|
||||
}
|
||||
@@ -362,7 +446,7 @@ public class MixinInjector extends AbstractInjector
|
||||
else if (hasInject)
|
||||
{
|
||||
// Make sure the method doesn't invoke copied methods
|
||||
for (Instruction i : mixinMethod.getCode().getInstructions())
|
||||
/*for (Instruction i : mixinMethod.getCode().getInstructions())
|
||||
{
|
||||
if (i instanceof InvokeInstruction)
|
||||
{
|
||||
@@ -370,22 +454,27 @@ public class MixinInjector extends AbstractInjector
|
||||
|
||||
if (copiedMethods.containsKey(ii.getMethod()))
|
||||
{
|
||||
throw new InjectException("Injected methods cannot invoke copied methods");
|
||||
throw new InjectException("Injected methods cannot invoke copied methods " + ii.toString());
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
Method method = targetClass.findMethod(mixinMethod.getName(), mixinMethod.getDescriptor());
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
method = new Method(targetClass, mixinMethod.getName(), mixinMethod.getDescriptor());
|
||||
targetClass.addMethod(method);
|
||||
}
|
||||
|
||||
Method copy = new Method(targetClass, mixinMethod.getName(), mixinMethod.getDescriptor());
|
||||
moveCode(copy, mixinMethod.getCode());
|
||||
copy.setAccessFlags(mixinMethod.getAccessFlags());
|
||||
copy.setPublic();
|
||||
moveCode(method, mixinMethod.getCode());
|
||||
method.setAccessFlags(mixinMethod.getAccessFlags());
|
||||
method.setPublic();
|
||||
assert mixinMethod.getExceptions().getExceptions().isEmpty();
|
||||
|
||||
setOwnersToTargetClass(mixinClass, targetClass, copy, copiedMethods);
|
||||
setOwnersToTargetClass(mixinClass, targetClass, method, copiedMethods);
|
||||
|
||||
targetClass.addMethod(copy);
|
||||
|
||||
log.debug("[DEBUG] Injected mixin method {} to {}", copy, targetClass);
|
||||
log.debug("[DEBUG] Injected mixin method {} to {}", method, targetClass);
|
||||
++injected;
|
||||
}
|
||||
else if (mixinMethod.findAnnotation(REPLACE) != null)
|
||||
@@ -486,11 +575,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);
|
||||
}
|
||||
@@ -581,8 +674,10 @@ public class MixinInjector extends AbstractInjector
|
||||
PushConstantInstruction pi = (PushConstantInstruction) i;
|
||||
|
||||
if (mixinCf.getPoolClass().equals(pi.getConstant()))
|
||||
{
|
||||
pi.setConstant(cf.getPoolClass());
|
||||
}
|
||||
}
|
||||
|
||||
verify(mixinCf, i);
|
||||
}
|
||||
@@ -597,26 +692,34 @@ 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)
|
||||
{
|
||||
InvokeStatic is = (InvokeStatic) i;
|
||||
|
||||
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{}
|
||||
{
|
||||
throw new InjectException("Injected bytecode must be Java 6 compatible");
|
||||
}
|
||||
}
|
||||
|
||||
private Method findDeobMatching(ClassFile deobClass, Method mixinMethod, String deobName)
|
||||
{
|
||||
@@ -625,18 +728,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
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -672,20 +783,22 @@ public class MixinInjector extends AbstractInjector
|
||||
.map(mix -> InjectUtil.getVanillaClassFromAnnotationString(inject, mix))
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
throw new IllegalArgumentException("No MIXIN or MIXINS found on " + from.toString());
|
||||
throw new IllegalArgumentException("No MIXIN or MIXINS found on " + from);
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class CopiedMethod
|
||||
{
|
||||
@Nonnull Method copy;
|
||||
@Nonnull
|
||||
Method copy;
|
||||
@Nullable Integer garbage;
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class ShadowField
|
||||
{
|
||||
@Nonnull Field targetField;
|
||||
@Nonnull
|
||||
Field targetField;
|
||||
@Nullable Number obfuscatedGetter;
|
||||
}
|
||||
|
||||
@@ -699,7 +812,9 @@ public class MixinInjector extends AbstractInjector
|
||||
public ClassFile get()
|
||||
{
|
||||
if (bytes != null)
|
||||
{
|
||||
return JarUtil.loadClass(bytes);
|
||||
}
|
||||
|
||||
bytes = JarUtil.writeClass(mixin.getGroup(), mixin);
|
||||
return mixin;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
@@ -36,6 +36,7 @@ import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.rsapi.InjectGetter;
|
||||
import com.openosrs.injector.injectors.rsapi.InjectInvoke;
|
||||
import com.openosrs.injector.injectors.rsapi.InjectSetter;
|
||||
import static com.openosrs.injector.rsapi.RSApi.API_BASE;
|
||||
import com.openosrs.injector.rsapi.RSApiClass;
|
||||
import com.openosrs.injector.rsapi.RSApiMethod;
|
||||
import java.util.ArrayList;
|
||||
@@ -50,7 +51,6 @@ import net.runelite.asm.Type;
|
||||
import net.runelite.asm.attributes.Annotated;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import net.runelite.deob.DeobAnnotations;
|
||||
import static com.openosrs.injector.rsapi.RSApi.API_BASE;
|
||||
|
||||
public class RSApiInjector extends AbstractInjector
|
||||
{
|
||||
@@ -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();
|
||||
|
||||
@@ -116,9 +118,9 @@ public class RSApiInjector extends AbstractInjector
|
||||
|
||||
final Signature sig = apiMethod.getSignature();
|
||||
|
||||
if (sig.isVoid())
|
||||
{
|
||||
if (sig.size() == 1)
|
||||
{
|
||||
if (sig.isVoid() || sig.getReturnValue().equals(Type.fromAsmString(apiMethod.getClazz().getName())))
|
||||
{
|
||||
Type type = InjectUtil.apiToDeob(inject, sig.getTypeOfArg(0));
|
||||
if (deobType.equals(type))
|
||||
@@ -129,7 +131,7 @@ public class RSApiInjector extends AbstractInjector
|
||||
}
|
||||
else if (sig.size() == 0)
|
||||
{
|
||||
Type type = InjectUtil.apiToDeob(inject, sig.getReturnValue());
|
||||
Type type = InjectUtil.apiToDeob(inject, sig.getReturnValue(), deobType);
|
||||
if (deobType.equals(type))
|
||||
{
|
||||
continue;
|
||||
@@ -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,9 +217,11 @@ public class RSApiInjector extends AbstractInjector
|
||||
apiMethod.setInjected(true);
|
||||
}
|
||||
else if (matching.size() != 0)
|
||||
{
|
||||
throw new InjectException("Multiple api imports matching method " + deobMethod.getPoolMethod());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void retryFailures()
|
||||
{
|
||||
@@ -224,8 +232,10 @@ public class RSApiInjector extends AbstractInjector
|
||||
|
||||
matched.removeIf(RSApiMethod::isInjected);
|
||||
|
||||
if (matched.size() > 2)
|
||||
/*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<>();
|
||||
|
||||
@@ -264,7 +276,7 @@ public class RSApiInjector extends AbstractInjector
|
||||
final ClassFile targetClass = InjectUtil.vanillaFromApiMethod(inject, apiMethod);
|
||||
apiMethod.setInjected(true);
|
||||
|
||||
if (apiMethod.getSignature().isVoid())
|
||||
if (apiMethod.getSignature().getArguments().size() == 1)
|
||||
{
|
||||
++set;
|
||||
log.debug("[DEBUG] Injecting setter {} for {} into {}", apiMethod.getMethod(), field.getPoolField(), targetClass.getPoolClass());
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
@@ -12,13 +12,10 @@ import com.openosrs.injector.InjectException;
|
||||
import com.openosrs.injector.InjectUtil;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.AbstractInjector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import net.runelite.asm.Method;
|
||||
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.Label;
|
||||
import net.runelite.asm.attributes.code.instruction.types.ComparisonInstruction;
|
||||
@@ -32,8 +29,6 @@ import net.runelite.asm.attributes.code.instructions.IfACmpNe;
|
||||
import net.runelite.asm.attributes.code.instructions.IfICmpNe;
|
||||
import net.runelite.asm.attributes.code.instructions.IfNe;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.LDC;
|
||||
import net.runelite.asm.attributes.code.instructions.Return;
|
||||
import net.runelite.asm.pool.Field;
|
||||
|
||||
public class AddPlayerToMenu extends AbstractInjector
|
||||
@@ -45,15 +40,15 @@ public class AddPlayerToMenu extends AbstractInjector
|
||||
|
||||
public void inject()
|
||||
{
|
||||
final Method addPlayerOptions = InjectUtil.findMethod(inject, "addPlayerToMenu");
|
||||
final Method addPlayerOptions = inject.toVanilla(inject.getDeobfuscated().findClass("Scene")).findMethod("copy$addPlayerToMenu");
|
||||
final net.runelite.asm.pool.Method shouldHideAttackOptionFor =
|
||||
inject.getVanilla().findClass("client").findMethod("shouldHideAttackOptionFor").getPoolMethod();
|
||||
final net.runelite.asm.pool.Method shouldDrawMethod =
|
||||
inject.getVanilla().findStaticMethod("shouldDraw").getPoolMethod();
|
||||
// final net.runelite.asm.pool.Method shouldDrawMethod =
|
||||
// inject.getVanilla().findStaticMethod("shouldDraw").getPoolMethod();
|
||||
|
||||
try
|
||||
{
|
||||
injectSameTileFix(addPlayerOptions, shouldDrawMethod);
|
||||
// injectSameTileFix(addPlayerOptions, shouldDrawMethod);
|
||||
injectHideAttack(addPlayerOptions, shouldHideAttackOptionFor);
|
||||
injectHideCast(addPlayerOptions, shouldHideAttackOptionFor);
|
||||
}
|
||||
@@ -63,32 +58,32 @@ public class AddPlayerToMenu extends AbstractInjector
|
||||
}
|
||||
}
|
||||
|
||||
private void injectSameTileFix(Method addPlayerOptions, net.runelite.asm.pool.Method shouldDrawMethod)
|
||||
{
|
||||
// ALOAD 0
|
||||
// ICONST_0
|
||||
// INVOKESTATIC Scene.shouldDraw
|
||||
// IFNE CONTINUE_LABEL if returned true then jump to continue
|
||||
// RETURN
|
||||
// CONTINUE_LABEL
|
||||
// REST OF METHOD GOES HERE
|
||||
Instructions insns = addPlayerOptions.getCode().getInstructions();
|
||||
Label CONTINUE_LABEL = new Label(insns);
|
||||
List<Instruction> prependList = new ArrayList<>()
|
||||
{{
|
||||
add(new ALoad(insns, 0));
|
||||
add(new LDC(insns, 0));
|
||||
add(new InvokeStatic(insns, shouldDrawMethod));
|
||||
add(new IfNe(insns, CONTINUE_LABEL));
|
||||
add(new Return(insns, InstructionType.RETURN));
|
||||
add(CONTINUE_LABEL);
|
||||
}};
|
||||
int i = 0;
|
||||
for (Instruction instruction : prependList)
|
||||
{
|
||||
insns.addInstruction(i++, instruction);
|
||||
}
|
||||
}
|
||||
// private void injectSameTileFix(Method addPlayerOptions, net.runelite.asm.pool.Method shouldDrawMethod)
|
||||
// {
|
||||
// // ALOAD 0
|
||||
// // ICONST_0
|
||||
// // INVOKESTATIC Scene.shouldDraw
|
||||
// // IFNE CONTINUE_LABEL if returned true then jump to continue
|
||||
// // RETURN
|
||||
// // CONTINUE_LABEL
|
||||
// // REST OF METHOD GOES HERE
|
||||
// Instructions insns = addPlayerOptions.getCode().getInstructions();
|
||||
// Label CONTINUE_LABEL = new Label(insns);
|
||||
// List<Instruction> prependList = new ArrayList<>()
|
||||
// {{
|
||||
// add(new ALoad(insns, 0));
|
||||
// add(new LDC(insns, 0));
|
||||
// add(new InvokeStatic(insns, shouldDrawMethod));
|
||||
// add(new IfNe(insns, CONTINUE_LABEL));
|
||||
// add(new Return(insns, InstructionType.RETURN));
|
||||
// add(CONTINUE_LABEL);
|
||||
// }};
|
||||
// int i = 0;
|
||||
// for (Instruction instruction : prependList)
|
||||
// {
|
||||
// insns.addInstruction(i++, instruction);
|
||||
// }
|
||||
// }
|
||||
|
||||
private void injectHideAttack(Method addPlayerOptions, net.runelite.asm.pool.Method shouldHideAttackOptionFor)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
@@ -22,17 +22,9 @@ 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.signature.Signature;
|
||||
import static com.openosrs.injector.injection.InjectData.HOOKS;
|
||||
|
||||
public class ClearColorBuffer extends AbstractInjector
|
||||
{
|
||||
private static final net.runelite.asm.pool.Method CLEARBUFFER = new net.runelite.asm.pool.Method(
|
||||
new net.runelite.asm.pool.Class(HOOKS),
|
||||
"clearColorBuffer",
|
||||
new Signature("(IIIII)V")
|
||||
);
|
||||
|
||||
public ClearColorBuffer(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
@@ -40,11 +32,13 @@ public class ClearColorBuffer extends AbstractInjector
|
||||
|
||||
public void inject()
|
||||
{
|
||||
|
||||
/*
|
||||
* This class stops the client from basically painting everything black before the scene is drawn
|
||||
*/
|
||||
final Execution exec = new Execution(inject.getVanilla());
|
||||
|
||||
final net.runelite.asm.pool.Method clearBuffer = inject.getVanilla().findClass("client").findMethod("clearColorBuffer").getPoolMethod();
|
||||
final net.runelite.asm.pool.Method fillRectPool = InjectUtil.findMethod(inject, "Rasterizer2D_fillRectangle", "Rasterizer2D", null).getPoolMethod();
|
||||
final Method drawEntities = InjectUtil.findMethod(inject, "drawEntities"); // XXX: should prob be called drawViewport?
|
||||
|
||||
@@ -83,7 +77,7 @@ public class ClearColorBuffer extends AbstractInjector
|
||||
}
|
||||
|
||||
Instructions ins = instr.getInstructions();
|
||||
ins.replace(instr, new InvokeStatic(ins, CLEARBUFFER));
|
||||
ins.replace(instr, new InvokeStatic(ins, clearBuffer));
|
||||
log.debug("[DEBUG] Injected drawRectangle at {}", methodContext.getMethod().getPoolMethod());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Owain van Brakel <https://github.com/Owain94>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
import com.openosrs.injector.InjectUtil;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.AbstractInjector;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.Field;
|
||||
import net.runelite.asm.Method;
|
||||
import net.runelite.asm.Type;
|
||||
import net.runelite.asm.attributes.Code;
|
||||
import net.runelite.asm.attributes.code.Instruction;
|
||||
import net.runelite.asm.attributes.code.Instructions;
|
||||
import net.runelite.asm.attributes.code.instructions.CheckCast;
|
||||
import net.runelite.asm.attributes.code.instructions.GetField;
|
||||
import net.runelite.asm.attributes.code.instructions.GetStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeSpecial;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeVirtual;
|
||||
import net.runelite.asm.attributes.code.instructions.New;
|
||||
import net.runelite.asm.attributes.code.instructions.PutField;
|
||||
import net.runelite.asm.attributes.code.instructions.PutStatic;
|
||||
import net.runelite.asm.pool.Class;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public class CopyRuneLiteClasses extends AbstractInjector
|
||||
{
|
||||
private static final List<String> RUNELITE_OBJECTS = List.of(
|
||||
"RuneLiteClanMember",
|
||||
"RuneLiteIterableLinkDeque",
|
||||
"RuneLiteIterableNodeDeque",
|
||||
"RuneLiteIterableNodeHashTable",
|
||||
"RuneLiteMenuEntry",
|
||||
"RuneLiteObject"
|
||||
);
|
||||
|
||||
|
||||
private final Set<Type> shadowFields = new HashSet<>();
|
||||
|
||||
public CopyRuneLiteClasses(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
|
||||
public void inject()
|
||||
{
|
||||
for (String className : RUNELITE_OBJECTS)
|
||||
{
|
||||
shadowFields.clear();
|
||||
|
||||
ClassFile runeliteObjectVanilla = inject.getVanilla().findClass(className);
|
||||
|
||||
final ClassFile runeLiteDeob = inject.getDeobfuscated()
|
||||
.findClass(className);
|
||||
|
||||
if (runeliteObjectVanilla == null)
|
||||
{
|
||||
runeliteObjectVanilla = new ClassFile(inject.getVanilla());
|
||||
runeliteObjectVanilla.setVersion(Opcodes.V1_8);
|
||||
runeliteObjectVanilla.setName(className);
|
||||
runeliteObjectVanilla.setAccess(runeLiteDeob.getAccess());
|
||||
|
||||
if (runeLiteDeob.getParentClass() != null)
|
||||
{
|
||||
ClassFile deobClass = inject.getDeobfuscated().findClass(runeLiteDeob.getParentClass().getName());
|
||||
|
||||
if (deobClass != null)
|
||||
{
|
||||
runeliteObjectVanilla.setParentClass(inject.toVanilla(deobClass).getPoolClass());
|
||||
}
|
||||
else
|
||||
{
|
||||
runeliteObjectVanilla.setParentClass(runeLiteDeob.getParentClass());
|
||||
}
|
||||
}
|
||||
|
||||
inject.getToVanilla().put(runeLiteDeob, runeliteObjectVanilla);
|
||||
|
||||
for (Class interfaze : runeLiteDeob.getInterfaces())
|
||||
{
|
||||
runeliteObjectVanilla.getInterfaces().addInterface(interfaze);
|
||||
}
|
||||
|
||||
for (Method method : runeLiteDeob.getMethods())
|
||||
{
|
||||
transformMethod(method);
|
||||
runeliteObjectVanilla.addMethod(method);
|
||||
}
|
||||
|
||||
for (Field field : runeLiteDeob.getFields())
|
||||
{
|
||||
if (shadowFields.contains(field.getType()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
field.setType(InjectUtil.deobToVanilla(inject, field.getType()));
|
||||
runeliteObjectVanilla.addField(field);
|
||||
}
|
||||
|
||||
inject.getVanilla().addClass(runeliteObjectVanilla);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void transformMethod(Method method)
|
||||
{
|
||||
method.setDescriptor(getObfuscatedSignature(method.getDescriptor()));
|
||||
|
||||
Code code = method.getCode();
|
||||
|
||||
if (code != null)
|
||||
{
|
||||
Instructions ins = code.getInstructions();
|
||||
for (ListIterator<Instruction> iterator = ins.listIterator(); iterator.hasNext(); )
|
||||
{
|
||||
Instruction i = iterator.next();
|
||||
|
||||
if (i instanceof PutField)
|
||||
{
|
||||
net.runelite.asm.pool.Field field = ((PutField) i).getField();
|
||||
Field vanilla = findField(field);
|
||||
|
||||
if (vanilla != null)
|
||||
{
|
||||
iterator.set(new PutField(ins, vanilla));
|
||||
}
|
||||
else
|
||||
{
|
||||
field.setType(getObfuscatedSignature(field.getType()));
|
||||
iterator.set(new PutField(ins, field));
|
||||
}
|
||||
}
|
||||
else if (i instanceof GetField)
|
||||
{
|
||||
net.runelite.asm.pool.Field field = ((GetField) i).getField();
|
||||
Field vanilla = findField(field);
|
||||
|
||||
if (vanilla != null)
|
||||
{
|
||||
iterator.set(new GetField(ins, vanilla));
|
||||
}
|
||||
else
|
||||
{
|
||||
field.setType(getObfuscatedSignature(field.getType()));
|
||||
iterator.set(new GetField(ins, field));
|
||||
}
|
||||
}
|
||||
else if (i instanceof PutStatic)
|
||||
{
|
||||
net.runelite.asm.pool.Field field = ((PutStatic) i).getField();
|
||||
Field vanilla = findField(field);
|
||||
|
||||
if (vanilla != null)
|
||||
{
|
||||
iterator.set(new PutStatic(ins, vanilla));
|
||||
}
|
||||
else
|
||||
{
|
||||
field.setType(getObfuscatedSignature(field.getType()));
|
||||
iterator.set(new PutStatic(ins, field));
|
||||
}
|
||||
}
|
||||
else if (i instanceof GetStatic)
|
||||
{
|
||||
net.runelite.asm.pool.Field field = ((GetStatic) i).getField();
|
||||
Field vanilla = findField(field);
|
||||
|
||||
if (method.getClassFile().getName().equals(field.getClazz().getName()) && field.getType().toString().contains("Lnet/runelite/rs/api/RS"))
|
||||
{
|
||||
shadowFields.add(field.getType());
|
||||
|
||||
String fieldName = field.getType().toString().replace("Lnet/runelite/rs/api/RS", "").replace(";", "");
|
||||
final Field deobTargetField = InjectUtil.findStaticField(inject, fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1), null, InjectUtil.apiToDeob(inject, field.getType()));
|
||||
|
||||
iterator.set(new GetStatic(ins, inject.toVanilla(deobTargetField)));
|
||||
}
|
||||
else if (vanilla != null)
|
||||
{
|
||||
iterator.set(new GetStatic(ins, vanilla));
|
||||
}
|
||||
else
|
||||
{
|
||||
field.setType(getObfuscatedSignature(field.getType()));
|
||||
iterator.set(new GetStatic(ins, field));
|
||||
}
|
||||
}
|
||||
else if (i instanceof InvokeSpecial)
|
||||
{
|
||||
net.runelite.asm.pool.Method meth = ((InvokeSpecial) i).getMethod();
|
||||
Method vanilla = findMethod(meth, true);
|
||||
|
||||
if (vanilla != null)
|
||||
{
|
||||
iterator.set(new InvokeSpecial(ins, vanilla));
|
||||
}
|
||||
else
|
||||
{
|
||||
meth.setType(getObfuscatedSignature(meth.getType()));
|
||||
iterator.set(new InvokeSpecial(ins, meth));
|
||||
}
|
||||
}
|
||||
else if (i instanceof InvokeStatic)
|
||||
{
|
||||
net.runelite.asm.pool.Method meth = ((InvokeStatic) i).getMethod();
|
||||
Method vanilla = findMethod(meth, false);
|
||||
|
||||
if (vanilla != null)
|
||||
{
|
||||
iterator.set(new InvokeStatic(ins, vanilla));
|
||||
}
|
||||
else
|
||||
{
|
||||
meth.setType(getObfuscatedSignature(meth.getType()));
|
||||
iterator.set(new InvokeStatic(ins, meth));
|
||||
}
|
||||
}
|
||||
else if (i instanceof InvokeVirtual)
|
||||
{
|
||||
net.runelite.asm.pool.Method meth = ((InvokeVirtual) i).getMethod();
|
||||
Method vanilla = findMethod(meth, true);
|
||||
|
||||
if (vanilla != null)
|
||||
{
|
||||
iterator.set(new InvokeVirtual(ins, vanilla));
|
||||
}
|
||||
else
|
||||
{
|
||||
meth.setType(getObfuscatedSignature(meth.getType()));
|
||||
iterator.set(new InvokeVirtual(ins, meth));
|
||||
}
|
||||
}
|
||||
else if (i instanceof New)
|
||||
{
|
||||
|
||||
Class clazz = ((New) i).getNewClass();
|
||||
ClassFile deobClass = inject.getDeobfuscated().findClass(clazz.getName());
|
||||
|
||||
if (deobClass != null)
|
||||
{
|
||||
iterator.set(new New(ins, inject.toVanilla(deobClass)));
|
||||
}
|
||||
}
|
||||
else if (i instanceof CheckCast)
|
||||
{
|
||||
CheckCast clazz = ((CheckCast) i);
|
||||
iterator.set(new CheckCast(ins, getObfuscatedSignature(clazz.getType_())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Signature getObfuscatedSignature(Signature signature)
|
||||
{
|
||||
Signature.Builder builder = new Signature.Builder();
|
||||
|
||||
for (int j = 0; j < signature.size(); ++j)
|
||||
{
|
||||
Type type = signature.getTypeOfArg(j);
|
||||
builder.addArgument(InjectUtil.deobToVanilla(inject, type));
|
||||
}
|
||||
|
||||
builder.setReturnType(InjectUtil.deobToVanilla(inject, signature.getReturnValue()));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Type getObfuscatedSignature(Type type)
|
||||
{
|
||||
return InjectUtil.deobToVanilla(inject, type);
|
||||
}
|
||||
|
||||
private Method findMethod(net.runelite.asm.pool.Method meth, boolean notStatic)
|
||||
{
|
||||
try
|
||||
{
|
||||
return InjectUtil.findMethod(inject, meth.getName(), meth.getClazz().getName(), meth.getType()::equals, notStatic, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Field findField(net.runelite.asm.pool.Field field)
|
||||
{
|
||||
try
|
||||
{
|
||||
return InjectUtil.findField(inject, field.getName(), field.getClazz().getName());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
@@ -33,22 +33,25 @@ package com.openosrs.injector.injectors.raw;
|
||||
import com.openosrs.injector.InjectException;
|
||||
import com.openosrs.injector.InjectUtil;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import static com.openosrs.injector.injection.InjectData.CALLBACKS;
|
||||
import com.openosrs.injector.injectors.AbstractInjector;
|
||||
import java.util.HashSet;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.Field;
|
||||
import net.runelite.asm.Method;
|
||||
import net.runelite.asm.attributes.code.Instruction;
|
||||
import net.runelite.asm.attributes.code.Instructions;
|
||||
import net.runelite.asm.attributes.code.Label;
|
||||
import net.runelite.asm.attributes.code.instruction.types.JumpingInstruction;
|
||||
import net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction;
|
||||
import net.runelite.asm.attributes.code.instructions.GetField;
|
||||
import net.runelite.asm.attributes.code.instructions.GetStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.IMul;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeInterface;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import static com.openosrs.injector.injection.InjectData.HOOKS;
|
||||
|
||||
public class DrawAfterWidgets extends AbstractInjector
|
||||
{
|
||||
@@ -103,6 +106,8 @@ public class DrawAfterWidgets extends AbstractInjector
|
||||
|
||||
boolean injected = false;
|
||||
|
||||
Field client = getVanillaStaticFieldFromDeob("client");
|
||||
Field callbacks = getObfuscatedField("callbacks");
|
||||
Method noClip = InjectUtil.findMethod(inject, "Rasterizer2D_resetClip", "Rasterizer2D", null); // !!!!!
|
||||
|
||||
if (noClip == null)
|
||||
@@ -235,16 +240,17 @@ public class DrawAfterWidgets extends AbstractInjector
|
||||
|
||||
for (Label l : labelsToInjectAfter)
|
||||
{
|
||||
InvokeStatic invoke = new InvokeStatic(instructions,
|
||||
InvokeInterface invoke = new InvokeInterface(instructions,
|
||||
new net.runelite.asm.pool.Method(
|
||||
new net.runelite.asm.pool.Class(HOOKS),
|
||||
new net.runelite.asm.pool.Class(CALLBACKS),
|
||||
"drawAfterWidgets",
|
||||
new Signature("()V")
|
||||
)
|
||||
);
|
||||
|
||||
instructions.addInstruction(instructions.getInstructions().indexOf(l) + 1, invoke);
|
||||
|
||||
instructions.addInstruction(instructions.getInstructions().indexOf(l) + 1, new GetField(instructions, callbacks.getPoolField()));
|
||||
instructions.addInstruction(instructions.getInstructions().indexOf(l) + 1, new GetStatic(instructions, client.getPoolField()));
|
||||
log.debug("[DEBUG] injectDrawAfterWidgets injected a call after " + l);
|
||||
|
||||
injected = true;
|
||||
@@ -257,4 +263,40 @@ public class DrawAfterWidgets extends AbstractInjector
|
||||
throw new InjectException("injectDrawAfterWidgets failed to inject!");
|
||||
}
|
||||
}
|
||||
|
||||
public Field getVanillaStaticFieldFromDeob(String s)
|
||||
{
|
||||
for (ClassFile c : inject.getDeobfuscated())
|
||||
{
|
||||
for (Field f : c.getFields())
|
||||
{
|
||||
if (f.isStatic())
|
||||
{
|
||||
if (f.getName().equals(s))
|
||||
{
|
||||
return inject.toVanilla(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Field getObfuscatedField(String s)
|
||||
{
|
||||
for (ClassFile c : inject.getVanilla())
|
||||
{
|
||||
for (Field f : c.getFields())
|
||||
{
|
||||
if (!f.isStatic())
|
||||
{
|
||||
if (f.getName().equals(s))
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
@@ -24,19 +24,10 @@ import net.runelite.asm.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.asm.execution.Execution;
|
||||
import net.runelite.asm.execution.InstructionContext;
|
||||
import net.runelite.asm.execution.MethodContext;
|
||||
import net.runelite.asm.pool.Class;
|
||||
import net.runelite.asm.pool.Field;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import static com.openosrs.injector.injection.InjectData.HOOKS;
|
||||
|
||||
public class DrawMenu extends AbstractInjector
|
||||
{
|
||||
private static final net.runelite.asm.pool.Method DRAWMENU = new net.runelite.asm.pool.Method(
|
||||
new Class(HOOKS),
|
||||
"drawMenu",
|
||||
new Signature("()Z")
|
||||
);
|
||||
|
||||
public DrawMenu(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
@@ -66,6 +57,7 @@ public class DrawMenu extends AbstractInjector
|
||||
* --------
|
||||
*/
|
||||
|
||||
final net.runelite.asm.pool.Method drawMenu = inject.getVanilla().findClass("client").findMethod("drawMenu").getPoolMethod();
|
||||
final Method drawLoggedIn = InjectUtil.findMethod(inject, "drawLoggedIn", "Client", null, true, false);
|
||||
final Field gameDrawMode = InjectUtil.findField(inject, "gameDrawingMode", "Client").getPoolField();
|
||||
final Field isMenuOpen = InjectUtil.findField(inject, "isMenuOpen", "Client").getPoolField();
|
||||
@@ -87,7 +79,9 @@ public class DrawMenu extends AbstractInjector
|
||||
{
|
||||
Instruction instruction = ic.getInstruction();
|
||||
if (!(instruction instanceof GetStatic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (((GetStatic) instruction).getField().equals(isMenuOpen))
|
||||
{
|
||||
@@ -100,30 +94,40 @@ 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);
|
||||
|
||||
instrs.addInstruction(++idx, new InvokeStatic(instrs, DRAWMENU));
|
||||
instrs.addInstruction(++idx, new InvokeStatic(instrs, drawMenu));
|
||||
instrs.addInstruction(++idx, new IfNe(instrs, labelToJumpTo));
|
||||
|
||||
log.info("[INFO] DrawMenu injected a method call at index {} in method {}. With a comparison jumping to {}", idx, drawLoggedIn, labelToJumpTo);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
import com.openosrs.injector.InjectUtil;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.AbstractInjector;
|
||||
import java.util.ListIterator;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.Method;
|
||||
import net.runelite.asm.attributes.code.Instruction;
|
||||
import net.runelite.asm.attributes.code.Instructions;
|
||||
import net.runelite.asm.attributes.code.instructions.LDC;
|
||||
import net.runelite.asm.attributes.code.instructions.PutStatic;
|
||||
import net.runelite.asm.pool.Field;
|
||||
|
||||
public class GameDrawingMode extends AbstractInjector
|
||||
{
|
||||
public GameDrawingMode(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
|
||||
public void inject()
|
||||
{
|
||||
final ClassFile clientVanilla = inject.toVanilla(
|
||||
inject.getDeobfuscated()
|
||||
.findClass("Client")
|
||||
);
|
||||
final Field gameDrawingMode = InjectUtil.findField(inject, "gameDrawingMode", "Client").getPoolField();
|
||||
|
||||
Method clinit = clientVanilla.findMethod("<clinit>");
|
||||
|
||||
Instructions ins = clinit.getCode().getInstructions();
|
||||
ListIterator<Instruction> iterator = ins.getInstructions().listIterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
Instruction i = iterator.next();
|
||||
|
||||
if (i instanceof PutStatic)
|
||||
{
|
||||
Field field = ((PutStatic) i).getField();
|
||||
|
||||
if (field.getName().equals(gameDrawingMode.getName()))
|
||||
{
|
||||
iterator.add(new LDC(ins, 2));
|
||||
iterator.add(new PutStatic(ins, gameDrawingMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Owain van Brakel <https://github.com/Owain94>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.AbstractInjector;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.Method;
|
||||
import net.runelite.asm.attributes.Code;
|
||||
import net.runelite.asm.attributes.code.Instructions;
|
||||
import net.runelite.asm.attributes.code.instructions.ALoad;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeSpecial;
|
||||
import net.runelite.asm.attributes.code.instructions.VReturn;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
|
||||
public class GraphicsObject extends AbstractInjector
|
||||
{
|
||||
public GraphicsObject(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
|
||||
public void inject()
|
||||
{
|
||||
final ClassFile graphicsObjectVanilla = inject.toVanilla(
|
||||
inject.getDeobfuscated()
|
||||
.findClass("GraphicsObject")
|
||||
);
|
||||
|
||||
final ClassFile renderableVanilla = inject.toVanilla(
|
||||
inject.getDeobfuscated()
|
||||
.findClass("Renderable")
|
||||
);
|
||||
|
||||
graphicsObjectVanilla.clearFinal();
|
||||
|
||||
Method initGraphicsObject = new Method(graphicsObjectVanilla, "<init>", new Signature("()V"));
|
||||
initGraphicsObject.setPublic();
|
||||
|
||||
final Code code = new Code(initGraphicsObject);
|
||||
code.setMaxStack(1);
|
||||
initGraphicsObject.setCode(code);
|
||||
graphicsObjectVanilla.addMethod(initGraphicsObject);
|
||||
|
||||
Instructions ins = code.getInstructions();
|
||||
|
||||
ins.addInstruction(new ALoad(ins, 0));
|
||||
ins.addInstruction(new InvokeSpecial(ins, new net.runelite.asm.pool.Method(renderableVanilla.getPoolClass(), "<init>", new Signature("()V"))));
|
||||
ins.addInstruction(new VReturn(ins));
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
@@ -17,17 +17,9 @@ import net.runelite.asm.attributes.code.Instruction;
|
||||
import net.runelite.asm.attributes.code.Instructions;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeVirtual;
|
||||
import net.runelite.asm.pool.Class;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import static com.openosrs.injector.injection.InjectData.HOOKS;
|
||||
|
||||
public class RenderDraw extends AbstractInjector
|
||||
{
|
||||
private static final net.runelite.asm.pool.Method RENDERDRAW = new net.runelite.asm.pool.Method(
|
||||
new Class(HOOKS),
|
||||
"renderDraw",
|
||||
new Signature("(Lnet/runelite/api/Entity;IIIIIIIIJ)V")
|
||||
);
|
||||
private static final int EXPECTED = 21;
|
||||
|
||||
public RenderDraw(InjectData inject)
|
||||
@@ -38,13 +30,15 @@ public class RenderDraw extends AbstractInjector
|
||||
@Override
|
||||
public void inject()
|
||||
{
|
||||
final net.runelite.asm.pool.Method renderDraw = inject.toVanilla(inject.getDeobfuscated().findClass("Scene")).findMethod("renderDraw").getPoolMethod();
|
||||
|
||||
int replaced = 0;
|
||||
|
||||
/*
|
||||
* This class replaces entity draw invocation instructions
|
||||
* with the renderDraw method on drawcallbacks
|
||||
*/
|
||||
final net.runelite.asm.pool.Method draw = InjectUtil.findMethod(inject, "draw", "Entity", null, true, false).getPoolMethod();
|
||||
final net.runelite.asm.pool.Method draw = InjectUtil.findMethod(inject, "draw", "Renderable", null, true, false).getPoolMethod();
|
||||
|
||||
final Method drawTile = InjectUtil.findMethod(inject, "drawTile", "Scene", null, true, false);
|
||||
|
||||
@@ -56,7 +50,7 @@ public class RenderDraw extends AbstractInjector
|
||||
{
|
||||
if (((InvokeVirtual) i).getMethod().equals(draw))
|
||||
{
|
||||
iterator.set(new InvokeStatic(ins, RENDERDRAW));
|
||||
iterator.set(new InvokeStatic(ins, renderDraw));
|
||||
log.debug("[DEBUG] Replaced method call at {}", i);
|
||||
++replaced;
|
||||
}
|
||||
@@ -64,6 +58,8 @@ public class RenderDraw extends AbstractInjector
|
||||
}
|
||||
|
||||
if (replaced != EXPECTED)
|
||||
{
|
||||
throw new InjectException("Didn't replace the expected amount of method calls");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Owain van Brakel <https://github.com/Owain94>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.AbstractInjector;
|
||||
import java.util.List;
|
||||
import net.runelite.asm.ClassFile;
|
||||
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.instructions.ALoad;
|
||||
import net.runelite.asm.attributes.code.instructions.Dup;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeSpecial;
|
||||
import net.runelite.asm.attributes.code.instructions.New;
|
||||
import net.runelite.asm.attributes.code.instructions.Return;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
|
||||
public class RuneLiteIterables extends AbstractInjector
|
||||
{
|
||||
private static final String RUNELITE_ITERABLE_HASHTABLE = "RuneLiteIterableNodeHashTable";
|
||||
private static final String RUNELITE_ITERABLE_NODE_DEQUE = "RuneLiteIterableNodeDeque";
|
||||
private static final String RUNELITE_ITERABLE_LINK_DEQUE = "RuneLiteIterableLinkDeque";
|
||||
|
||||
public RuneLiteIterables(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
|
||||
public void inject()
|
||||
{
|
||||
injectHashTable();
|
||||
injectNodeDeque();
|
||||
injectLinkDeque();
|
||||
}
|
||||
|
||||
public void injectHashTable()
|
||||
{
|
||||
ClassFile runeliteIterableHashTableVanilla = inject.getVanilla().findClass(RUNELITE_ITERABLE_HASHTABLE);
|
||||
|
||||
final ClassFile nodeHashTableVanilla = inject.toVanilla(
|
||||
inject.getDeobfuscated()
|
||||
.findClass(RUNELITE_ITERABLE_HASHTABLE.replace("RuneLiteIterable", ""))
|
||||
);
|
||||
|
||||
Method copy = new Method(nodeHashTableVanilla, "iterator", new Signature("()Ljava/util/Iterator;"));
|
||||
copy.setPublic();
|
||||
|
||||
final Code code = new Code(copy);
|
||||
code.setMaxStack(3);
|
||||
copy.setCode(code);
|
||||
nodeHashTableVanilla.addMethod(copy);
|
||||
|
||||
final Instructions instructions = code.getInstructions();
|
||||
final List<Instruction> ins = instructions.getInstructions();
|
||||
|
||||
ins.add(new New(instructions, runeliteIterableHashTableVanilla.getPoolClass()));
|
||||
ins.add(new Dup(instructions));
|
||||
ins.add(new ALoad(instructions, 0));
|
||||
ins.add(new InvokeSpecial(instructions, new net.runelite.asm.pool.Method(runeliteIterableHashTableVanilla.getPoolClass(), "<init>", new Signature("(L" + nodeHashTableVanilla.getName() + ";)V"))));
|
||||
ins.add(new Return(instructions, InstructionType.ARETURN));
|
||||
}
|
||||
|
||||
public void injectNodeDeque()
|
||||
{
|
||||
ClassFile runeliteIterableNodeDequeVanilla = inject.getVanilla().findClass(RUNELITE_ITERABLE_NODE_DEQUE);
|
||||
|
||||
final ClassFile nodeDequeVanilla = inject.toVanilla(
|
||||
inject.getDeobfuscated()
|
||||
.findClass(RUNELITE_ITERABLE_NODE_DEQUE.replace("RuneLiteIterable", ""))
|
||||
);
|
||||
|
||||
Method copy = new Method(nodeDequeVanilla, "iterator", new Signature("()Ljava/util/Iterator;"));
|
||||
copy.setPublic();
|
||||
|
||||
final Code code = new Code(copy);
|
||||
code.setMaxStack(3);
|
||||
copy.setCode(code);
|
||||
nodeDequeVanilla.addMethod(copy);
|
||||
|
||||
final Instructions instructions = code.getInstructions();
|
||||
final List<Instruction> ins = instructions.getInstructions();
|
||||
|
||||
ins.add(new New(instructions, runeliteIterableNodeDequeVanilla.getPoolClass()));
|
||||
ins.add(new Dup(instructions));
|
||||
ins.add(new ALoad(instructions, 0));
|
||||
ins.add(new InvokeSpecial(instructions, new net.runelite.asm.pool.Method(runeliteIterableNodeDequeVanilla.getPoolClass(), "<init>", new Signature("(L" + nodeDequeVanilla.getName() + ";)V"))));
|
||||
ins.add(new Return(instructions, InstructionType.ARETURN));
|
||||
}
|
||||
|
||||
public void injectLinkDeque()
|
||||
{
|
||||
ClassFile runeliteIterableLinkDequeVanilla = inject.getVanilla().findClass(RUNELITE_ITERABLE_LINK_DEQUE);
|
||||
|
||||
final ClassFile linkDequeVanilla = inject.toVanilla(
|
||||
inject.getDeobfuscated()
|
||||
.findClass(RUNELITE_ITERABLE_LINK_DEQUE.replace("RuneLiteIterable", ""))
|
||||
);
|
||||
|
||||
Method copy = new Method(linkDequeVanilla, "iterator", new Signature("()Ljava/util/Iterator;"));
|
||||
copy.setPublic();
|
||||
|
||||
final Code code = new Code(copy);
|
||||
code.setMaxStack(3);
|
||||
copy.setCode(code);
|
||||
linkDequeVanilla.addMethod(copy);
|
||||
|
||||
final Instructions instructions = code.getInstructions();
|
||||
final List<Instruction> ins = instructions.getInstructions();
|
||||
|
||||
ins.add(new New(instructions, runeliteIterableLinkDequeVanilla.getPoolClass()));
|
||||
ins.add(new Dup(instructions));
|
||||
ins.add(new ALoad(instructions, 0));
|
||||
ins.add(new InvokeSpecial(instructions, new net.runelite.asm.pool.Method(runeliteIterableLinkDequeVanilla.getPoolClass(), "<init>", new Signature("(L" + linkDequeVanilla.getName() + ";)V"))));
|
||||
ins.add(new Return(instructions, InstructionType.ARETURN));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Owain van Brakel <https://github.com/Owain94>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
//import com.openosrs.injector.InjectUtil;
|
||||
|
||||
import com.openosrs.injector.InjectUtil;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.AbstractInjector;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
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.instructions.BAStore;
|
||||
import net.runelite.asm.attributes.code.instructions.Dup;
|
||||
import net.runelite.asm.attributes.code.instructions.GetStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.ILoad;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeSpecial;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.New;
|
||||
import net.runelite.asm.attributes.code.instructions.Return;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
|
||||
public class RuneliteMenuEntry extends AbstractInjector
|
||||
{
|
||||
private static final String RUNELITE_MENU_ENTRY = "RuneLiteMenuEntry";
|
||||
|
||||
public RuneliteMenuEntry(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
|
||||
public void inject()
|
||||
{
|
||||
addInvoke("newRuneliteMenuEntry", true);
|
||||
addInvoke("newBareRuneliteMenuEntry", false);
|
||||
addSwap(InjectUtil.findMethod(inject, "menu"), InjectUtil.findField(inject, "menuShiftClick", "Client"));
|
||||
}
|
||||
|
||||
private void addInvoke(String methodName, boolean iload)
|
||||
{
|
||||
ClassFile runeliteMenuEntryVanilla = inject.getVanilla().findClass(RUNELITE_MENU_ENTRY);
|
||||
|
||||
final ClassFile clientVanilla = inject.toVanilla(
|
||||
inject.getDeobfuscated()
|
||||
.findClass("Client")
|
||||
);
|
||||
|
||||
Method copy = clientVanilla.findMethod(methodName);
|
||||
|
||||
final Code code = new Code(copy);
|
||||
code.setMaxStack(3);
|
||||
copy.setCode(code);
|
||||
|
||||
final Instructions instructions = code.getInstructions();
|
||||
final List<Instruction> ins = instructions.getInstructions();
|
||||
|
||||
ins.add(new New(instructions, runeliteMenuEntryVanilla.getPoolClass()));
|
||||
ins.add(new Dup(instructions));
|
||||
if (iload)
|
||||
{
|
||||
ins.add(new ILoad(instructions, 0));
|
||||
ins.add(new InvokeSpecial(instructions, new net.runelite.asm.pool.Method(runeliteMenuEntryVanilla.getPoolClass(), "<init>", new Signature("(I)V"))));
|
||||
}
|
||||
else
|
||||
{
|
||||
ins.add(new InvokeSpecial(instructions, new net.runelite.asm.pool.Method(runeliteMenuEntryVanilla.getPoolClass(), "<init>", new Signature("()V"))));
|
||||
}
|
||||
ins.add(new Return(instructions, InstructionType.ARETURN));
|
||||
}
|
||||
|
||||
private void addSwap(Method method, Field field)
|
||||
{
|
||||
final ClassFile clientVanilla = inject.toVanilla(
|
||||
inject.getDeobfuscated()
|
||||
.findClass("Client")
|
||||
);
|
||||
|
||||
Instructions ins = method.getCode().getInstructions();
|
||||
ListIterator<Instruction> iterator = ins.getInstructions().listIterator();
|
||||
|
||||
int found = 0;
|
||||
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
Instruction i = iterator.next();
|
||||
|
||||
if (found < 1)
|
||||
{
|
||||
if (!(i instanceof GetStatic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (((GetStatic) i).getField().getName().equals(field.getName()))
|
||||
{
|
||||
found += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(i instanceof BAStore))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ILoad i1 = new ILoad(ins, 3);
|
||||
InvokeStatic i2 = new InvokeStatic(ins, new net.runelite.asm.pool.Method(clientVanilla.getPoolClass(), "swapMenuEntries", new Signature("(I)V")));
|
||||
|
||||
iterator.add(i1);
|
||||
iterator.add(i2);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Owain van Brakel <https://github.com/Owain94>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.AbstractInjector;
|
||||
import java.util.List;
|
||||
import net.runelite.asm.ClassFile;
|
||||
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.instructions.Dup;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeSpecial;
|
||||
import net.runelite.asm.attributes.code.instructions.New;
|
||||
import net.runelite.asm.attributes.code.instructions.Return;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
|
||||
public class RuneliteObject extends AbstractInjector
|
||||
{
|
||||
private static final String RUNELITE_OBJECT = "RuneLiteObject";
|
||||
|
||||
public RuneliteObject(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
|
||||
public void inject()
|
||||
{
|
||||
ClassFile runeliteObjectVanilla = inject.getVanilla().findClass(RUNELITE_OBJECT);
|
||||
|
||||
final ClassFile clientVanilla = inject.toVanilla(
|
||||
inject.getDeobfuscated()
|
||||
.findClass("Client")
|
||||
);
|
||||
|
||||
Method copy = new Method(clientVanilla, "createRuneLiteObject", new Signature("()Lnet/runelite/api/RuneLiteObject;"));
|
||||
copy.setPublic();
|
||||
|
||||
final Code code = new Code(copy);
|
||||
code.setMaxStack(2);
|
||||
copy.setCode(code);
|
||||
clientVanilla.addMethod(copy);
|
||||
|
||||
final Instructions instructions = code.getInstructions();
|
||||
final List<Instruction> ins = instructions.getInstructions();
|
||||
|
||||
ins.add(new New(instructions, runeliteObjectVanilla.getPoolClass()));
|
||||
ins.add(new Dup(instructions));
|
||||
ins.add(new InvokeSpecial(instructions, new net.runelite.asm.pool.Method(runeliteObjectVanilla.getPoolClass(), "<init>", new Signature("()V"))));
|
||||
ins.add(new Return(instructions, InstructionType.ARETURN));
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2018 Abex
|
||||
* All rights reserved.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
@@ -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()));
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
@@ -43,6 +43,7 @@ import net.runelite.asm.attributes.code.Instructions;
|
||||
import net.runelite.asm.attributes.code.instructions.ALoad;
|
||||
import net.runelite.asm.attributes.code.instructions.BiPush;
|
||||
import net.runelite.asm.attributes.code.instructions.CheckCast;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeInterface;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.InvokeVirtual;
|
||||
import net.runelite.asm.attributes.code.instructions.LDC;
|
||||
@@ -131,6 +132,10 @@ public class InjectInvoke
|
||||
{
|
||||
ins.add(new InvokeStatic(instructions, vanillaMethod.getPoolMethod()));
|
||||
}
|
||||
else if (vanillaMethod.getClassFile().isInterface())
|
||||
{
|
||||
ins.add(new InvokeInterface(instructions, vanillaMethod.getPoolMethod()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ins.add(new InvokeVirtual(instructions, vanillaMethod.getPoolMethod()));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
@@ -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,14 +89,28 @@ 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));
|
||||
}
|
||||
|
||||
if (!apiMethod.getSignature().getReturnValue().equals(Type.VOID))
|
||||
{
|
||||
ins.add(new ALoad(instructions, 0));
|
||||
ins.add(InjectUtil.createReturnForType(instructions, apiMethod.getSignature().getReturnValue()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ins.add(new VReturn(instructions));
|
||||
}
|
||||
|
||||
targetClass.addMethod(method);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.rsapi;
|
||||
|
||||
@@ -15,8 +15,10 @@ import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.runelite.asm.Type;
|
||||
@@ -45,7 +47,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 +76,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();
|
||||
|
||||
@@ -108,17 +114,19 @@ public class RSApi implements Iterable<RSApiClass>
|
||||
return findClass(name) != null;
|
||||
}
|
||||
|
||||
public RSApiClass withInterface(Class interf)
|
||||
public Set<RSApiClass> withInterface(Class interf)
|
||||
{
|
||||
RSApiClass clazz = findClass(interf.getName());
|
||||
if (clazz != null)
|
||||
return clazz;
|
||||
Set<RSApiClass> classes = new HashSet<>();
|
||||
|
||||
for (RSApiClass apiC : this)
|
||||
{
|
||||
if (apiC.getInterfaces().contains(interf))
|
||||
return apiC;
|
||||
{
|
||||
classes.add(apiC);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return classes;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.rsapi;
|
||||
|
||||
import static com.openosrs.injector.rsapi.RSApi.CONSTRUCT;
|
||||
import static com.openosrs.injector.rsapi.RSApi.IMPORT;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
@@ -22,8 +24,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import static com.openosrs.injector.rsapi.RSApi.CONSTRUCT;
|
||||
import static com.openosrs.injector.rsapi.RSApi.IMPORT;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -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,12 +58,14 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RSApiMethod addMethod(String name, Signature sig, int access)
|
||||
{
|
||||
@@ -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,8 +101,10 @@ 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)
|
||||
{
|
||||
|
||||
@@ -3,15 +3,13 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.transformers;
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2020, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.transformers;
|
||||
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.Method;
|
||||
import net.runelite.asm.attributes.Code;
|
||||
import net.runelite.asm.attributes.code.Exception;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public class Java8Ifier extends InjectTransformer
|
||||
{
|
||||
public Java8Ifier(InjectData inject)
|
||||
{
|
||||
super(inject);
|
||||
}
|
||||
|
||||
@Override
|
||||
void transformImpl()
|
||||
{
|
||||
inject.forEachPair(this::makeJava8);
|
||||
}
|
||||
|
||||
private void makeJava8(ClassFile rsc, ClassFile vanilla)
|
||||
{
|
||||
vanilla.setVersion(Opcodes.V1_8);
|
||||
for (Method method : vanilla.getMethods())
|
||||
{
|
||||
if (!method.getName().equals("<init>"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fixTryCatch(method);
|
||||
}
|
||||
}
|
||||
|
||||
private void fixTryCatch(Method method)
|
||||
{
|
||||
Code code = method.getCode();
|
||||
List<Exception> remove = code.getExceptions().getExceptions().stream().filter(e -> e.getCatchType() != null && e.getCatchType().getName().equals("java/lang/RuntimeException")).collect(Collectors.toList());
|
||||
remove.forEach(code.getExceptions()::remove);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is licensed under GPL3, see the complete license in
|
||||
* the LICENSE file in the root directory of this source tree.
|
||||
* the LICENSE file in the root directory of this submodule.
|
||||
*/
|
||||
package com.openosrs.injector.transformers;
|
||||
|
||||
|
||||
@@ -16,13 +16,16 @@ 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
|
||||
|
||||
@get:OutputFile
|
||||
abstract val output: RegularFileProperty
|
||||
|
||||
@get:OutputFile
|
||||
abstract val hash: RegularFileProperty
|
||||
|
||||
@TaskAction
|
||||
fun inject() {
|
||||
val vanilla = extension.vanilla.get().asFile
|
||||
@@ -30,10 +33,18 @@ abstract class Inject: DefaultTask() {
|
||||
val mixins = extension.mixins.get().asFile
|
||||
val rsapi = project.zipTree(extension.rsapi)
|
||||
|
||||
val injector: InjectTaskHandler = Injection(vanilla, rsclient, mixins, rsapi)
|
||||
val injector: InjectTaskHandler = Injection(
|
||||
vanilla,
|
||||
rsclient,
|
||||
mixins,
|
||||
rsapi,
|
||||
if (extension.development.isPresent) extension.development.get() else true,
|
||||
if (extension.skip.isPresent) extension.skip.get() else ""
|
||||
)
|
||||
|
||||
injector.inject()
|
||||
|
||||
injector.save(output.get().asFile)
|
||||
injector.hash(hash.get().asFile, vanilla)
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,27 @@
|
||||
package com.openosrs.injector
|
||||
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
|
||||
interface InjectExtension {
|
||||
@get:Input
|
||||
@get:Optional
|
||||
val development: Property<Boolean>
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
val skip: Property<String>
|
||||
|
||||
@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,13 +10,20 @@ 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) {
|
||||
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") }
|
||||
task.output.convention {
|
||||
file("$buildDir/libs/injected-client.oprs")
|
||||
}
|
||||
task.hash.convention {
|
||||
file("$buildDir/resources/main/client.hash")
|
||||
}
|
||||
|
||||
artifacts {
|
||||
it.add("runtimeElements", task.output)
|
||||
it.add("runtimeElements", task.hash)
|
||||
}
|
||||
|
||||
tasks.getByName("assemble") {
|
||||
@@ -24,5 +31,6 @@ class InjectPlugin: Plugin<Project> {
|
||||
}
|
||||
|
||||
extensions.add(InjectExtension::class.java, "injector", task.extension)
|
||||
}}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@
|
||||
*/
|
||||
package com.openosrs.injector.injectors;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.openosrs.injector.TestInjection;
|
||||
import com.openosrs.injector.rsapi.RSApi;
|
||||
import java.io.IOException;
|
||||
@@ -50,12 +49,12 @@ import net.runelite.asm.attributes.code.instructions.InvokeVirtual;
|
||||
import net.runelite.asm.attributes.code.instructions.LDC;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import net.runelite.asm.visitors.ClassFileVisitor;
|
||||
import net.runelite.deob.util.JarUtil;
|
||||
import net.runelite.mapping.ObfuscatedGetter;
|
||||
import net.runelite.mapping.ObfuscatedName;
|
||||
import net.runelite.mapping.ObfuscatedSignature;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
@@ -80,6 +79,25 @@ class DeobTarget
|
||||
}
|
||||
}
|
||||
|
||||
@ObfuscatedName("com/openosrs/injector/injectors/VanillaTarget2")
|
||||
class DeobTarget2
|
||||
{
|
||||
@ObfuscatedName("ob_foo5")
|
||||
@ObfuscatedGetter(intValue = 1157381415)
|
||||
static int foo5;
|
||||
|
||||
@ObfuscatedName("ob_foo6")
|
||||
@ObfuscatedSignature(
|
||||
descriptor = "(I)V",
|
||||
garbageValue = "123"
|
||||
)
|
||||
private void foo6()
|
||||
{
|
||||
// De-obfuscated foo6
|
||||
System.out.println("foo6");
|
||||
}
|
||||
}
|
||||
|
||||
class VanillaTarget
|
||||
{
|
||||
static int ob_foo4;
|
||||
@@ -95,6 +113,21 @@ class VanillaTarget
|
||||
}
|
||||
}
|
||||
|
||||
class VanillaTarget2
|
||||
{
|
||||
static int ob_foo5;
|
||||
|
||||
private void ob_foo6(int garbageValue)
|
||||
{
|
||||
// Obfuscated foo6
|
||||
if (garbageValue != 123)
|
||||
{
|
||||
return;
|
||||
}
|
||||
System.out.println("foo6");
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Source
|
||||
{
|
||||
@net.runelite.api.mixins.Inject
|
||||
@@ -130,28 +163,39 @@ abstract class Source2
|
||||
}
|
||||
}
|
||||
|
||||
// Test injecting a field into multiple vanilla classes (@Mixins)
|
||||
abstract class Source3
|
||||
{
|
||||
@net.runelite.api.mixins.Inject
|
||||
private boolean injectMe;
|
||||
}
|
||||
|
||||
public class MixinInjectorTest
|
||||
{
|
||||
@Test
|
||||
public void testInject() throws Exception
|
||||
{
|
||||
InputStream deobIn = getClass().getResourceAsStream("DeobTarget.class");
|
||||
ClassFile deobTarget = JarUtil.loadClass(ByteStreams.toByteArray(deobIn));
|
||||
ClassFile deobTarget = loadClass(DeobTarget.class);
|
||||
ClassFile deobTarget2 = loadClass(DeobTarget2.class);
|
||||
|
||||
ClassGroup deob = new ClassGroup();
|
||||
deob.addClass(deobTarget);
|
||||
deob.addClass(deobTarget2);
|
||||
|
||||
InputStream vanillaIn = getClass().getResourceAsStream("VanillaTarget.class");
|
||||
ClassFile vanillaTarget = JarUtil.loadClass(ByteStreams.toByteArray(vanillaIn));
|
||||
ClassFile vanillaTarget = loadClass(VanillaTarget.class);
|
||||
ClassFile vanillaTarget2 = loadClass(VanillaTarget2.class);
|
||||
|
||||
ClassGroup vanilla = new ClassGroup();
|
||||
vanilla.addClass(vanillaTarget);
|
||||
vanilla.addClass(vanillaTarget2);
|
||||
|
||||
Map<Provider<ClassFile>, List<ClassFile>> mixinClasses = new HashMap<>();
|
||||
mixinClasses.put(() -> loadClass(Source.class), Collections.singletonList(vanillaTarget));
|
||||
mixinClasses.put(() -> loadClass(Source2.class), Collections.singletonList(vanillaTarget));
|
||||
mixinClasses.put(() -> loadClass(Source3.class), List.of(vanillaTarget, vanillaTarget2));
|
||||
|
||||
TestInjection inject = new TestInjection(vanilla, deob, new ClassGroup(), new RSApi());
|
||||
inject.initToVanilla();
|
||||
new MixinInjector(inject).inject(mixinClasses);
|
||||
|
||||
// Check if "foo" has been injected
|
||||
@@ -203,12 +247,7 @@ public class MixinInjectorTest
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!field.getName().equals("ob_foo4"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return field.getName().equals("ob_foo4");
|
||||
})
|
||||
.count(), 1);
|
||||
|
||||
@@ -233,12 +272,7 @@ public class MixinInjectorTest
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!method.getName().equals("copy$foo3"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return method.getName().equals("copy$foo3");
|
||||
})
|
||||
.count(), 1);
|
||||
|
||||
@@ -267,14 +301,11 @@ public class MixinInjectorTest
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!field.getName().equals("foo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return field.getName().equals("foo");
|
||||
})
|
||||
.count(), 1);
|
||||
|
||||
assertTrue(fieldExists(List.of(vanillaTarget, vanillaTarget2), "injectMe"));
|
||||
}
|
||||
|
||||
private boolean getStaticHasGetter(Method ob_foo3, String gottenField)
|
||||
@@ -283,7 +314,7 @@ 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 &&
|
||||
@@ -291,6 +322,19 @@ public class MixinInjectorTest
|
||||
it.next() instanceof IMul;
|
||||
}
|
||||
|
||||
private boolean fieldExists(List<ClassFile> classes, String name)
|
||||
{
|
||||
for (ClassFile c : classes)
|
||||
{
|
||||
if (c.findField(name) == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static ClassFile loadClass(Class<?> clazz)
|
||||
{
|
||||
try (InputStream is = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.', '/') + ".class"))
|
||||
|
||||
@@ -30,6 +30,10 @@ 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.asm.Field;
|
||||
import net.runelite.asm.Type;
|
||||
import static net.runelite.deob.DeobAnnotations.OBFUSCATED_NAME;
|
||||
import static net.runelite.deob.DeobAnnotations.OBFUSCATED_SIGNATURE;
|
||||
import net.runelite.deob.util.JarUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -55,6 +59,8 @@ public class DrawAfterWidgetsTest
|
||||
vanilla.addClass(obRasterizer);
|
||||
|
||||
InjectData inject = new TestInjection(vanilla, deob, new ClassGroup(), new RSApi());
|
||||
addPhonyFields(deob, vanilla);
|
||||
inject.initToVanilla();
|
||||
new DrawAfterWidgets(inject).inject();
|
||||
}
|
||||
|
||||
@@ -78,6 +84,24 @@ public class DrawAfterWidgetsTest
|
||||
vanilla.addClass(obRasterizer);
|
||||
|
||||
InjectData inject = new TestInjection(vanilla, deob, new ClassGroup(), new RSApi());
|
||||
addPhonyFields(deob, vanilla);
|
||||
inject.initToVanilla();
|
||||
new DrawAfterWidgets(inject).inject();
|
||||
}
|
||||
|
||||
private static void addPhonyFields(ClassGroup deob, ClassGroup vanilla)
|
||||
{
|
||||
final ClassFile d = deob.findClass("Client");
|
||||
final ClassFile v = vanilla.findClass("client");
|
||||
final Field clientD = new Field(d, "client", new Type("LClient;"));
|
||||
clientD.findAnnotation(OBFUSCATED_NAME, true).setElement("obclient");
|
||||
clientD.findAnnotation(OBFUSCATED_SIGNATURE, true).setElement("descriptor", "Lclient;");
|
||||
clientD.setStatic();
|
||||
d.addField(clientD);
|
||||
final Field clientV = new Field(v, "obclient", new Type("Lclient;"));
|
||||
clientV.setStatic();
|
||||
v.addField(clientV);
|
||||
final Field callbacks = new Field(v, "callbacks", new Type("LCallbacks;"));
|
||||
v.addField(callbacks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ 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.asm.Method;
|
||||
import net.runelite.asm.signature.Signature;
|
||||
import net.runelite.deob.util.JarUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -32,6 +34,9 @@ public class DrawMenuTest
|
||||
|
||||
InjectData inject = new TestInjection(van, deob, new ClassGroup(), new RSApi());
|
||||
|
||||
addPhonyMethod(van);
|
||||
|
||||
inject.initToVanilla();
|
||||
new DrawMenu(inject).inject();
|
||||
}
|
||||
|
||||
@@ -49,6 +54,18 @@ public class DrawMenuTest
|
||||
|
||||
InjectData inject = new TestInjection(van, deob, new ClassGroup(), new RSApi());
|
||||
|
||||
addPhonyMethod(van);
|
||||
|
||||
inject.initToVanilla();
|
||||
new DrawMenu(inject).inject();
|
||||
}
|
||||
|
||||
private void addPhonyMethod(ClassGroup vanilla)
|
||||
{
|
||||
final ClassFile c = vanilla.findClass("client");
|
||||
|
||||
final Method clientM = new Method(c, "drawMenu", new Signature("()Z"));
|
||||
clientM.setStatic(true);
|
||||
c.addMethod(clientM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user