Merge pull request #3119 from Lucwousin/inj-mixins-fields
This commit is contained in:
@@ -14,8 +14,10 @@ dependencies {
|
||||
vanillaDep(group = "net.runelite.rs", name = "vanilla", version = rsversion.toString())
|
||||
|
||||
annotationProcessor(group = "org.projectlombok", name = "lombok", version = ProjectVersions.lombokVersion)
|
||||
testAnnotationProcessor(group = "org.projectlombok", name = "lombok", version = ProjectVersions.lombokVersion)
|
||||
|
||||
compileOnly(group = "org.projectlombok", name = "lombok", version = ProjectVersions.lombokVersion)
|
||||
testCompileOnly(group = "org.projectlombok", name = "lombok", version = ProjectVersions.lombokVersion)
|
||||
|
||||
implementation(gradleApi())
|
||||
|
||||
@@ -29,6 +31,8 @@ dependencies {
|
||||
implementation(group = "org.jetbrains", name = "annotations", version = "22.0.0")
|
||||
implementation(group = "com.google.guava", name = "guava", version = "30.1.1-jre")
|
||||
implementation(group = "net.sf.jopt-simple", name = "jopt-simple", version = "5.0.4")
|
||||
|
||||
testImplementation(group = "junit", name = "junit", version = "4.12")
|
||||
}
|
||||
|
||||
tasks.register<JavaExec>("inject") {
|
||||
|
||||
@@ -13,7 +13,9 @@ import com.openosrs.injector.rsapi.RSApi;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.ClassGroup;
|
||||
import net.runelite.asm.Field;
|
||||
@@ -24,6 +26,8 @@ import net.runelite.asm.signature.Signature;
|
||||
/**
|
||||
* Abstract class meant as the interface of {@link com.openosrs.injector.Injector injection} for injectors
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public abstract class InjectData
|
||||
{
|
||||
public static final String HOOKS = "net/runelite/client/callback/Hooks";
|
||||
|
||||
@@ -217,13 +217,21 @@ public class MixinInjector extends AbstractInjector
|
||||
}
|
||||
}
|
||||
|
||||
targetClass.addField(copy);
|
||||
|
||||
if (injectedFields.containsKey(field.getName()) && !ASSERTION_FIELD.equals(field.getName()))
|
||||
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 static field: " + field.getName());
|
||||
}
|
||||
|
||||
injectedFields.put(field.getName(), copy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 source tree.
|
||||
*/
|
||||
package com.openosrs.injector;
|
||||
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.Injector;
|
||||
import com.openosrs.injector.rsapi.RSApi;
|
||||
import net.runelite.asm.ClassGroup;
|
||||
|
||||
public class TestInjection extends InjectData
|
||||
{
|
||||
public TestInjection(ClassGroup vanilla, ClassGroup deobfuscated, ClassGroup mixins, RSApi rsApi)
|
||||
{
|
||||
super(vanilla, deobfuscated, mixins, rsApi);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runChildInjector(Injector injector) throws InjectException
|
||||
{
|
||||
injector.inject();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (c) 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.TestInjection;
|
||||
import com.openosrs.injector.rsapi.RSApi;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import javax.inject.Provider;
|
||||
import net.runelite.api.mixins.Copy;
|
||||
import net.runelite.api.mixins.Replace;
|
||||
import net.runelite.api.mixins.Shadow;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.ClassGroup;
|
||||
import net.runelite.asm.Field;
|
||||
import net.runelite.asm.Method;
|
||||
import static net.runelite.asm.Type.INT;
|
||||
import net.runelite.asm.attributes.code.Instruction;
|
||||
import net.runelite.asm.attributes.code.instructions.GetStatic;
|
||||
import net.runelite.asm.attributes.code.instructions.IMul;
|
||||
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.mapping.ObfuscatedGetter;
|
||||
import net.runelite.mapping.ObfuscatedName;
|
||||
import net.runelite.mapping.ObfuscatedSignature;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
|
||||
@ObfuscatedName("com/openosrs/injector/injectors/VanillaTarget")
|
||||
class DeobTarget
|
||||
{
|
||||
@ObfuscatedName("ob_foo4")
|
||||
@ObfuscatedGetter(intValue = 1157381415)
|
||||
static int foo4;
|
||||
|
||||
@ObfuscatedName("ob_foo3")
|
||||
@ObfuscatedSignature(
|
||||
descriptor = "(I)V",
|
||||
garbageValue = "123"
|
||||
)
|
||||
private void foo3()
|
||||
{
|
||||
// De-obfuscated foo3
|
||||
System.out.println("foo3");
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
private void ob_foo3(int garbageValue)
|
||||
{
|
||||
// Obfuscated foo3
|
||||
if (garbageValue != 123)
|
||||
{
|
||||
return;
|
||||
}
|
||||
System.out.println("foo3");
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
private static int foo;
|
||||
@Shadow("foo4")
|
||||
private static int foo4;
|
||||
|
||||
@net.runelite.api.mixins.Inject
|
||||
private void foo2()
|
||||
{
|
||||
}
|
||||
|
||||
@Copy("foo3")
|
||||
@Replace("foo3")
|
||||
private void copy$foo3()
|
||||
{
|
||||
System.out.println("replaced");
|
||||
System.out.println(foo4);
|
||||
copy$foo3();
|
||||
}
|
||||
}
|
||||
|
||||
// Test shadowing the "foo" field injected by Source
|
||||
abstract class Source2
|
||||
{
|
||||
@Shadow("foo")
|
||||
private static int foo;
|
||||
|
||||
@net.runelite.api.mixins.Inject
|
||||
private void foo5()
|
||||
{
|
||||
System.out.println(foo);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
ClassFile deobTarget = loadClass(DeobTarget.class);
|
||||
ClassFile deobTarget2 = loadClass(DeobTarget2.class);
|
||||
|
||||
ClassGroup deob = new ClassGroup();
|
||||
deob.addClass(deobTarget);
|
||||
deob.addClass(deobTarget2);
|
||||
|
||||
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
|
||||
Field foo = vanillaTarget.findField("foo");
|
||||
assertNotNull(foo);
|
||||
assertEquals(INT, foo.getType());
|
||||
assertEquals(ACC_PUBLIC | ACC_STATIC, foo.getAccessFlags());
|
||||
|
||||
// Check if "foo2()V" has been injected
|
||||
Method foo2 = vanillaTarget.findMethod("foo2");
|
||||
assertNotNull(foo2);
|
||||
assertEquals(new Signature("()V"), foo2.getDescriptor());
|
||||
assertEquals(ACC_PUBLIC, foo2.getAccessFlags());
|
||||
|
||||
// Check if "ob_foo3(I)V" was copied
|
||||
Method foo3 = vanillaTarget.findMethod("copy$foo3");
|
||||
assertNotNull(foo3);
|
||||
assertEquals(new Signature("(I)V"), foo3.getDescriptor());
|
||||
assertEquals(ACC_PUBLIC, foo3.getAccessFlags());
|
||||
|
||||
// Check if "ob_foo3(I)V" was replaced
|
||||
Method ob_foo3 = vanillaTarget.findMethod("ob_foo3");
|
||||
assertNotNull(ob_foo3);
|
||||
assertEquals(new Signature("(I)V"), ob_foo3.getDescriptor());
|
||||
assertEquals(ob_foo3
|
||||
.getCode()
|
||||
.getInstructions()
|
||||
.getInstructions()
|
||||
.stream()
|
||||
.filter(i -> i instanceof LDC && ((LDC) i).getConstant().equals("replaced"))
|
||||
.count(), 1);
|
||||
// Check that the "foo4" field access in the new code body was mapped correctly
|
||||
assertEquals(ob_foo3
|
||||
.getCode()
|
||||
.getInstructions()
|
||||
.getInstructions()
|
||||
.stream()
|
||||
.filter(i ->
|
||||
{
|
||||
if (!(i instanceof GetStatic))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
net.runelite.asm.pool.Field field = ((GetStatic) i).getField();
|
||||
|
||||
if (!field.getClazz().getName().equals("com/openosrs/injector/injectors/VanillaTarget"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!field.getName().equals("ob_foo4"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.count(), 1);
|
||||
|
||||
assert getStaticHasGetter(ob_foo3, "ob_foo4");
|
||||
// Check that the "foo3()" call in the new code body was mapped to the copy
|
||||
assertEquals(ob_foo3
|
||||
.getCode()
|
||||
.getInstructions()
|
||||
.getInstructions()
|
||||
.stream()
|
||||
.filter(i ->
|
||||
{
|
||||
if (!(i instanceof InvokeVirtual))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
net.runelite.asm.pool.Method method = ((InvokeVirtual) i).getMethod();
|
||||
|
||||
if (!method.getClazz().getName().equals("com/openosrs/injector/injectors/VanillaTarget"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!method.getName().equals("copy$foo3"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.count(), 1);
|
||||
|
||||
// Check if "foo5()V" was injected
|
||||
Method foo5 = vanillaTarget.findMethod("foo5");
|
||||
assertNotNull(foo5);
|
||||
assertEquals(new Signature("()V"), foo5.getDescriptor());
|
||||
assertEquals(ACC_PUBLIC, foo5.getAccessFlags());
|
||||
// Check that the shadow "foo" field access was mapped correctly
|
||||
assertEquals(foo5
|
||||
.getCode()
|
||||
.getInstructions()
|
||||
.getInstructions()
|
||||
.stream()
|
||||
.filter(i ->
|
||||
{
|
||||
if (!(i instanceof GetStatic))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
net.runelite.asm.pool.Field field = ((GetStatic) i).getField();
|
||||
|
||||
if (!field.getClazz().getName().equals("com/openosrs/injector/injectors/VanillaTarget"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!field.getName().equals("foo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.count(), 1);
|
||||
|
||||
assertTrue(fieldExists(List.of(vanillaTarget, vanillaTarget2), "injectMe"));
|
||||
}
|
||||
|
||||
private boolean getStaticHasGetter(Method ob_foo3, String gottenField)
|
||||
{
|
||||
ListIterator<Instruction> it = ob_foo3.getCode().getInstructions().listIterator();
|
||||
Instruction i;
|
||||
while (it.hasNext() &&
|
||||
!((i = it.next()) instanceof GetStatic &&
|
||||
((GetStatic) i).getField().getName().equals(gottenField)));
|
||||
|
||||
return
|
||||
(i = it.next()) instanceof LDC &&
|
||||
((LDC) i).getConstantAsInt() == 1157381415 &&
|
||||
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"))
|
||||
{
|
||||
ClassReader reader = new ClassReader(is);
|
||||
ClassFileVisitor cv = new ClassFileVisitor();
|
||||
|
||||
reader.accept(cv, 0);
|
||||
|
||||
return cv.getClassFile();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.openosrs.injector.InjectUtil;
|
||||
import com.openosrs.injector.TestInjection;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.rsapi.RSApi;
|
||||
import javax.swing.plaf.TabbedPaneUI;
|
||||
import net.runelite.asm.Annotation;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.ClassGroup;
|
||||
import net.runelite.asm.Field;
|
||||
import net.runelite.asm.Named;
|
||||
import net.runelite.asm.Type;
|
||||
import net.runelite.asm.attributes.Annotated;
|
||||
import net.runelite.deob.DeobAnnotations;
|
||||
import net.runelite.deob.util.JarUtil;
|
||||
import org.junit.Test;
|
||||
import static net.runelite.deob.DeobAnnotations.OBFUSCATED_NAME;
|
||||
import static net.runelite.deob.DeobAnnotations.OBFUSCATED_SIGNATURE;
|
||||
|
||||
public class DrawAfterWidgetsTest
|
||||
{
|
||||
@Test
|
||||
public void testInjectDrawWidgetsRev160() throws Exception
|
||||
{
|
||||
// Rev 160 does not have the drawWidgets call inlined
|
||||
|
||||
ClassFile deobClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_deob160.class")));
|
||||
ClassFile deobRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_deob160.class")));
|
||||
|
||||
ClassGroup deob = new ClassGroup();
|
||||
deob.addClass(deobClient);
|
||||
deob.addClass(deobRasterizer);
|
||||
|
||||
ClassFile obClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_ob160.class")));
|
||||
ClassFile obRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_ob160.class")));
|
||||
|
||||
ClassGroup vanilla = new ClassGroup();
|
||||
vanilla.addClass(obClient);
|
||||
vanilla.addClass(obRasterizer);
|
||||
|
||||
InjectData inject = new TestInjection(vanilla, deob, new ClassGroup(), new RSApi());
|
||||
addPhonyFields(deob, vanilla);
|
||||
inject.initToVanilla();
|
||||
new DrawAfterWidgets(inject).inject();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInjectDrawWidgetsRev180() throws Exception
|
||||
{
|
||||
// Rev 180 has the drawWidgets call inlined
|
||||
|
||||
ClassFile deobClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_deob180.class")));
|
||||
ClassFile deobRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_deob180.class")));
|
||||
|
||||
ClassGroup deob = new ClassGroup();
|
||||
deob.addClass(deobClient);
|
||||
deob.addClass(deobRasterizer);
|
||||
|
||||
ClassFile obClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_ob180.class")));
|
||||
ClassFile obRasterizer = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Rasterizer2D_ob180.class")));
|
||||
|
||||
ClassGroup vanilla = new ClassGroup();
|
||||
vanilla.addClass(obClient);
|
||||
vanilla.addClass(obRasterizer);
|
||||
|
||||
InjectData inject = new TestInjection(vanilla, deob, new ClassGroup(), new RSApi());
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 source tree.
|
||||
*/
|
||||
package com.openosrs.injector.injectors.raw;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.openosrs.injector.TestInjection;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.rsapi.RSApi;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.ClassGroup;
|
||||
import net.runelite.deob.util.JarUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DrawMenuTest
|
||||
{
|
||||
@Test
|
||||
public void test160() throws Exception
|
||||
{
|
||||
// 160 has both drawMenu and drawTopLeftText inlined
|
||||
ClassFile deobClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_deob160.class")));
|
||||
ClassFile obClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_ob160.class")));
|
||||
|
||||
ClassGroup van = new ClassGroup();
|
||||
van.addClass(obClient);
|
||||
ClassGroup deob = new ClassGroup();
|
||||
deob.addClass(deobClient);
|
||||
|
||||
InjectData inject = new TestInjection(van, deob, new ClassGroup(), new RSApi());
|
||||
inject.initToVanilla();
|
||||
new DrawMenu(inject).inject();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test180() throws Exception
|
||||
{
|
||||
// 180 has only drawMenu inlined
|
||||
ClassFile deobClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_deob180.class")));
|
||||
ClassFile obClient = JarUtil.loadClass(ByteStreams.toByteArray(getClass().getResourceAsStream("/drawafterwidgets/Client_ob180.class")));
|
||||
|
||||
ClassGroup van = new ClassGroup();
|
||||
van.addClass(obClient);
|
||||
ClassGroup deob = new ClassGroup();
|
||||
deob.addClass(deobClient);
|
||||
|
||||
InjectData inject = new TestInjection(van, deob, new ClassGroup(), new RSApi());
|
||||
inject.initToVanilla();
|
||||
new DrawMenu(inject).inject();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 source tree.
|
||||
*/
|
||||
package com.openosrs.injector.transformers;
|
||||
|
||||
import com.openosrs.injector.InjectException;
|
||||
import com.openosrs.injector.injection.InjectData;
|
||||
import com.openosrs.injector.injectors.Injector;
|
||||
import com.openosrs.injector.transformers.srcchangeclasses.NewName;
|
||||
import com.openosrs.injector.transformers.srcchangeclasses.OldName;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.function.BiConsumer;
|
||||
import net.runelite.asm.ClassFile;
|
||||
import net.runelite.asm.ClassGroup;
|
||||
import net.runelite.asm.objectwebasm.NonloadingClassWriter;
|
||||
import net.runelite.asm.visitors.ClassFileVisitor;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
public class SourceChangerTest
|
||||
{
|
||||
private static final String PACKAGE = "com.openosrs.injector.transformers.srcchangeclasses.";
|
||||
|
||||
@Test
|
||||
@Ignore // Ignored because it's not really testing anything atm, but it works!
|
||||
public void test() throws Exception
|
||||
{
|
||||
final ClassFileVisitor deob = new ClassFileVisitor(), vann = new ClassFileVisitor();
|
||||
new ClassReader(PACKAGE + "NewName").accept(deob, ClassReader.SKIP_FRAMES);
|
||||
new ClassReader(PACKAGE + "OldName").accept(vann, ClassReader.SKIP_FRAMES);
|
||||
|
||||
new SourceChanger(
|
||||
new InjectData(new ClassGroup(), new ClassGroup(), null, null) {
|
||||
public void runChildInjector(Injector injector) throws InjectException
|
||||
{}
|
||||
|
||||
@Override
|
||||
public void forEachPair(BiConsumer<ClassFile, ClassFile> consumer)
|
||||
{
|
||||
consumer.accept(deob.getClassFile(), vann.getClassFile());
|
||||
}
|
||||
}).transformImpl();
|
||||
|
||||
final ClassGroup group = new ClassGroup();
|
||||
group.addClass(vann.getClassFile());
|
||||
|
||||
final ClassWriter cw = new NonloadingClassWriter(group, 0);
|
||||
vann.getClassFile().accept(cw);
|
||||
|
||||
OldName obj = (OldName) MethodHandles.privateLookupIn(
|
||||
NewName.class,
|
||||
MethodHandles.lookup())
|
||||
.defineClass(cw.toByteArray())
|
||||
.getDeclaredConstructor()
|
||||
.newInstance();
|
||||
|
||||
obj.obfMethodName();
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 source tree.
|
||||
*/
|
||||
package com.openosrs.injector.transformers.srcchangeclasses;
|
||||
|
||||
public class NewName
|
||||
{
|
||||
public void deobMethodName()
|
||||
{
|
||||
// do something interesting
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 source tree.
|
||||
*/
|
||||
package com.openosrs.injector.transformers.srcchangeclasses;
|
||||
|
||||
public class OldName
|
||||
{
|
||||
public void obfMethodName()
|
||||
{
|
||||
new RuntimeException().printStackTrace();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user