use of net.runelite.asm.ClassGroup in project runelite by runelite.
the class ClassGroupFactory method generateGroup.
public static ClassGroup generateGroup() {
ClassGroup group = new ClassGroup();
ClassFile cf = new ClassFile(group);
cf.setName("test");
cf.setSuperName("java/lang/Object");
group.addClass(cf);
Field field = new Field(cf, "field", Type.INT);
field.setStatic();
cf.addField(field);
Method method = new Method(cf, "func", new Signature("()V"));
method.setStatic();
cf.addMethod(method);
Code code = new Code(method);
method.setCode(code);
{
method = new Method(cf, "func2", new Signature("(III)V"));
method.setStatic();
cf.addMethod(method);
code = new Code(method);
method.setCode(code);
Instructions ins = code.getInstructions();
ins.addInstruction(new VReturn(ins));
}
addVoidMethod(cf, "void1");
addVoidMethod(cf, "void2");
addVoidMethod(cf, "void3");
addVoidMethod(cf, "void4");
return group;
}
use of net.runelite.asm.ClassGroup in project runelite by runelite.
the class MixinInjectorTest method testInject.
@Test
public void testInject() throws Exception {
InputStream deobIn = getClass().getResourceAsStream("DeobTarget.class");
ClassFile deobTarget = ClassUtil.loadClass(deobIn);
ClassGroup deob = new ClassGroup();
deob.addClass(deobTarget);
InputStream vanillaIn = getClass().getResourceAsStream("VanillaTarget.class");
ClassFile vanillaTarget = ClassUtil.loadClass(vanillaIn);
ClassGroup vanilla = new ClassGroup();
vanilla.addClass(vanillaTarget);
Map<Class<?>, List<ClassFile>> mixinClasses = new HashMap<>();
mixinClasses.put(Source.class, Collections.singletonList(vanillaTarget));
mixinClasses.put(Source2.class, Collections.singletonList(vanillaTarget));
Inject inject = new Inject(deob, vanilla);
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("net/runelite/injector/VanillaTarget")) {
return false;
}
if (!field.getName().equals("ob_foo4")) {
return false;
}
return true;
}).count(), 1);
// 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("net/runelite/injector/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("net/runelite/injector/VanillaTarget")) {
return false;
}
if (!field.getName().equals("foo")) {
return false;
}
return true;
}).count(), 1);
}
use of net.runelite.asm.ClassGroup in project runelite by runelite.
the class InjectMojo method execute.
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
ClientVersion ver = new ClientVersion(new File(vanillaPath));
int version;
try {
version = ver.getVersion();
} catch (IOException ex) {
throw new MojoExecutionException("Unable to read vanilla client version", ex);
}
log.info("Vanilla client version " + version);
ClassGroup rs;
ClassGroup vanilla;
try {
rs = JarUtil.loadJar(new File(rsClientPath));
vanilla = JarUtil.loadJar(new File(vanillaPath));
} catch (IOException ex) {
throw new MojoExecutionException("Unable to load dependency jars", ex);
}
Injector injector = new Injector(rs, vanilla);
try {
injector.inject();
} catch (InjectionException ex) {
throw new MojoExecutionException("Error injecting client", ex);
}
InjectorValidator iv = new InjectorValidator(vanilla);
iv.validate();
if (iv.getError() > 0) {
throw new MojoExecutionException("Error building injected jar");
}
if (iv.getMissing() > 0) {
throw new MojoExecutionException("Unable to inject all methods");
}
try {
writeClasses(vanilla, outputDirectory);
} catch (IOException ex) {
throw new MojoExecutionException("Unable to write classes", ex);
}
log.info("Injector wrote " + vanilla.getClasses().size() + " classes, " + iv.getOkay() + " injected methods");
}
use of net.runelite.asm.ClassGroup in project runelite by runelite.
the class InjectConstruct method inject.
public void inject(Map<ClassFile, java.lang.Class> implemented) throws InjectionException {
for (Entry<ClassFile, java.lang.Class> entry : implemented.entrySet()) {
Class<?> clazz = entry.getValue();
ClassFile cf = entry.getKey();
if (clazz == null) {
continue;
}
for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) {
if (method.isSynthetic()) {
continue;
}
Construct construct = method.getAnnotation(Construct.class);
if (construct == null) {
continue;
}
String obfuscatedName = DeobAnnotations.getObfuscatedName(cf.getAnnotations());
if (obfuscatedName == null) {
obfuscatedName = cf.getName();
}
ClassGroup vanilla = inject.getVanilla();
ClassFile other = vanilla.findClass(obfuscatedName);
assert other != null : "unable to find vanilla class from obfuscated name: " + obfuscatedName;
injectConstruct(other, method);
}
}
}
use of net.runelite.asm.ClassGroup in project runelite by runelite.
the class InjectInvoker method process.
/**
* Inject an invoker for a method
*
* @param m Method in the deobfuscated client to inject an invoker for
* @param other Class in the vanilla client of the same class m is a
* member of
* @param implementingClass Java class for the API interface the class
* will implement
*/
public void process(Method m, ClassFile other, java.lang.Class<?> implementingClass) {
Annotations an = m.getAnnotations();
if (an == null || an.find(EXPORT) == null) {
// not an exported method
return;
}
String exportedName = DeobAnnotations.getExportedName(an);
String obfuscatedName = DeobAnnotations.getObfuscatedName(an);
if (obfuscatedName == null) {
obfuscatedName = m.getName();
}
String garbage = DeobAnnotations.getObfuscatedValue(m);
Method otherm = other.findMethod(obfuscatedName, inject.getMethodSignature(m));
assert otherm != null;
assert m.isStatic() == otherm.isStatic();
ClassGroup vanilla = inject.getVanilla();
ClassFile targetClass = m.isStatic() ? vanilla.findClass("client") : other;
// Place into implementing class, unless the method is static
java.lang.Class<?> targetClassJava = m.isStatic() ? Inject.CLIENT_CLASS : implementingClass;
if (targetClassJava == null) {
assert !m.isStatic();
// non static exported method on non exported interface, weird.
logger.debug("Non static exported method {} on non exported interface", exportedName);
return;
}
// api method to invoke 'otherm'
java.lang.reflect.Method apiMethod = inject.findImportMethodOnApi(targetClassJava, exportedName, null);
if (apiMethod == null) {
logger.debug("Unable to find api method on {} with imported name {}, not injecting invoker", targetClassJava, exportedName);
return;
}
injectInvoker(targetClass, apiMethod, m, otherm, garbage);
++injectedInvokers;
}
Aggregations