How RuneLite Works - open-osrs/runelite GitHub Wiki
Importing and Exporting Fields and Methods
Field and method mappings are stored as annotations on the runescape-client project, which is a deobfuscated and decompiled version of the RuneScape client.
For example, the field isMembers:
@Implements("Client")
@ObfuscatedName("client")
public final class Client extends GameEngine {
...
@ObfuscatedName("v")
@Export("isMembers")
static boolean isMembers;
...
}
We can see the orginal "obfuscated name" of the field: client.v, and the deobfuscated name, which is exported as isMembers.
In order to have a method to get the value of this field injected into our client, we need to add an import on the respective interface in runescape-api, such as:
public interface RSClient extends RSGameEngine, Client {
...
@Import("isMembers")
boolean isMembers();
...
}
This pair of Import and Export is what causes the injector to inject a method into class client to get the value of isMembers.
Then, to expose it to runelite-api, so that runelite-client can see it, add the method to its interface Client too.
public interface Client {
...
boolean isMembers();
}
Exporting Static fields
Use the same approach as above, however since the class a static field resides in is dynamic depending on the deobfuscation, if you wish to Import the field in runescape-api it must go in the Client class as a non-static member. Also be aware that static methods that are in classes which have only static members and no instantiated fields cannot be tracked using the deobber and therefore cannot be imported.
Generally, runelite-api is a subset of runescape-api, with the majority of its methods implemented automatically by the injector. However, it is also mixed with the runelite-mixins which can provide some higher level wrappers around things (commonly enums instead of ints). runescape-api is meant to be 1:1 with the deobfuscated client.
The injector is run when the project named Injector is built. It takes the vanilla gamepack, the annotations on runescape-client and runescape-api, and injects methods and hooks as appropriate. It then produces the injected jar, which is an artifact of the build. This artifact is what runelite-client has a dependency on, which is the client that it loads on startup.
runelite-client does not download the gamepack from the RuneScape servers, or inject it at runtime.
How the update pipeline works
First, we take the vanilla jar and run the deobfuscator on it. This produces the deobfuscated jar, which has most of the obfuscation removed, and can be easily de-compiled, re-compiled, and runs correctly.
Next, we take the old runescape-client, with its annotations, and pass it and the deobfuscated jar to the mapper. The mapper maps the common fields and methods between the two jars and copies the annotations to the correct methods/fields/classes in the new jar, and renames them according to the exported name. This produces the mapped jar.
Then, we run FernFlower on the mapped jar to decompile it, and commit the new code to the runescape-client project in the runelite repository.