Asm mixins that "work"
This commit is contained in:
@@ -118,6 +118,19 @@ class DevToolsPanel extends PluginPanel
|
||||
varInspector.open();
|
||||
}
|
||||
});
|
||||
|
||||
container.add(plugin.getLogMenuActions());
|
||||
plugin.getLogMenuActions().addActionListener((ev) ->
|
||||
{
|
||||
if(plugin.getLogMenuActions().isActive())
|
||||
{
|
||||
client.setPrintMenuActions(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
client.setPrintMenuActions(true);
|
||||
}
|
||||
});
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ public class DevToolsPlugin extends Plugin
|
||||
private DevToolsButton detachedCamera;
|
||||
private DevToolsButton widgetInspector;
|
||||
private DevToolsButton varInspector;
|
||||
private DevToolsButton logMenuActions;
|
||||
private NavigationButton navButton;
|
||||
|
||||
@Provides
|
||||
@@ -173,6 +174,8 @@ public class DevToolsPlugin extends Plugin
|
||||
overlayManager.add(cameraOverlay);
|
||||
overlayManager.add(worldMapLocationOverlay);
|
||||
overlayManager.add(mapRegionOverlay);
|
||||
|
||||
logMenuActions = new DevToolsButton("Menu Actions");
|
||||
|
||||
final DevToolsPanel panel = injector.getInstance(DevToolsPanel.class);
|
||||
|
||||
|
||||
@@ -32,101 +32,82 @@ import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
import io.sigpipe.jbsdiff.InvalidHeaderException;
|
||||
import io.sigpipe.jbsdiff.Patch;
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.logging.Logger;
|
||||
import javassist.ClassPool;
|
||||
import javassist.NotFoundException;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.RuneLite;
|
||||
|
||||
import static net.runelite.client.rs.ClientUpdateCheckMode.AUTO;
|
||||
import static net.runelite.client.rs.ClientUpdateCheckMode.NONE;
|
||||
import static net.runelite.client.rs.ClientUpdateCheckMode.VANILLA;
|
||||
import net.runelite.client.rs.bytecode.ByteCodePatcher;
|
||||
import net.runelite.client.rs.bytecode.ByteCodeUtils;
|
||||
import net.runelite.client.rs.bytecode.Hooks;
|
||||
|
||||
import net.runelite.client.rs.mixins.MixinRunner;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.apache.commons.compress.compressors.CompressorException;
|
||||
import org.xeustechnologies.jcl.JarClassLoader;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class ClientLoader
|
||||
{
|
||||
public static File hooksFile = new File(RuneLite.RUNELITE_DIR + "/hooks-" + RuneLiteAPI.getVersion() + "-.json");
|
||||
private final ClientConfigLoader clientConfigLoader;
|
||||
private ClientUpdateCheckMode updateCheckMode;
|
||||
private static String[] preotectedStuffs;
|
||||
private static int stepCount;
|
||||
|
||||
@Inject
|
||||
private ClientLoader(
|
||||
@Named("updateCheckMode") final ClientUpdateCheckMode updateCheckMode,
|
||||
final ClientConfigLoader clientConfigLoader)
|
||||
@Named("updateCheckMode") final ClientUpdateCheckMode updateCheckMode,
|
||||
final ClientConfigLoader clientConfigLoader)
|
||||
{
|
||||
this.updateCheckMode = updateCheckMode;
|
||||
this.clientConfigLoader = clientConfigLoader;
|
||||
}
|
||||
|
||||
|
||||
public Applet load()
|
||||
{
|
||||
if (updateCheckMode == NONE)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
File injectedClientFile = ByteCodeUtils.injectedClientFile;
|
||||
File hijackedClientFile = ByteCodeUtils.hijackedClientFile;
|
||||
Manifest manifest = new Manifest();
|
||||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
|
||||
JarOutputStream target = new JarOutputStream(new FileOutputStream(injectedClientFile), manifest);
|
||||
RSConfig config = clientConfigLoader.fetch();
|
||||
|
||||
|
||||
Map<String, byte[]> zipFile = new HashMap<>();
|
||||
{
|
||||
String codebase = config.getCodeBase();
|
||||
String initialJar = config.getInitialJar();
|
||||
URL url = new URL(codebase + initialJar);
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
JarInputStream jis;
|
||||
|
||||
|
||||
jis = new JarInputStream(response.body().byteStream());
|
||||
|
||||
byte[] tmp = new byte[4096];
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024);
|
||||
for (; ; )
|
||||
@@ -136,7 +117,7 @@ public class ClientLoader
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
buffer.reset();
|
||||
for (; ; )
|
||||
{
|
||||
@@ -147,12 +128,12 @@ public class ClientLoader
|
||||
}
|
||||
buffer.write(tmp, 0, n);
|
||||
}
|
||||
|
||||
|
||||
zipFile.put(metadata.getName(), buffer.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (updateCheckMode == AUTO)
|
||||
{
|
||||
Map<String, String> hashes;
|
||||
@@ -162,41 +143,33 @@ public class ClientLoader
|
||||
{
|
||||
}.getType());
|
||||
}
|
||||
|
||||
|
||||
for (Map.Entry<String, String> file : hashes.entrySet())
|
||||
{
|
||||
byte[] bytes = zipFile.get(file.getKey());
|
||||
|
||||
|
||||
String ourHash = null;
|
||||
if (bytes != null)
|
||||
{
|
||||
ourHash = Hashing.sha512().hashBytes(bytes).toString();
|
||||
}
|
||||
|
||||
|
||||
if (!file.getValue().equals(ourHash))
|
||||
{
|
||||
if (hijackedClientFile.exists())
|
||||
{
|
||||
Logger.getAnonymousLogger().warning("[RuneLitePlus] Hash checking / Client patching skipped due to hijacked client.");
|
||||
updateCheckMode = VANILLA;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
log.info("{} had a hash mismatch; falling back to vanilla. {} != {}", file.getKey(), file.getValue(), ourHash);
|
||||
log.info("Client is outdated!");
|
||||
updateCheckMode = VANILLA;
|
||||
break;
|
||||
}
|
||||
log.info("{} had a hash mismatch; falling back to vanilla. {} != {}", file.getKey(),
|
||||
file.getValue(), ourHash);
|
||||
log.info("Client is outdated!");
|
||||
updateCheckMode = VANILLA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (updateCheckMode == AUTO)
|
||||
{
|
||||
ByteArrayOutputStream patchOs = new ByteArrayOutputStream(756 * 1024);
|
||||
int patchCount = 0;
|
||||
|
||||
|
||||
for (Map.Entry<String, byte[]> file : zipFile.entrySet())
|
||||
{
|
||||
byte[] bytes;
|
||||
@@ -206,292 +179,110 @@ public class ClientLoader
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
bytes = ByteStreams.toByteArray(is);
|
||||
}
|
||||
|
||||
|
||||
patchOs.reset();
|
||||
Patch.patch(file.getValue(), bytes, patchOs);
|
||||
file.setValue(patchOs.toByteArray());
|
||||
|
||||
|
||||
++patchCount;
|
||||
|
||||
if (!file.getKey().startsWith("META"))
|
||||
{
|
||||
add(file.getValue(), file.getKey(), target);
|
||||
}
|
||||
}
|
||||
target.close();
|
||||
|
||||
|
||||
log.info("Patched {} classes", patchCount);
|
||||
}
|
||||
if (hooksFile.exists())
|
||||
|
||||
log.info("Patching for RuneLitePlus");
|
||||
|
||||
if (updateCheckMode == AUTO)
|
||||
{
|
||||
ByteCodePatcher.classPool = new ClassPool(true);
|
||||
ByteCodePatcher.classPool.appendClassPath(RuneLite.RUNELITE_DIR + "/injectedClient-" + RuneLiteAPI.getVersion() + "-.jar");
|
||||
Gson gson = new Gson();
|
||||
Hooks hooks = gson.fromJson(new BufferedReader(new FileReader(hooksFile)), Hooks.class);
|
||||
|
||||
if (hooks.clientInstance.equals("") ||
|
||||
hooks.clientClass.equals("") ||
|
||||
hooks.projectileClass.equals("") ||
|
||||
hooks.actorClass.equals("") ||
|
||||
hooks.playerClass.equals(""))
|
||||
|
||||
HashMap<String, byte[]> patches = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, byte[]> file : zipFile.entrySet())
|
||||
{
|
||||
log.info("[RuneLitePlus] Bad hooks, re-scraping.");
|
||||
stepCount = getStepCount(ByteCodeUtils.injectedClientFile.getPath());
|
||||
ByteCodePatcher.clientInstance = initHookScrape(ByteCodeUtils.injectedClientFile.getPath());
|
||||
ByteCodePatcher.findHooks(injectedClientFile.getPath());
|
||||
}
|
||||
else
|
||||
{
|
||||
ByteCodePatcher.clientInstance = hooks.clientInstance;
|
||||
ByteCodePatcher.applyHooks(ByteCodeUtils.injectedClientFile, hooks);
|
||||
log.info("[RuneLitePlus] Loaded hooks");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
log.info("[RuneLitePlus] Hooks file not found, scraping hooks.");
|
||||
stepCount = getStepCount(ByteCodeUtils.injectedClientFile.getPath());
|
||||
ByteCodePatcher.clientInstance = initHookScrape(ByteCodeUtils.injectedClientFile.getPath());
|
||||
ByteCodePatcher.hooks.protectedStuff = preotectedStuffs;
|
||||
ByteCodePatcher.findHooks(injectedClientFile.getPath());
|
||||
}
|
||||
|
||||
Map<String, byte[]> zipFile2 = new HashMap<>();
|
||||
JarInputStream jis = new JarInputStream(new FileInputStream(hijackedClientFile));
|
||||
|
||||
byte[] tmp = new byte[4096];
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024);
|
||||
for (; ; )
|
||||
{
|
||||
JarEntry metadata = jis.getNextJarEntry();
|
||||
if (metadata == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
buffer.reset();
|
||||
for (; ; )
|
||||
{
|
||||
int n = jis.read(tmp);
|
||||
if (n <= -1)
|
||||
byte[] patchClass;
|
||||
try (InputStream is = ClientLoader.class.getResourceAsStream("/extended-mixins/" + file.getKey()))
|
||||
{
|
||||
break;
|
||||
if (is == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
patchClass = ByteStreams.toByteArray(is);
|
||||
}
|
||||
buffer.write(tmp, 0, n);
|
||||
|
||||
patches.put(file.getKey(), patchClass);
|
||||
|
||||
}
|
||||
|
||||
zipFile2.put(metadata.getName(), buffer.toByteArray());
|
||||
|
||||
new MixinRunner(zipFile, patches).run();
|
||||
|
||||
}
|
||||
|
||||
|
||||
for (Map.Entry<String, byte[]> entry : zipFile.entrySet())
|
||||
{
|
||||
if (entry.getKey().contains("class"))
|
||||
{
|
||||
Files.write(new File("H:\\rsclasses\\" + entry.getKey()).toPath(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
String initialClass = config.getInitialClass();
|
||||
|
||||
|
||||
ClassLoader rsClassLoader = new ClassLoader(ClientLoader.class.getClassLoader())
|
||||
{
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
String path = name.replace('.', '/').concat(".class");
|
||||
byte[] data = zipFile2.get(path);
|
||||
byte[] data = zipFile.get(path);
|
||||
if (data == null)
|
||||
{
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
|
||||
|
||||
return defineClass(name, data, 0, data.length);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Class<?> clientClass = rsClassLoader.loadClass(initialClass);
|
||||
|
||||
|
||||
Applet rs = (Applet) clientClass.newInstance();
|
||||
rs.setStub(new RSAppletStub(config));
|
||||
return rs;
|
||||
}
|
||||
catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||
| CompressorException | InvalidHeaderException | SecurityException e)
|
||||
catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException | CompressorException | InvalidHeaderException | SecurityException | NoSuchMethodException | InvocationTargetException e)
|
||||
{
|
||||
if (e instanceof ClassNotFoundException)
|
||||
{
|
||||
log.error("Unable to load client - class not found. This means you"
|
||||
+ " are not running RuneLite with Maven as the client patch"
|
||||
+ " is not in your classpath.");
|
||||
+ " are not running RuneLite with Maven as the client patch"
|
||||
+ " is not in your classpath.");
|
||||
}
|
||||
|
||||
|
||||
log.error("Error loading RS!", e);
|
||||
return null;
|
||||
}
|
||||
catch (NotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void add(byte[] bytes, String entryName, JarOutputStream target) throws IOException
|
||||
{
|
||||
JarEntry entry = new JarEntry(entryName);
|
||||
target.putNextEntry(entry);
|
||||
target.write(bytes);
|
||||
target.closeEntry();
|
||||
}
|
||||
|
||||
private static int getStepCount(String jarFile)
|
||||
{
|
||||
int stepCount = 0;
|
||||
JarClassLoader jcl = new JarClassLoader();
|
||||
BufferedInputStream in = null;
|
||||
try
|
||||
{
|
||||
ClassPool classPool = new ClassPool(true);
|
||||
classPool.appendClassPath(RuneLite.RUNELITE_DIR + "/injectedClient-" + RuneLiteAPI.getVersion() + "-.jar");
|
||||
JarEntry entry = new JarEntry(entryName);
|
||||
target.putNextEntry(entry);
|
||||
target.write(bytes);
|
||||
target.closeEntry();
|
||||
}
|
||||
catch (NotFoundException e)
|
||||
finally
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
jcl.add(new FileInputStream(jarFile));
|
||||
try (JarInputStream in = new JarInputStream(new BufferedInputStream(new FileInputStream(jarFile))))
|
||||
if (in != null)
|
||||
{
|
||||
JarEntry entry;
|
||||
while ((entry = in.getNextJarEntry()) != null)
|
||||
{
|
||||
if (entry.getName().endsWith(".class"))
|
||||
{
|
||||
stepCount++;
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return stepCount;
|
||||
}
|
||||
|
||||
private static String initHookScrape(String jarFile)
|
||||
{
|
||||
int currentStep = 0;
|
||||
RuneLite.splashScreen.setMessage("Analyzing injected client");
|
||||
List<String> protectedStuff = new ArrayList<>();
|
||||
String clientInstance = "";
|
||||
JarClassLoader jcl = new JarClassLoader();
|
||||
try
|
||||
{
|
||||
ClassPool classPool = new ClassPool(true);
|
||||
classPool.appendClassPath(RuneLite.RUNELITE_DIR + "/injectedClient-" + RuneLiteAPI.getVersion() + "-.jar");
|
||||
}
|
||||
catch (NotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
jcl.add(new FileInputStream(jarFile));
|
||||
try (JarInputStream in = new JarInputStream(new BufferedInputStream(new FileInputStream(jarFile))))
|
||||
{
|
||||
JarEntry entry;
|
||||
while ((entry = in.getNextJarEntry()) != null)
|
||||
{
|
||||
if (entry.getName().endsWith(".class"))
|
||||
{
|
||||
File temp = new File(jarFile);
|
||||
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
||||
try
|
||||
{
|
||||
URLClassLoader child = new URLClassLoader(
|
||||
new URL[]{temp.toURI().toURL()},
|
||||
cl
|
||||
);
|
||||
try
|
||||
{
|
||||
Class classToLoad = Class.forName(entry.getName().replace(".class", ""), false, child);
|
||||
RuneLite.splashScreen.setSubMessage(entry.getName());
|
||||
currentStep++;
|
||||
RuneLite.splashScreen.setProgress(currentStep, stepCount);
|
||||
JarClassLoader jcl2 = new JarClassLoader();
|
||||
try
|
||||
{
|
||||
jcl2.add(new FileInputStream(ByteCodeUtils.injectedClientFile));
|
||||
Field[] fields = classToLoad.getDeclaredFields();
|
||||
Method[] methods = classToLoad.getDeclaredMethods();
|
||||
for (Field f : fields)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (f.getName().contains("$"))
|
||||
{
|
||||
log.info(classToLoad.getName() + "." + f.getName());
|
||||
protectedStuff.add(classToLoad.getName() + "." + f.getName());
|
||||
}
|
||||
if (f.getType().getName().equals("client"))
|
||||
{
|
||||
ByteCodePatcher.hooks.clientInstance = classToLoad.getName() + "." + f.getName();
|
||||
clientInstance = classToLoad.getName() + "." + f.getName();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
for (Method m : methods)
|
||||
{
|
||||
RuneLite.splashScreen.setSubMessage("Checked " + m.getName());
|
||||
if (m.getName().contains("$"))
|
||||
{
|
||||
protectedStuff.add(classToLoad.getName() + "." + m.getName());
|
||||
}
|
||||
}
|
||||
RuneLite.splashScreen.setProgress(currentStep, stepCount);
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
RuneLite.splashScreen.setProgress(2, 5);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
log.info("Class not found: " + entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (String ignored : protectedStuff)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
preotectedStuffs = new String[i];
|
||||
i = 0;
|
||||
|
||||
for (String o : protectedStuff)
|
||||
{
|
||||
preotectedStuffs[i] = o;
|
||||
i++;
|
||||
}
|
||||
|
||||
return clientInstance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,298 +0,0 @@
|
||||
package net.runelite.client.rs.bytecode;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.NotFoundException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.rs.ClientLoader;
|
||||
import net.runelite.client.rs.bytecode.transformers.ActorTransform;
|
||||
import net.runelite.client.rs.bytecode.transformers.ClientTransform;
|
||||
import net.runelite.client.rs.bytecode.transformers.ErrorTransform;
|
||||
import net.runelite.client.rs.bytecode.transformers.PlayerTransform;
|
||||
import net.runelite.client.rs.bytecode.transformers.ProjectileTransform;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import org.xeustechnologies.jcl.JarClassLoader;
|
||||
|
||||
@Slf4j
|
||||
public class ByteCodePatcher
|
||||
{
|
||||
|
||||
public static List<CtClass> modifiedClasses = new ArrayList<>();
|
||||
public static Hooks hooks = new Hooks();
|
||||
public static String clientInstance;
|
||||
private static JarClassLoader jcl = new JarClassLoader();
|
||||
public static ClassPool classPool = null;
|
||||
private static ClassLoader cl = ClassLoader.getSystemClassLoader();
|
||||
private static int classCount = 0;
|
||||
|
||||
public static void applyHooks(File jf, Hooks hooks)
|
||||
{
|
||||
RuneLite.splashScreen.setProgress(0, 5);
|
||||
RuneLite.splashScreen.setMessage("Applying cached bytecode patches...");
|
||||
try
|
||||
{
|
||||
URLClassLoader child = new URLClassLoader(
|
||||
new URL[]{jf.toURI().toURL()},
|
||||
cl
|
||||
);
|
||||
try
|
||||
{
|
||||
RuneLite.splashScreen.setSubMessage("Transforming Client");
|
||||
Class clientClass = Class.forName(hooks.clientClass, false, child);
|
||||
transformClient(clientClass);
|
||||
RuneLite.splashScreen.setProgress(1, 5);
|
||||
|
||||
RuneLite.splashScreen.setSubMessage("Transforming Actor");
|
||||
Class actorClass = Class.forName(hooks.actorClass, false, child);
|
||||
transformActor(actorClass);
|
||||
RuneLite.splashScreen.setProgress(2, 5);
|
||||
|
||||
RuneLite.splashScreen.setSubMessage("Transforming Projectile");
|
||||
Class projectileClass = Class.forName(hooks.projectileClass, false, child);
|
||||
transformProjectile(projectileClass);
|
||||
RuneLite.splashScreen.setProgress(3, 5);
|
||||
|
||||
RuneLite.splashScreen.setSubMessage("Transforming Player");
|
||||
Class playerClass = Class.forName(hooks.playerClass, false, child);
|
||||
transformPlayer(playerClass);
|
||||
RuneLite.splashScreen.setProgress(4, 5);
|
||||
|
||||
// Odds and ends
|
||||
RuneLite.splashScreen.setSubMessage("Transforming Error method");
|
||||
transformStackTrace();
|
||||
RuneLite.splashScreen.setProgress(5, 5);
|
||||
|
||||
RuneLite.splashScreen.setSubMessage("");
|
||||
ByteCodeUtils.updateHijackedJar();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void findHooks(String jf)
|
||||
{
|
||||
RuneLite.splashScreen.setMessage("Hijacking Classes");
|
||||
try
|
||||
{
|
||||
classPool = new ClassPool(true);
|
||||
classPool.appendClassPath(RuneLite.RUNELITE_DIR + "/injectedClient-" + RuneLiteAPI.getVersion() + "-.jar");
|
||||
}
|
||||
catch (NotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
jcl.add(new FileInputStream(jf));
|
||||
try (JarInputStream in = new JarInputStream(new BufferedInputStream(new FileInputStream(jf))))
|
||||
{
|
||||
JarEntry entry;
|
||||
while ((entry = in.getNextJarEntry()) != null)
|
||||
{
|
||||
if (entry.getName().endsWith(".class"))
|
||||
{
|
||||
classCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
int i = 0;
|
||||
jcl.add(new FileInputStream(jf));
|
||||
try (JarInputStream in = new JarInputStream(new BufferedInputStream(new FileInputStream(jf))))
|
||||
{
|
||||
JarEntry entry;
|
||||
while ((entry = in.getNextJarEntry()) != null)
|
||||
{
|
||||
if (entry.getName().endsWith(".class"))
|
||||
{
|
||||
RuneLite.splashScreen.setProgress(i, classCount);
|
||||
RuneLite.splashScreen.setSubMessage("Checking " + entry.getName());
|
||||
checkClasses(new File(jf), entry);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
try
|
||||
{
|
||||
Writer writer = new FileWriter(ClientLoader.hooksFile);
|
||||
gson.toJson(hooks, writer);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
ByteCodeUtils.updateHijackedJar();
|
||||
}
|
||||
|
||||
private static void checkClasses(File jf, JarEntry entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
URLClassLoader child = new URLClassLoader(
|
||||
new URL[]{jf.toURI().toURL()},
|
||||
cl
|
||||
);
|
||||
try
|
||||
{
|
||||
Class classToLoad = Class.forName(entry.getName().replace(".class", ""), false, child);
|
||||
checkClient(classToLoad);
|
||||
checkActor(classToLoad);
|
||||
checkProjectile(classToLoad);
|
||||
checkPlayer(classToLoad);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
// System.out.println("Class not found: "+entry.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkClient(Class current)
|
||||
{
|
||||
try
|
||||
{
|
||||
Method method = current.getDeclaredMethod("getProjectiles");
|
||||
if (method != null)
|
||||
{
|
||||
hooks.clientClass = current.getName();
|
||||
log.info("[RuneLitePlus] Transforming Client at class: " + current.getName());
|
||||
ClientTransform ct = new ClientTransform();
|
||||
ct.modify(current);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException | NoClassDefFoundError e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void transformClient(Class client)
|
||||
{
|
||||
log.info("[RuneLitePlus] Transforming Client at class: " + client.getName());
|
||||
ClientTransform ct = new ClientTransform();
|
||||
ct.modify(client);
|
||||
}
|
||||
|
||||
private static void checkActor(Class current)
|
||||
{
|
||||
try
|
||||
{
|
||||
Method method = current.getDeclaredMethod("setCombatInfo", new Class[]{int.class, int.class, int.class, int.class, int.class, int.class});
|
||||
if (method != null)
|
||||
{
|
||||
hooks.actorClass = current.getName();
|
||||
log.info("[RuneLitePlus] Transforming Actor at class: " + current.getName());
|
||||
ActorTransform at = new ActorTransform();
|
||||
at.modify(current);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException | NoClassDefFoundError e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void transformActor(Class actor)
|
||||
{
|
||||
log.info("[RuneLitePlus] Transforming Actor at class: " + actor.getName());
|
||||
ActorTransform at = new ActorTransform();
|
||||
at.modify(actor);
|
||||
}
|
||||
|
||||
private static void checkProjectile(Class current)
|
||||
{
|
||||
try
|
||||
{
|
||||
Method method = current.getDeclaredMethod("projectileMoved", new Class[]{int.class, int.class, int.class, int.class});
|
||||
if (method != null)
|
||||
{
|
||||
hooks.projectileClass = current.getName();
|
||||
log.info("[RuneLitePlus] Transforming Projectile at class: " + current.getName());
|
||||
ProjectileTransform pt = new ProjectileTransform();
|
||||
pt.modify(current);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException | NoClassDefFoundError e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void transformProjectile(Class projectile)
|
||||
{
|
||||
log.info("[RuneLitePlus] Transforming Projectile at class: " + projectile.getName());
|
||||
ProjectileTransform pt = new ProjectileTransform();
|
||||
pt.modify(projectile);
|
||||
}
|
||||
|
||||
private static void checkPlayer(Class current)
|
||||
{
|
||||
try
|
||||
{
|
||||
Method method = current.getDeclaredMethod("getSkullIcon");
|
||||
if (method != null)
|
||||
{
|
||||
hooks.playerClass = current.getName();
|
||||
log.info("[RuneLitePlus] Transforming Player at class: " + current.getName());
|
||||
PlayerTransform pt = new PlayerTransform();
|
||||
pt.modify(current);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException | NoClassDefFoundError e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void transformPlayer(Class player)
|
||||
{
|
||||
log.info("[RuneLitePlus] Transforming Player at class: " + player.getName());
|
||||
PlayerTransform pt = new PlayerTransform();
|
||||
pt.modify(player);
|
||||
}
|
||||
|
||||
private static void transformStackTrace()
|
||||
{
|
||||
log.info("[RuneLitePlus] Transforming Stack Trace");
|
||||
ErrorTransform et = new ErrorTransform();
|
||||
et.modify(null);
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
package net.runelite.client.rs.bytecode;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import javassist.CtClass;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
|
||||
public class ByteCodeUtils
|
||||
{
|
||||
//TODO: Write method to delete old revision injected clients.
|
||||
public static File injectedClientFile = new File(RuneLite.RUNELITE_DIR + "/injectedClient-" + RuneLiteAPI.getVersion() + "-.jar");
|
||||
public static File hijackedClientFile = new File(RuneLite.RUNELITE_DIR + "/hijackedClient-" + RuneLiteAPI.getVersion() + "-.jar");
|
||||
|
||||
public static JarOutputStream target;
|
||||
|
||||
static void updateHijackedJar()
|
||||
{
|
||||
Manifest manifest = new Manifest();
|
||||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
|
||||
try
|
||||
{
|
||||
target = new JarOutputStream(new FileOutputStream(hijackedClientFile), manifest);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
try
|
||||
{
|
||||
JarFile original = new JarFile(injectedClientFile);
|
||||
Enumeration<JarEntry> entries = original.entries();
|
||||
while (entries.hasMoreElements())
|
||||
{
|
||||
JarEntry entry = entries.nextElement();
|
||||
boolean skip = false;
|
||||
for (CtClass ct : ByteCodePatcher.modifiedClasses)
|
||||
{
|
||||
if ((ct.getName() + ".class").equals(entry.getName()))
|
||||
{
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
if (!skip)
|
||||
{
|
||||
add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
for (CtClass ct : ByteCodePatcher.modifiedClasses)
|
||||
{
|
||||
add(ct);
|
||||
}
|
||||
|
||||
target.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void add(CtClass ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
JarEntry newEntry = new JarEntry(ct.getName() + ".class");
|
||||
target.putNextEntry(newEntry);
|
||||
target.write(ct.toBytecode());
|
||||
target.closeEntry();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void add(JarEntry entry) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!entry.getName().startsWith("META") && !entry.getName().equals(""))
|
||||
{
|
||||
target.putNextEntry(entry);
|
||||
target.write(getBytesFromZipFile(entry.getName()));
|
||||
target.closeEntry();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBytesFromZipFile(String entryName)
|
||||
{
|
||||
ZipFile zipFile;
|
||||
try
|
||||
{
|
||||
zipFile = new ZipFile(injectedClientFile);
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
|
||||
while (entries.hasMoreElements())
|
||||
{
|
||||
ZipEntry entry = entries.nextElement();
|
||||
if (entry.getName().equals(entryName))
|
||||
{
|
||||
InputStream stream = zipFile.getInputStream(entry);
|
||||
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
int nRead;
|
||||
byte[] data = new byte[1024];
|
||||
while ((nRead = stream.read(data, 0, data.length)) != -1)
|
||||
{
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
buffer.flush();
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package net.runelite.client.rs.bytecode;
|
||||
|
||||
public class Hooks {
|
||||
|
||||
public String clientInstance = "";
|
||||
public String actorClass = "";
|
||||
public String projectileClass = "";
|
||||
public String playerClass = "";
|
||||
public String[] protectedStuff;
|
||||
public String clientClass = "";
|
||||
|
||||
public Hooks() {
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package net.runelite.client.rs.bytecode.transformers;
|
||||
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
import javassist.CtNewMethod;
|
||||
import javassist.NotFoundException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.rs.bytecode.ByteCodePatcher;
|
||||
|
||||
@Slf4j
|
||||
public class ActorTransform implements Transform
|
||||
{
|
||||
private CtClass ct;
|
||||
|
||||
@Override
|
||||
public void modify(Class actor)
|
||||
{
|
||||
try
|
||||
{
|
||||
ct = ByteCodePatcher.classPool.get(actor.getName());
|
||||
|
||||
transformGetAnimation();
|
||||
transformAnimationChanged();
|
||||
transformGraphicChanged();
|
||||
|
||||
ByteCodePatcher.modifiedClasses.add(ct);
|
||||
}
|
||||
catch (CannotCompileException | NotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void transformGetAnimation() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod protectedAnimation = ct.getDeclaredMethod("1protect$getRsAnimation");
|
||||
ct.removeMethod(protectedAnimation);
|
||||
|
||||
protectedAnimation.setName("getRsAnimation");
|
||||
ct.addMethod(protectedAnimation);
|
||||
|
||||
CtMethod getAnimation = ct.getDeclaredMethod("getAnimation");
|
||||
ct.removeMethod(getAnimation);
|
||||
|
||||
getAnimation = CtNewMethod.make(
|
||||
"public int getAnimation()" +
|
||||
"{" +
|
||||
" return this.getRsAnimation();" +
|
||||
"}", ct);
|
||||
ct.addMethod(getAnimation);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private void transformAnimationChanged() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod getAnimationChanged = ct.getDeclaredMethod("animationChanged", new CtClass[]{CtClass.intType});
|
||||
ct.removeMethod(getAnimationChanged);
|
||||
|
||||
getAnimationChanged = CtNewMethod.make(
|
||||
"public void animationChanged(int n)" +
|
||||
"{" +
|
||||
" net.runelite.api.events.AnimationChanged animationChanged = new net.runelite.api.events.AnimationChanged();" +
|
||||
" animationChanged.setActor((net.runelite.api.Actor) this);" +
|
||||
ByteCodePatcher.clientInstance + ".getCallbacks().post((java.lang.Object)animationChanged);" +
|
||||
"}", ct);
|
||||
ct.addMethod(getAnimationChanged);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformGraphicChanged() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod graphicChanged = ct.getDeclaredMethod("graphicChanged", new CtClass[]{CtClass.intType});
|
||||
ct.removeMethod(graphicChanged);
|
||||
|
||||
graphicChanged = CtNewMethod.make(
|
||||
"public void graphicChanged(int paramInt)" +
|
||||
"{" +
|
||||
" net.runelite.api.events.GraphicChanged localGraphicChanged = new net.runelite.api.events.GraphicChanged();" +
|
||||
" localGraphicChanged.setActor(this);" +
|
||||
ByteCodePatcher.clientInstance + ".getCallbacks().post(localGraphicChanged);" +
|
||||
"}", ct);
|
||||
ct.addMethod(graphicChanged);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,642 +0,0 @@
|
||||
package net.runelite.client.rs.bytecode.transformers;
|
||||
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
import javassist.CtNewMethod;
|
||||
import javassist.NotFoundException;
|
||||
import javassist.bytecode.AnnotationsAttribute;
|
||||
import javassist.bytecode.ClassFile;
|
||||
import javassist.bytecode.ConstPool;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.rs.bytecode.ByteCodePatcher;
|
||||
|
||||
@Slf4j
|
||||
public class ClientTransform implements Transform
|
||||
{
|
||||
|
||||
private CtClass ct;
|
||||
|
||||
@Override
|
||||
public void modify(Class clazz)
|
||||
{
|
||||
try
|
||||
{
|
||||
ct = ByteCodePatcher.classPool.get(clazz.getName());
|
||||
|
||||
transformProtectedGetMenuOptions();
|
||||
transformProtectedGetMenuTargets();
|
||||
transformProtectedGetMenuIdentifiers();
|
||||
transformProtectedGetMenuTypes();
|
||||
transformProtectedGetMenuActionParams0();
|
||||
transformProtectedGetMenuActionParams1();
|
||||
transformGetMenuEntries();
|
||||
transformSetMenuEntries();
|
||||
transformOnMenuOptionsChanged();
|
||||
transformGetProjectiles();
|
||||
transformGetCollisionMaps();
|
||||
transformDraw2010Menu();
|
||||
transformRenderSelf();
|
||||
transformboundingBoxCheck();
|
||||
transformcheckClickBox();
|
||||
|
||||
ByteCodePatcher.modifiedClasses.add(ct);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void transformProtectedGetMenuOptions() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod protectedGetMenuOptions;
|
||||
|
||||
protectedGetMenuOptions = ct.getDeclaredMethod("1protect$getMenuOptions");
|
||||
ct.removeMethod(protectedGetMenuOptions);
|
||||
|
||||
protectedGetMenuOptions.setName("getMenuOptions");
|
||||
ct.addMethod(protectedGetMenuOptions);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformGetProjectiles() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod getProjectiles;
|
||||
|
||||
CtMethod getProjectilesDeque = ct.getDeclaredMethod("1protect$getProjectilesDeque");
|
||||
ct.removeMethod(getProjectilesDeque);
|
||||
|
||||
getProjectilesDeque.setName("getProjectilesDeque");
|
||||
ct.addMethod(getProjectilesDeque);
|
||||
|
||||
getProjectiles = ct.getDeclaredMethod("getProjectiles");
|
||||
ct.removeMethod(getProjectiles);
|
||||
|
||||
getProjectiles = CtNewMethod.make(
|
||||
"public java.util.List getProjectiles() { " +
|
||||
"java.util.ArrayList localArrayList = new java.util.ArrayList();" +
|
||||
"net.runelite.rs.api.RSDeque localRSDeque = getProjectilesDeque();" +
|
||||
"net.runelite.rs.api.RSNode localRSNode = localRSDeque.getHead();" +
|
||||
"for (net.runelite.api.Node localNode = localRSNode.getNext(); localNode != localRSNode; localNode = localNode.getNext()) {" +
|
||||
"net.runelite.api.Projectile localProjectile = (net.runelite.api.Projectile)localNode;" +
|
||||
"localArrayList.add(localProjectile); }" +
|
||||
"return localArrayList; }", ct);
|
||||
ct.addMethod(getProjectiles);
|
||||
|
||||
ClassFile classFile = ct.getClassFile();
|
||||
ConstPool constPool = classFile.getConstPool();
|
||||
AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
|
||||
javassist.bytecode.annotation.Annotation annotation = new javassist.bytecode.annotation.Annotation("Override", constPool);
|
||||
attr.setAnnotation(annotation);
|
||||
getProjectiles.getMethodInfo().addAttribute(attr);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformProtectedGetMenuTargets() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod protectedGetMenuTargets;
|
||||
|
||||
protectedGetMenuTargets = ct.getDeclaredMethod("1protect$getMenuTargets");
|
||||
ct.removeMethod(protectedGetMenuTargets);
|
||||
|
||||
protectedGetMenuTargets.setName("getMenuTargets");
|
||||
ct.addMethod(protectedGetMenuTargets);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformGetCollisionMaps() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod getCollisionMaps;
|
||||
|
||||
CtMethod protectedMaps = ct.getDeclaredMethod("1protect$getRsCollisionMaps");
|
||||
ct.removeMethod(protectedMaps);
|
||||
|
||||
protectedMaps.setName("getRsCollisionMaps");
|
||||
ct.addMethod(protectedMaps);
|
||||
|
||||
getCollisionMaps = ct.getDeclaredMethod("getCollisionMaps");
|
||||
ct.removeMethod(getCollisionMaps);
|
||||
|
||||
getCollisionMaps = CtMethod.make("public net.runelite.rs.api.RSCollisionData[] getCollisionMaps() { return getRsCollisionMaps(); }", ct);
|
||||
ct.addMethod(getCollisionMaps);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformProtectedGetMenuIdentifiers() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod protectedGetMenuIdentifiers;
|
||||
|
||||
protectedGetMenuIdentifiers = ct.getDeclaredMethod("1protect$getMenuIdentifiers");
|
||||
ct.removeMethod(protectedGetMenuIdentifiers);
|
||||
|
||||
protectedGetMenuIdentifiers.setName("getMenuIdentifiers");
|
||||
ct.addMethod(protectedGetMenuIdentifiers);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformProtectedGetMenuTypes() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod protectedGetMenuTypes;
|
||||
protectedGetMenuTypes = ct.getDeclaredMethod("1protect$getMenuTypes");
|
||||
|
||||
// Don't remove as this is referenced elsewhere in client
|
||||
// ct.removeMethod(protectedGetMenuTypes);
|
||||
|
||||
CtMethod newProtectedGetMenuTypes = CtNewMethod.copy(protectedGetMenuTypes, ct, null);
|
||||
newProtectedGetMenuTypes.setName("getMenuTypes");
|
||||
|
||||
ct.addMethod(newProtectedGetMenuTypes);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformProtectedGetMenuActionParams0() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod protectedGetMenuActionParams0;
|
||||
|
||||
protectedGetMenuActionParams0 = ct.getDeclaredMethod("1protect$getMenuActionParams0");
|
||||
ct.removeMethod(protectedGetMenuActionParams0);
|
||||
|
||||
protectedGetMenuActionParams0.setName("getMenuActionParams0");
|
||||
ct.addMethod(protectedGetMenuActionParams0);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformProtectedGetMenuActionParams1() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod protectedGetMenuActionParams1;
|
||||
|
||||
protectedGetMenuActionParams1 = ct.getDeclaredMethod("1protect$getMenuActionParams1");
|
||||
ct.removeMethod(protectedGetMenuActionParams1);
|
||||
protectedGetMenuActionParams1.setName("getMenuActionParams1");
|
||||
ct.addMethod(protectedGetMenuActionParams1);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformGetMenuEntries() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod getMenuEntries;
|
||||
|
||||
getMenuEntries = ct.getDeclaredMethod("getMenuEntries");
|
||||
ct.removeMethod(getMenuEntries);
|
||||
|
||||
getMenuEntries = CtMethod.make(
|
||||
"public net.runelite.api.MenuEntry[] getMenuEntries()" +
|
||||
"{" +
|
||||
" int n2 = this.getMenuOptionCount();" +
|
||||
" String[] arrstring = this.getMenuOptions();" +
|
||||
" String[] arrstring2 = this.getMenuTargets();" +
|
||||
" int[] arrn = this.getMenuIdentifiers();" +
|
||||
" int[] arrn2 = this.getMenuTypes();" +
|
||||
" int[] arrn3 = this.getMenuActionParams0();" +
|
||||
" int[] arrn4 = this.getMenuActionParams1();" +
|
||||
" boolean[] arrbl = this.getMenuForceLeftClick();" +
|
||||
" net.runelite.api.MenuEntry[] arrmenuEntry = new net.runelite.api.MenuEntry[n2];" +
|
||||
" int n3 = 0;" +
|
||||
" while (n3 < n2) " +
|
||||
" {" +
|
||||
" net.runelite.api.MenuEntry menuEntry = arrmenuEntry[n3] = new net.runelite.api.MenuEntry();" +
|
||||
" menuEntry.setOption(arrstring[n3]);" +
|
||||
" menuEntry.setTarget(arrstring2[n3]);" +
|
||||
" menuEntry.setIdentifier(arrn[n3]);" +
|
||||
" menuEntry.setType(arrn2[n3]);" +
|
||||
" menuEntry.setParam0(arrn3[n3]);" +
|
||||
" menuEntry.setParam1(arrn4[n3]);" +
|
||||
" menuEntry.setForceLeftClick(arrbl[n3]);" +
|
||||
" ++n3;" +
|
||||
" }" +
|
||||
" return arrmenuEntry;" +
|
||||
"}", ct);
|
||||
ct.addMethod(getMenuEntries);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformSetMenuEntries() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod setMenuEntries;
|
||||
|
||||
setMenuEntries = ct.getDeclaredMethod("setMenuEntries");
|
||||
ct.removeMethod(setMenuEntries);
|
||||
setMenuEntries = CtNewMethod.make(
|
||||
"public void setMenuEntries(net.runelite.api.MenuEntry[] arrmenuEntry)" +
|
||||
"{" +
|
||||
" int n2 = 0;" +
|
||||
" String[] arrstring = this.getMenuOptions();" +
|
||||
" String[] arrstring2 = this.getMenuTargets();" +
|
||||
" int[] arrn = this.getMenuIdentifiers();" +
|
||||
" int[] arrn2 = this.getMenuTypes();" +
|
||||
" int[] arrn3 = this.getMenuActionParams0();" +
|
||||
" int[] arrn4 = this.getMenuActionParams1();" +
|
||||
" boolean[] arrbl = getMenuForceLeftClick();" +
|
||||
" net.runelite.api.MenuEntry[] arrmenuEntry2 = arrmenuEntry;" +
|
||||
" int n3 = arrmenuEntry2.length;" +
|
||||
" int n4 = 0;" +
|
||||
" do" +
|
||||
" {" +
|
||||
" String string;" +
|
||||
" if (n4 >= n3)" +
|
||||
" {" +
|
||||
" this.setMenuOptionCount(n2);" +
|
||||
" oldMenuEntryCount = n2;" +
|
||||
" return;" +
|
||||
" }" +
|
||||
" net.runelite.api.MenuEntry menuEntry = arrmenuEntry2[n4];" +
|
||||
" int n5 = menuEntry.getType();" +
|
||||
" arrstring[n2] = menuEntry.getOption();" +
|
||||
" arrstring2[n2] = menuEntry.getTarget();" +
|
||||
" arrn[n2] = menuEntry.getIdentifier();" +
|
||||
" arrn2[n2] = n5;" +
|
||||
" arrn3[n2] = menuEntry.getParam0();" +
|
||||
" arrn4[n2] = menuEntry.getParam1();" +
|
||||
" arrbl[n2] = menuEntry.isForceLeftClick();" +
|
||||
" ++n2;" +
|
||||
" ++n4;" +
|
||||
" } while (true);" +
|
||||
"}"
|
||||
, ct);
|
||||
ct.addMethod(setMenuEntries);
|
||||
}
|
||||
|
||||
private void transformOnMenuOptionsChanged() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod onMenuOptionsChanged;
|
||||
|
||||
onMenuOptionsChanged = ct.getDeclaredMethod("onMenuOptionsChanged", new CtClass[]{CtClass.intType});
|
||||
ct.removeMethod(onMenuOptionsChanged);
|
||||
|
||||
onMenuOptionsChanged = CtMethod.make(
|
||||
"public static void onMenuOptionsChanged(int n2)" +
|
||||
"{" +
|
||||
" int n3;" +
|
||||
" int n4 = oldMenuEntryCount;" +
|
||||
" oldMenuEntryCount = n3 = " + ByteCodePatcher.clientInstance + ".getMenuOptionCount();" +
|
||||
" if (n3 != n4 + 1) return;" +
|
||||
" net.runelite.api.events.MenuEntryAdded menuEntryAdded = new net.runelite.api.events.MenuEntryAdded(" +
|
||||
ByteCodePatcher.clientInstance + ".getMenuOptions()[n3 - 1]," +
|
||||
ByteCodePatcher.clientInstance + ".getMenuTargets()[n3 - 1]," +
|
||||
ByteCodePatcher.clientInstance + ".getMenuTypes()[n3 - 1]," +
|
||||
ByteCodePatcher.clientInstance + ".getMenuIdentifiers()[n3 - 1]," +
|
||||
ByteCodePatcher.clientInstance + ".getMenuActionParams0()[n3 - 1]," +
|
||||
ByteCodePatcher.clientInstance + ".getMenuActionParams1()[n3 - 1]);" +
|
||||
ByteCodePatcher.clientInstance + ".getCallbacks().post((Object)menuEntryAdded);" +
|
||||
"}"
|
||||
, ct);
|
||||
|
||||
ct.addMethod(onMenuOptionsChanged);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformRenderSelf() throws CannotCompileException
|
||||
{
|
||||
CtMethod renderSelf;
|
||||
|
||||
renderSelf = CtMethod.make("public void toggleRenderSelf() { jb = !jb; }", ct);
|
||||
|
||||
ClassFile classFile = ct.getClassFile();
|
||||
ConstPool constPool = classFile.getConstPool();
|
||||
AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
|
||||
javassist.bytecode.annotation.Annotation annotation = new javassist.bytecode.annotation.Annotation("Export", constPool);
|
||||
attr.setAnnotation(annotation);
|
||||
renderSelf.getMethodInfo().addAttribute(attr);
|
||||
|
||||
ct.addMethod(renderSelf);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformDraw2010Menu() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod draw2010Menu;
|
||||
|
||||
draw2010Menu = ct.getDeclaredMethod("draw2010Menu");
|
||||
ct.removeMethod(draw2010Menu);
|
||||
|
||||
draw2010Menu = CtNewMethod.make(
|
||||
"public void draw2010Menu()" +
|
||||
"{" +
|
||||
" int n2 = this.getMenuX();" +
|
||||
" int n3 = this.getMenuY();" +
|
||||
" int n4 = this.getMenuWidth();" +
|
||||
" int n5 = this.getMenuHeight();" +
|
||||
" this.RasterizerDrawHorizontalLine(n2 + 2, n3, n4 - 4, 7170651);" +
|
||||
" this.RasterizerDrawHorizontalLine(n2 + 2, n3 + n5 - 1, n4 - 4, 7170651);" +
|
||||
" this.RasterizerDrawVerticalLine(n2, n3 + 2, n5 - 4, 7170651);" +
|
||||
" this.RasterizerDrawVerticalLine(n2 + n4 - 1, n3 + 2, n5 - 4, 7170651);" +
|
||||
" this.RasterizerDrawRectangle(n2 + 1, n3 + 5, n4 - 2, n5 - 6, 2827810);" +
|
||||
" this.RasterizerDrawHorizontalLine(n2 + 1, n3 + 17, n4 - 2, 2827810);" +
|
||||
" this.RasterizerDrawCircle(n2 + 2, n3 + n5 - 3, 0, 2827810);" +
|
||||
" this.RasterizerDrawCircle(n2 + n4 - 3, n3 + n5 - 3, 0, 2827810);" +
|
||||
" this.RasterizerDrawGradient(n2 + 2, n3 + 1, n4 - 4, 16, 3288610, 592388);" +
|
||||
" this.RasterizerFillRectangle(n2 + 1, n3 + 1, 2, 4, 2827810);" +
|
||||
" this.RasterizerFillRectangle(n2 + n4 - 3, n3 + 1, 2, 4, 2827810);" +
|
||||
" this.RasterizerDrawHorizontalLine(n2 + 2, n3 + 18, n4 - 4, 5392957);" +
|
||||
" this.RasterizerDrawHorizontalLine(n2 + 3, n3 + n5 - 3, n4 - 6, 5392957);" +
|
||||
" this.RasterizerDrawVerticalLine(n2 + 2, n3 + 18, n5 - 21, 5392957);" +
|
||||
" this.RasterizerDrawVerticalLine(n2 + n4 - 3, n3 + 18, n5 - 21, 5392957);" +
|
||||
" this.RasterizerFillRectangle(n2 + 3, n3 + 19, n4 - 6, n5 - 22, 2828060);" +
|
||||
" this.RasterizerDrawCircle(n2 + 1, n3 + 1, 0, 7170651);" +
|
||||
" this.RasterizerDrawCircle(n2 + n4 - 2, n3 + 1, 0, 7170651);" +
|
||||
" this.RasterizerDrawCircle(n2 + 1, n3 + n5 - 2, 0, 7170651);" +
|
||||
" this.RasterizerDrawCircle(n2 + n4 - 2, n3 + n5 - 2, 0, 7170651);" +
|
||||
" net.runelite.rs.api.RSFont rSFont = this.getFontBold12();" +
|
||||
" rSFont.drawTextLeftAligned(\"Choose Option\", n2 + 3, n3 + 14, 13023381, -1);" +
|
||||
" int n6 = this.getMouseX();" +
|
||||
" int n7 = this.getMouseY();" +
|
||||
" int n8 = this.getMenuOptionCount();" +
|
||||
" String[] arrstring = this.getMenuTargets();" +
|
||||
" String[] arrstring2 = this.getMenuOptions();" +
|
||||
" for (int i = 0; i < n8; ++i)" +
|
||||
" {" +
|
||||
" int n9 = n3 + (n8 - 1 - i) * 15 + 31;" +
|
||||
" String string = arrstring2[i];" +
|
||||
" if (!arrstring[i].isEmpty())" +
|
||||
" {" +
|
||||
" string = string + \" \" + arrstring[i];" +
|
||||
" }" +
|
||||
" rSFont.drawTextLeftAligned(string, n2 + 3, n9, 13023381, -1);" +
|
||||
" if (n6 <= n2 || n6 >= n4 + n2 || n7 <= n9 - 13 || n7 >= n9 + 3)" +
|
||||
" {" +
|
||||
" continue;" +
|
||||
" }" +
|
||||
" this.RasterizerFillRectangleAlpha(n2 + 3, n9 - 12, n4 - 6, 15, 16777215, 80);" +
|
||||
" }" +
|
||||
"}"
|
||||
, ct);
|
||||
ct.addMethod(draw2010Menu);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
//TODO: fix not being able to click far away objects towards top of screen only.
|
||||
private void transformboundingBoxCheck() throws CannotCompileException
|
||||
{
|
||||
CtMethod boundingboxCheck2;
|
||||
|
||||
boundingboxCheck2 = CtMethod.make(
|
||||
"public boolean boundingboxCheck2(net.runelite.api.Model model, int n2, int n3, int n4)" +
|
||||
"{" +
|
||||
" int n5 = " + ByteCodePatcher.clientInstance + ".getCameraPitch();" +
|
||||
" int n6 = " + ByteCodePatcher.clientInstance + ".getCameraYaw();" +
|
||||
" int n7 = net.runelite.api.Perspective.SINE[n5];" +
|
||||
" int n8 = net.runelite.api.Perspective.COSINE[n5];" +
|
||||
" int n9 = net.runelite.api.Perspective.SINE[n6];" +
|
||||
" int n10 = net.runelite.api.Perspective.COSINE[n6];" +
|
||||
" int n11 = " + ByteCodePatcher.clientInstance + ".getCenterX();" +
|
||||
" int n12 = " + ByteCodePatcher.clientInstance + ".getCenterY();" +
|
||||
" int n13 = " + ByteCodePatcher.clientInstance + ".getViewportMouseX();" +
|
||||
" int n14 = " + ByteCodePatcher.clientInstance + ".getViewportMouseY();" +
|
||||
" int n15 = " + ByteCodePatcher.clientInstance + ".get3dZoom();" +
|
||||
" int n16 = (n13 - n11) * 50 / n15;" +
|
||||
" int n17 = (n14 - n12) * 50 / n15;" +
|
||||
" int n18 = (n13 - n11) * 10000 / n15;" +
|
||||
" int n19 = (n14 - n12) * 10000 / n15;" +
|
||||
" int n20 = client.rl$rot1(n17, 50, n8, n7);" +
|
||||
" int n21 = client.rl$rot2(n17, 50, n8, n7);" +
|
||||
" n17 = n20;" +
|
||||
" n20 = client.rl$rot1(n19, 10000, n8, n7);" +
|
||||
" int n22 = client.rl$rot2(n19, 10000, n8, n7);" +
|
||||
" n19 = n20;" +
|
||||
" n20 = client.rl$rot3(n16, n21, n10, n9);" +
|
||||
" n21 = client.rl$rot4(n16, n21, n10, n9);" +
|
||||
" n16 = n20;" +
|
||||
" n20 = client.rl$rot3(n18, n22, n10, n9);" +
|
||||
" n22 = client.rl$rot4(n18, n22, n10, n9);" +
|
||||
" int n23 = (n20 - n16) / 2;" +
|
||||
" int n24 = (n19 - n17) / 2;" +
|
||||
" int n25 = (n22 - n21) / 2;" +
|
||||
" int n26 = Math.abs(n23);" +
|
||||
" int n27 = Math.abs(n24);" +
|
||||
" int n28 = Math.abs(n25);" +
|
||||
" int n29 = n2 + model.getCenterX();" +
|
||||
" int n30 = n3 + model.getCenterY();" +
|
||||
" int n31 = n4 + model.getCenterZ();" +
|
||||
" int n32 = model.getExtremeX();" +
|
||||
" int n33 = model.getExtremeY();" +
|
||||
" int n34 = model.getExtremeZ();" +
|
||||
" int n35 = (n16 + n20) / 2;" +
|
||||
" int n36 = (n17 + n19) / 2;" +
|
||||
" int n37 = (n22 + n21) / 2;" +
|
||||
" int n38 = n35 - n29;" +
|
||||
" int n39 = n36 - n30;" +
|
||||
" int n40 = n37 - n31;" +
|
||||
" if (Math.abs(n38) > n32 + n26)" +
|
||||
" {" +
|
||||
" return false;" +
|
||||
" }" +
|
||||
" if (Math.abs(n39) > n33 + n27)" +
|
||||
" {" +
|
||||
" return false;" +
|
||||
" }" +
|
||||
" if (Math.abs(n40) > n34 + n28)" +
|
||||
" {" +
|
||||
" return false;" +
|
||||
" }" +
|
||||
" if (Math.abs(n40 * n24 - n39 * n25) > n33 * n28 + n34 * n27)" +
|
||||
" {" +
|
||||
" return false;" +
|
||||
" }" +
|
||||
" if (Math.abs(n38 * n25 - n40 * n23) > n34 * n26 + n32 * n28)" +
|
||||
" {" +
|
||||
" return false;" +
|
||||
" }" +
|
||||
" if (Math.abs(n39 * n23 - n38 * n24) <= n33 * n26 + n32 * n27)" +
|
||||
" {" +
|
||||
" return true;" +
|
||||
" }" +
|
||||
" return false;" +
|
||||
"}", ct);
|
||||
ct.addMethod(boundingboxCheck2);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformcheckClickBox() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod checkClickBox;
|
||||
|
||||
checkClickBox = ct.getDeclaredMethod("checkClickbox");
|
||||
ct.removeMethod(checkClickBox);
|
||||
|
||||
checkClickBox = CtMethod.make(
|
||||
"public void checkClickbox(net.runelite.api.Model model, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9, long l2) {" +
|
||||
" int n10;" +
|
||||
" int n11;" +
|
||||
" int n12;" +
|
||||
" int n13;" +
|
||||
" int n14;" +
|
||||
" net.runelite.rs.api.RSModel rSModel = (net.runelite.rs.api.RSModel)model;" +
|
||||
" boolean bl2 = l2 != 0L && (int)(l2 >>> 16 & 1L) != 1;" +
|
||||
" boolean bl3 = " + ByteCodePatcher.clientInstance + ".getViewportContainsMouse();" +
|
||||
" if (!bl2)" +
|
||||
" {" +
|
||||
" return;" +
|
||||
" }" +
|
||||
" if (!bl3)" +
|
||||
" {" +
|
||||
" return;" +
|
||||
" }" +
|
||||
" boolean bl4 = this.boundingboxCheck2((net.runelite.api.Model)rSModel, n7, n8, n9);" +
|
||||
" if (!bl4)" +
|
||||
" {" +
|
||||
" return;" +
|
||||
" }" +
|
||||
" if (rSModel.isClickable())" +
|
||||
" {" +
|
||||
" this.addHashAtMouse(l2);" +
|
||||
" return;" +
|
||||
" }" +
|
||||
" int n15 = rSModel.getVerticesCount();" +
|
||||
" int n16 = rSModel.getTrianglesCount();" +
|
||||
" int[] arrn = rSModel.getVerticesX();" +
|
||||
" int[] arrn2 = rSModel.getVerticesY();" +
|
||||
" int[] arrn3 = rSModel.getVerticesZ();" +
|
||||
" int[] arrn4 = rSModel.getTrianglesX();" +
|
||||
" int[] arrn5 = rSModel.getTrianglesY();" +
|
||||
" int[] arrn6 = rSModel.getTrianglesZ();" +
|
||||
" int[] arrn7 = rSModel.getFaceColors3();" +
|
||||
" int n17 = " + ByteCodePatcher.clientInstance + ".get3dZoom();" +
|
||||
" int n18 = " + ByteCodePatcher.clientInstance + ".getCenterX();" +
|
||||
" int n19 = " + ByteCodePatcher.clientInstance + ".getCenterY();" +
|
||||
" int n20 = 0;" +
|
||||
" int n21 = 0;" +
|
||||
" if (n2 != 0)" +
|
||||
" {" +
|
||||
" n20 = net.runelite.api.Perspective.SINE[n2];" +
|
||||
" n21 = net.runelite.api.Perspective.COSINE[n2];" +
|
||||
" }" +
|
||||
" for (n14 = 0; n14 < n15; ++n14)" +
|
||||
" {" +
|
||||
" n11 = arrn[n14];" +
|
||||
" n13 = arrn2[n14];" +
|
||||
" n12 = arrn3[n14];" +
|
||||
" if (n2 != 0)" +
|
||||
" {" +
|
||||
" n10 = n12 * n20 + n11 * n21 >> 16;" +
|
||||
" n12 = n12 * n21 - n11 * n20 >> 16;" +
|
||||
" n11 = n10;" +
|
||||
" }" +
|
||||
" n10 = (n12 += n9) * n5 + n6 * (n11 += n7) >> 16;" +
|
||||
" n12 = n6 * n12 - n11 * n5 >> 16;" +
|
||||
" n11 = n10;" +
|
||||
" n10 = n4 * (n13 += n8) - n12 * n3 >> 16;" +
|
||||
" if ((n12 = n13 * n3 + n4 * n12 >> 16) >= 50)" +
|
||||
" {" +
|
||||
" client.rl$modelViewportYs[n14] = n11 * n17 / n12 + n18;" +
|
||||
" client.rl$modelViewportXs[n14] = n10 * n17 / n12 + n19;" +
|
||||
" continue;" +
|
||||
" }" +
|
||||
" client.rl$modelViewportYs[n14] = -5000;" +
|
||||
" }" +
|
||||
" n14 = " + ByteCodePatcher.clientInstance + ".getViewportMouseX();" +
|
||||
" n11 = " + ByteCodePatcher.clientInstance + ".getViewportMouseY();" +
|
||||
" n13 = 0;" +
|
||||
" while (n13 < n16)" +
|
||||
" {" +
|
||||
" if (arrn7[n13] != -2)" +
|
||||
" {" +
|
||||
" int n22;" +
|
||||
" boolean bl5;" +
|
||||
" int n23;" +
|
||||
" n12 = arrn4[n13];" +
|
||||
" n10 = arrn5[n13];" +
|
||||
" int n24 = arrn6[n13];" +
|
||||
" int n25 = rl$modelViewportYs[n12];" +
|
||||
" int n26 = rl$modelViewportYs[n10];" +
|
||||
" int n27 = rl$modelViewportYs[n24];" +
|
||||
" int n28 = rl$modelViewportXs[n12];" +
|
||||
" int n29 = rl$modelViewportXs[n10];" +
|
||||
" int n30 = rl$modelViewportXs[n24];" +
|
||||
" if (n25 != -5000 && n26 != -5000 && n27 != -5000 && (bl5 = (n23 = (n22 = rSModel.isClickable() ? 20 : 5) + n11) < n28 && n23 < n29 && n23 < n30 ? false : ((n23 = n11 - n22) > n28 && n23 > n29 && n23 > n30 ? false : ((n23 = n22 + n14) < n25 && n23 < n26 && n23 < n27 ? false : (n23 = n14 - n22) <= n25 || n23 <= n26 || n23 <= n27))))" +
|
||||
" {" +
|
||||
" this.addHashAtMouse(l2);" +
|
||||
" return;" +
|
||||
" }" +
|
||||
" }" +
|
||||
" ++n13;" +
|
||||
" }" +
|
||||
"}", ct);
|
||||
ct.addMethod(checkClickBox);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package net.runelite.client.rs.bytecode.transformers;
|
||||
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
import javassist.NotFoundException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.rs.bytecode.ByteCodePatcher;
|
||||
|
||||
@Slf4j
|
||||
// This prevents the client from sending stack traces to Jagex at all, even classes outside of runelite.
|
||||
public class ErrorTransform implements Transform
|
||||
{
|
||||
private CtClass ct;
|
||||
|
||||
// Where Runelites error interceptor is located, not auto-scraped.
|
||||
private static final String ERROR_INSTANCE_CLASS = "dp";
|
||||
private static final String ERROR_INSTANCE_METHOD = "a";
|
||||
// private static final String ERROR_WARNING = "Tried to send a warning";
|
||||
|
||||
@Override
|
||||
public void modify(Class clazz)
|
||||
{
|
||||
try
|
||||
{
|
||||
ct = ByteCodePatcher.classPool.get(ERROR_INSTANCE_CLASS);
|
||||
transformError();
|
||||
|
||||
ByteCodePatcher.modifiedClasses.add(ct);
|
||||
}
|
||||
catch (CannotCompileException | NotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void transformError() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod error = ct.getDeclaredMethod(ERROR_INSTANCE_METHOD);
|
||||
ct.removeMethod(error);
|
||||
|
||||
error = CtMethod.make(
|
||||
"public static void a(String string, Throwable throwable, byte by)" +
|
||||
"{" +
|
||||
" throwable.printStackTrace();" +
|
||||
" System.out.println(\"[RuneLitePlus] Prevented preceeding stack trace from being sent to Jagex\");" +
|
||||
"}", ct);
|
||||
ct.addMethod(error);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package net.runelite.client.rs.bytecode.transformers;
|
||||
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
import javassist.CtNewMethod;
|
||||
import javassist.NotFoundException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.rs.bytecode.ByteCodePatcher;
|
||||
|
||||
@Slf4j
|
||||
public class PlayerTransform implements Transform
|
||||
{
|
||||
private CtClass ct;
|
||||
|
||||
@Override
|
||||
public void modify(Class player)
|
||||
{
|
||||
try
|
||||
{
|
||||
ct = ByteCodePatcher.classPool.get(player.getName());
|
||||
transformProtectedGetSkullIcon();
|
||||
transformGetSkullIcon();
|
||||
ByteCodePatcher.modifiedClasses.add(ct);
|
||||
}
|
||||
catch (CannotCompileException | NotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void transformProtectedGetSkullIcon() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod protectedGetSkullIcon;
|
||||
|
||||
protectedGetSkullIcon = ct.getDeclaredMethod("1protect$getRsSkullIcon");
|
||||
ct.removeMethod(protectedGetSkullIcon);
|
||||
protectedGetSkullIcon.setName("getRsSkullIcon");
|
||||
|
||||
ct.addMethod(protectedGetSkullIcon);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformGetSkullIcon() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod getSkullIcon;
|
||||
|
||||
String SkullIcon = "net.runelite.api.SkullIcon";
|
||||
getSkullIcon = ct.getDeclaredMethod("getSkullIcon");
|
||||
ct.removeMethod(getSkullIcon);
|
||||
|
||||
getSkullIcon = CtNewMethod.make(
|
||||
"public " + SkullIcon + " getSkullIcon()" +
|
||||
"{" +
|
||||
"switch (this.getRsSkullIcon())" +
|
||||
"{" +
|
||||
"case 0:" +
|
||||
"return " + SkullIcon + ".SKULL;" +
|
||||
"case 1:" +
|
||||
"return " + SkullIcon + ".SKULL_FIGHT_PIT;" +
|
||||
"case 8:" +
|
||||
"return " + SkullIcon + ".DEAD_MAN_FIVE;" +
|
||||
"case 9:" +
|
||||
"return " + SkullIcon + ".DEAD_MAN_FOUR;" +
|
||||
"case 10:" +
|
||||
"return " + SkullIcon + ".DEAD_MAN_THREE;" +
|
||||
"case 11:" +
|
||||
"return " + SkullIcon + ".DEAD_MAN_TWO;" +
|
||||
"case 12:" +
|
||||
"return " + SkullIcon + ".DEAD_MAN_ONE;" +
|
||||
"}" +
|
||||
"return null;" +
|
||||
"}", ct);
|
||||
ct.addMethod(getSkullIcon);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package net.runelite.client.rs.bytecode.transformers;
|
||||
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
import javassist.CtNewMethod;
|
||||
import javassist.NotFoundException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.rs.bytecode.ByteCodePatcher;
|
||||
|
||||
@Slf4j
|
||||
public class ProjectileTransform implements Transform
|
||||
{
|
||||
private CtClass ct;
|
||||
|
||||
// Next variable is manually added, and will break on rev update
|
||||
private static final String interactingIntvalue = "-1655053057";
|
||||
|
||||
@Override
|
||||
public void modify(Class projectile)
|
||||
{
|
||||
try
|
||||
{
|
||||
ct = ByteCodePatcher.classPool.get(projectile.getName());
|
||||
transformGetAnimation();
|
||||
transformInteracting();
|
||||
ByteCodePatcher.modifiedClasses.add(ct);
|
||||
}
|
||||
catch (CannotCompileException | NotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void transformGetAnimation() throws CannotCompileException, NotFoundException
|
||||
{
|
||||
CtMethod getAnimation;
|
||||
|
||||
getAnimation = ct.getDeclaredMethod("projectileMoved", new CtClass[]{CtClass.intType, CtClass.intType, CtClass.intType, CtClass.intType});
|
||||
ct.removeMethod(getAnimation);
|
||||
|
||||
getAnimation = CtNewMethod.make(
|
||||
"public void projectileMoved(int n, int n2, int n3, int n4)" +
|
||||
"{ " +
|
||||
" int n5 = this.getId();" +
|
||||
" net.runelite.api.coords.LocalPoint localPoint = new net.runelite.api.coords.LocalPoint(n, n2);" +
|
||||
" net.runelite.api.events.ProjectileMoved projectileMoved = new net.runelite.api.events.ProjectileMoved();" +
|
||||
" projectileMoved.setProjectile(this);" +
|
||||
" projectileMoved.setPosition(localPoint);" +
|
||||
" projectileMoved.setZ(n3);" +
|
||||
ByteCodePatcher.clientInstance + ".getCallbacks().post(projectileMoved);" +
|
||||
"}", ct);
|
||||
ct.addMethod(getAnimation);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private void transformInteracting() throws CannotCompileException
|
||||
{
|
||||
CtMethod getRsInteracting;
|
||||
CtMethod getInteracting;
|
||||
|
||||
getRsInteracting = CtNewMethod.make("public int getRsInteracting() { return this.n * " + interactingIntvalue + "; }", ct);
|
||||
ct.addMethod(getRsInteracting);
|
||||
|
||||
getInteracting = CtNewMethod.make(
|
||||
"public net.runelite.api.Actor getInteracting()" +
|
||||
"{" +
|
||||
" int var1 = this.getRsInteracting();" +
|
||||
" if (var1 == 0)" +
|
||||
" {" +
|
||||
" return null;" +
|
||||
" }" +
|
||||
" else" +
|
||||
" {" +
|
||||
" int var2;" +
|
||||
" if (var1 > 0)" +
|
||||
" {" +
|
||||
" var2 = var1 - 1;" +
|
||||
" net.runelite.rs.api.RSNPC[] var4 = " + ByteCodePatcher.clientInstance + ".getCachedNPCs();" +
|
||||
" return var4[var2];" +
|
||||
" }" +
|
||||
" else" +
|
||||
" {" +
|
||||
" var2 = -var1 - 1;" +
|
||||
" if (var2 == " + ByteCodePatcher.clientInstance + ".getLocalInteractingIndex())" +
|
||||
" {" +
|
||||
" return " + ByteCodePatcher.clientInstance + ".getLocalPlayer();" +
|
||||
" }" +
|
||||
" else" +
|
||||
" {" +
|
||||
" net.runelite.rs.api.RSPlayer[] var3 = " + ByteCodePatcher.clientInstance + ".getCachedPlayers();" +
|
||||
" return var3[var2];" +
|
||||
" }" +
|
||||
" }" +
|
||||
" }" +
|
||||
"}", ct);
|
||||
ct.addMethod(getInteracting);
|
||||
|
||||
log.info(
|
||||
"[RuneLitePlus] transformed {} ({}) at class: {}",
|
||||
this.getClass().getSimpleName(),
|
||||
new Object(){}.getClass().getEnclosingMethod().getName(),
|
||||
ct.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package net.runelite.client.rs.bytecode.transformers;
|
||||
|
||||
public interface Transform {
|
||||
|
||||
void modify(Class clazz);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.runelite.client.rs.mixins.transformers.*;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.commons.ClassRemapper;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class MixinRunner
|
||||
{
|
||||
|
||||
private final Map<String, byte[]> classes;
|
||||
private final Map<String, byte[]> patches;
|
||||
|
||||
public Map<String, byte[]> run()
|
||||
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException
|
||||
{
|
||||
runVisitor(InterfaceTransformer.class);
|
||||
runVisitor(OverwriteTransformer.class);
|
||||
runSanityChecker(OverwriteSanityCheck.class);
|
||||
runVisitor(InjectTransformer.class);
|
||||
runVisitor(AppendTransformer.class); // append has to come before prepend or append does nothing
|
||||
// (test method: Projectile.rl$$init()V )
|
||||
runVisitor(PrependTransformer.class);
|
||||
runRemapper(ProtectTransformer.class);
|
||||
|
||||
recalcMaxes();
|
||||
return classes;
|
||||
}
|
||||
|
||||
private void runRemapper(Class<? extends Remapper> clazz) throws IllegalAccessException, InstantiationException
|
||||
{
|
||||
for (Map.Entry<String, byte[]> entry : classes.entrySet())
|
||||
{
|
||||
if (entry.getKey().contains("META-INF"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Remapper inst = clazz.newInstance();
|
||||
ClassReader cr = new ClassReader(entry.getValue());
|
||||
ClassWriter cw = new ClassWriter(cr, 1);
|
||||
cr.accept(new ClassRemapper(cw, inst), 0);
|
||||
|
||||
entry.setValue(cw.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
private void runVisitor(Class<? extends ClassVisitor> clazz)
|
||||
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException
|
||||
{
|
||||
runVisitor(clazz, 1);
|
||||
}
|
||||
|
||||
private void runVisitor(Class<? extends ClassVisitor> clazz, int flags)
|
||||
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException
|
||||
{
|
||||
for (Map.Entry<String, byte[]> entry : classes.entrySet())
|
||||
{
|
||||
if (entry.getKey().contains("META-INF"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ClassReader cr = new ClassReader(entry.getValue());
|
||||
ClassWriter cw = new ClassWriter(cr, flags);
|
||||
byte[] patch = patches.getOrDefault(entry.getKey(), null);
|
||||
ClassNode node = new ClassNode();
|
||||
cr.accept(node, 0);
|
||||
ClassVisitor inst = clazz.getConstructor(ClassVisitor.class, byte[].class, ClassNode.class).newInstance(cw,
|
||||
patch, node);
|
||||
cr.accept(inst, 0);
|
||||
|
||||
entry.setValue(cw.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
private void runSanityChecker(Class<? extends SanityChecker> clazz)
|
||||
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException
|
||||
{
|
||||
runSanityChecker(clazz, 1);
|
||||
}
|
||||
|
||||
private void runSanityChecker(Class<? extends SanityChecker> clazz, int flags)
|
||||
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException
|
||||
{
|
||||
for (Map.Entry<String, byte[]> entry : patches.entrySet())
|
||||
{
|
||||
ClassReader cr = new ClassReader(entry.getValue());
|
||||
ClassWriter cw = new ClassWriter(cr, flags);
|
||||
ClassNode node = new ClassNode();
|
||||
cr.accept(node, 0);
|
||||
SanityChecker inst = clazz.getConstructor(ClassVisitor.class, ClassNode.class).newInstance(cw, node);
|
||||
cr.accept(inst, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void recalcMaxes()
|
||||
throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException
|
||||
{
|
||||
runVisitor(DoNothingTransformer.class, 3);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.util.RefUtils;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LineNumberNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
@Slf4j
|
||||
public class AppendTransformer extends ClassVisitor implements Opcodes
|
||||
{
|
||||
|
||||
private final byte[] patch;
|
||||
private String className;
|
||||
private ClassNode classNode;
|
||||
|
||||
public AppendTransformer(ClassVisitor classVisitor, byte[] patch, ClassNode node)
|
||||
{
|
||||
super(Opcodes.ASM6, classVisitor);
|
||||
this.patch = patch;
|
||||
this.classNode = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
className = name;
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions)
|
||||
{
|
||||
if (patch == null)
|
||||
{
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
ClassReader cr = new ClassReader(patch);
|
||||
ClassNode patchNode = new ClassNode(Opcodes.ASM6);
|
||||
cr.accept(patchNode, 0);
|
||||
for (Object obj : patchNode.methods)
|
||||
{
|
||||
MethodNode patchMethod = (MethodNode) obj;
|
||||
if ((patchMethod.access == access && patchMethod.name.equals("append$" + name) &&
|
||||
patchMethod.desc.equals(descriptor)) &&
|
||||
RefUtils.checkAnnotation(patchMethod, "Append"))
|
||||
{
|
||||
MethodVisitor mv =
|
||||
new MethodVisitor(Opcodes.ASM6, super.visitMethod(access, name, descriptor, signature,
|
||||
exceptions))
|
||||
{
|
||||
};
|
||||
mv.visitCode();
|
||||
|
||||
for (Object obj2 : classNode.methods)
|
||||
{
|
||||
MethodNode classMethod = (MethodNode) obj2;
|
||||
if (classMethod.access == access && classMethod.name.equals(name) &&
|
||||
classMethod.desc.equals(descriptor))
|
||||
{
|
||||
AbstractInsnNode inode = classMethod.instructions.getLast();
|
||||
|
||||
while(inode instanceof LabelNode || inode instanceof LineNumberNode)
|
||||
{
|
||||
inode = inode.getPrevious();
|
||||
}
|
||||
|
||||
if(RefUtils.isReturn(inode.getOpcode(), true))
|
||||
{
|
||||
log.error("[Append] Can't append to {}.{}, requires typed return opcode", className, name);
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
|
||||
classMethod.instructions.remove(inode);
|
||||
|
||||
classMethod.accept(new MethodReflector(mv));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
patchMethod.accept(new MethodReflector(mv));
|
||||
|
||||
mv.visitEnd();
|
||||
return mv;
|
||||
}
|
||||
}
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
public class DoNothingTransformer extends ClassVisitor
|
||||
{
|
||||
public DoNothingTransformer(ClassVisitor parent, byte[] patch, ClassNode node)
|
||||
{
|
||||
super(Opcodes.ASM6, parent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import net.runelite.client.util.RefUtils;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class InjectTransformer extends ClassVisitor
|
||||
{
|
||||
|
||||
private final byte[] patch;
|
||||
private ClassNode node;
|
||||
private String className;
|
||||
private boolean patching = false;
|
||||
|
||||
public InjectTransformer(ClassVisitor classVisitor, byte[] patch, ClassNode node)
|
||||
{
|
||||
super(Opcodes.ASM6, classVisitor);
|
||||
this.patch = patch;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
className = name;
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions)
|
||||
{
|
||||
if (patch == null || name.startsWith("1protect$"))
|
||||
{
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
if (name.startsWith("prepend$") || name.startsWith("append$")||
|
||||
(patching && name.startsWith("<")))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
ClassReader cr = new ClassReader(patch);
|
||||
ClassNode patchNode = new ClassNode(Opcodes.ASM6);
|
||||
cr.accept(patchNode, 0);
|
||||
for (Object obj : patchNode.methods)
|
||||
{
|
||||
MethodNode node = (MethodNode) obj;
|
||||
if ((node.access == access && node.name.equals(name) && node.desc.equals(descriptor)) &&
|
||||
RefUtils.checkAnnotation(node, "Inject"))
|
||||
{
|
||||
mv.visitCode();
|
||||
node.accept(new MethodReflector(mv));
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
|
||||
if (patch == null)
|
||||
{
|
||||
super.visitEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
ClassReader cr = new ClassReader(patch);
|
||||
ClassNode patchNode = new ClassNode(Opcodes.ASM6);
|
||||
cr.accept(patchNode, 0);
|
||||
patching = true;
|
||||
for (Object obj : patchNode.methods)
|
||||
{
|
||||
MethodNode node = (MethodNode) obj;
|
||||
if (RefUtils.checkAnnotation(node, "Inject"))
|
||||
{
|
||||
visitMethod(node.access, node.name, node.desc, node.signature,
|
||||
(String[]) node.exceptions.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
|
||||
for (Object obj : patchNode.fields)
|
||||
{
|
||||
FieldNode node = (FieldNode) obj;
|
||||
if (RefUtils.checkAnnotation(node, "Inject"))
|
||||
{
|
||||
visitField(node.access, node.name, node.desc, node.signature, node.value);
|
||||
}
|
||||
}
|
||||
patching = false;
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Slf4j
|
||||
public class InterfaceTransformer extends ClassVisitor implements Opcodes
|
||||
{
|
||||
|
||||
private final byte[] patch;
|
||||
private ClassNode node;
|
||||
private String className;
|
||||
|
||||
public InterfaceTransformer(ClassVisitor classVisitor, byte[] patch, ClassNode node)
|
||||
{
|
||||
super(Opcodes.ASM6, classVisitor);
|
||||
this.patch = patch;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
className = name;
|
||||
if(patch != null)
|
||||
{
|
||||
ClassReader reader = new ClassReader(patch);
|
||||
ClassNode pNode = new ClassNode();
|
||||
reader.accept(pNode, 0);
|
||||
if(pNode.interfaces != null && pNode.interfaces.size() != 0)
|
||||
{
|
||||
if(interfaces == null)
|
||||
{
|
||||
interfaces = (String[]) pNode.interfaces.toArray(new String[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayList<String> list = new ArrayList<>(Arrays.asList(interfaces));
|
||||
pNode.interfaces.forEach((s) -> list.add((String) s));
|
||||
interfaces = list.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.TypePath;
|
||||
|
||||
public class MethodReflector extends MethodVisitor
|
||||
{
|
||||
|
||||
private MethodVisitor target;
|
||||
|
||||
public MethodReflector(MethodVisitor target)
|
||||
{
|
||||
super(Opcodes.ASM6);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public void visitParameter(String var1, int var2)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitParameter(var1, var2);
|
||||
}
|
||||
super.visitParameter(var1, var2);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotationDefault()
|
||||
{
|
||||
return super.visitAnnotationDefault();
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String var1, boolean var2)
|
||||
{
|
||||
return super.visitAnnotation(var1, var2);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitTypeAnnotation(int var1, TypePath var2, String var3, boolean var4)
|
||||
{
|
||||
return super.visitTypeAnnotation(var1, var2, var3, var4);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitParameterAnnotation(int var1, String var2, boolean var3)
|
||||
{
|
||||
return super.visitParameterAnnotation(var1, var2, var3);
|
||||
}
|
||||
|
||||
public void visitAttribute(Attribute var1)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitAttribute(var1);
|
||||
}
|
||||
super.visitAttribute(var1);
|
||||
}
|
||||
|
||||
public void visitFrame(int var1, int var2, Object[] var3, int var4, Object[] var5)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitFrame(var1, var2, var3, var4, var5);
|
||||
}
|
||||
super.visitFrame(var1, var2, var3, var4, var5);
|
||||
}
|
||||
|
||||
public void visitInsn(int var1)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitInsn(var1);
|
||||
}
|
||||
super.visitInsn(var1);
|
||||
}
|
||||
|
||||
public void visitIntInsn(int var1, int var2)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitIntInsn(var1, var2);
|
||||
}
|
||||
super.visitIntInsn(var1, var2);
|
||||
}
|
||||
|
||||
public void visitVarInsn(int var1, int var2)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitVarInsn(var1, var2);
|
||||
}
|
||||
super.visitVarInsn(var1, var2);
|
||||
}
|
||||
|
||||
public void visitTypeInsn(int var1, String var2)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitTypeInsn(var1, var2);
|
||||
}
|
||||
super.visitTypeInsn(var1, var2);
|
||||
}
|
||||
|
||||
public void visitFieldInsn(int var1, String var2, String var3, String var4)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitFieldInsn(var1, var2, var3, var4);
|
||||
}
|
||||
super.visitFieldInsn(var1, var2, var3, var4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public void visitMethodInsn(int var1, String var2, String var3, String var4)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitMethodInsn(var1, var2, var3, var4);
|
||||
}
|
||||
super.visitMethodInsn(var1, var2, var3, var4);
|
||||
}
|
||||
|
||||
public void visitMethodInsn(int var1, String var2, String var3, String var4, boolean var5)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitMethodInsn(var1, var2, var3, var4, var5);
|
||||
}
|
||||
super.visitMethodInsn(var1, var2, var3, var4, var5);
|
||||
}
|
||||
|
||||
public void visitInvokeDynamicInsn(String var1, String var2, Handle var3, Object... var4)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitInvokeDynamicInsn(var1, var2, var3, var4);
|
||||
}
|
||||
super.visitInvokeDynamicInsn(var1, var2, var3, var4);
|
||||
}
|
||||
|
||||
public void visitJumpInsn(int var1, Label var2)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitJumpInsn(var1, var2);
|
||||
}
|
||||
super.visitJumpInsn(var1, var2);
|
||||
}
|
||||
|
||||
public void visitLabel(Label var1)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitLabel(var1);
|
||||
}
|
||||
super.visitLabel(var1);
|
||||
}
|
||||
|
||||
public void visitLdcInsn(Object var1)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitLdcInsn(var1);
|
||||
}
|
||||
super.visitLdcInsn(var1);
|
||||
}
|
||||
|
||||
public void visitIincInsn(int var1, int var2)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitIincInsn(var1, var2);
|
||||
}
|
||||
super.visitIincInsn(var1, var2);
|
||||
}
|
||||
|
||||
public void visitTableSwitchInsn(int var1, int var2, Label var3, Label... var4)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitTableSwitchInsn(var1, var2, var3, var4);
|
||||
}
|
||||
super.visitTableSwitchInsn(var1, var2, var3, var4);
|
||||
}
|
||||
|
||||
public void visitLookupSwitchInsn(Label var1, int[] var2, Label[] var3)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitLookupSwitchInsn(var1, var2, var3);
|
||||
}
|
||||
super.visitLookupSwitchInsn(var1, var2, var3);
|
||||
}
|
||||
|
||||
public void visitMultiANewArrayInsn(String var1, int var2)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitMultiANewArrayInsn(var1, var2);
|
||||
}
|
||||
super.visitMultiANewArrayInsn(var1, var2);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitInsnAnnotation(int var1, TypePath var2, String var3, boolean var4)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitInsnAnnotation(var1, var2, var3, var4);
|
||||
}
|
||||
return super.visitInsnAnnotation(var1, var2, var3, var4);
|
||||
}
|
||||
|
||||
public void visitTryCatchBlock(Label var1, Label var2, Label var3, String var4)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitTryCatchBlock(var1, var2, var3, var4);
|
||||
}
|
||||
super.visitTryCatchBlock(var1, var2, var3, var4);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitTryCatchAnnotation(int var1, TypePath var2, String var3, boolean var4)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitTryCatchAnnotation(var1, var2, var3, var4);
|
||||
}
|
||||
return super.visitTryCatchAnnotation(var1, var2, var3, var4);
|
||||
}
|
||||
|
||||
public void visitLocalVariable(String var1, String var2, String var3, Label var4, Label var5, int var6)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitLocalVariable(var1, var2, var3, var4, var5, var6);
|
||||
}
|
||||
super.visitLocalVariable(var1, var2, var3, var4, var5, var6);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitLocalVariableAnnotation(int var1, TypePath var2, Label[] var3, Label[] var4, int[] var5, String var6, boolean var7)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitLocalVariableAnnotation(var1, var2, var3, var4, var5, var6, var7);
|
||||
}
|
||||
return super.visitLocalVariableAnnotation(var1, var2, var3, var4, var5, var6, var7);
|
||||
}
|
||||
|
||||
public void visitLineNumber(int var1, Label var2)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitLineNumber(var1, var2);
|
||||
}
|
||||
super.visitLineNumber(var1, var2);
|
||||
}
|
||||
|
||||
public void visitMaxs(int var1, int var2)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
target.visitMaxs(var1, var2);
|
||||
}
|
||||
super.visitMaxs(var1, var2);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.util.RefUtils;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Slf4j
|
||||
public class OverwriteSanityCheck extends SanityChecker implements Opcodes
|
||||
{
|
||||
|
||||
private String className;
|
||||
private ClassNode patchNode;
|
||||
public static final ArrayList<String> methodsUsed = new ArrayList<>();
|
||||
|
||||
public OverwriteSanityCheck(ClassVisitor classVisitor, ClassNode node)
|
||||
{
|
||||
super(ASM6, classVisitor);
|
||||
this.className = node.name;
|
||||
this.patchNode = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions)
|
||||
{
|
||||
String check = String.format("%s %s %s %s", className, name,
|
||||
descriptor, access);
|
||||
|
||||
MethodNode methodNode = null;
|
||||
for (Object obj2 : patchNode.methods)
|
||||
{
|
||||
MethodNode classMethod = (MethodNode) obj2;
|
||||
if (classMethod.access == access && classMethod.name.equals(name) &&
|
||||
classMethod.desc.equals(descriptor))
|
||||
{
|
||||
methodNode = classMethod;
|
||||
}
|
||||
}
|
||||
|
||||
if(methodNode == null)
|
||||
{
|
||||
log.error("[OverwriteSanity] Failed to find original patch method for {}", check);
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
|
||||
if (!RefUtils.checkAnnotation(methodNode, "Overwrite"))
|
||||
{
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
|
||||
if (!methodsUsed.contains(check))
|
||||
{
|
||||
throw new RuntimeException("[OverwriteSanity] Overwrite target not found: " + check);
|
||||
}
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.util.RefUtils;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
@Slf4j
|
||||
public class OverwriteTransformer extends ClassVisitor
|
||||
{
|
||||
|
||||
private final byte[] patch;
|
||||
private ClassNode node;
|
||||
private String className;
|
||||
|
||||
public OverwriteTransformer(ClassVisitor classVisitor, byte[] patch, ClassNode node)
|
||||
{
|
||||
super(Opcodes.ASM6, classVisitor);
|
||||
this.patch = patch;
|
||||
this.node = node;
|
||||
this.className = node.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
className = name;
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions)
|
||||
{
|
||||
if (patch == null || name.startsWith("1protect$"))
|
||||
{
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
|
||||
if (name.startsWith("prepend$") || name.startsWith("append$"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassReader cr = new ClassReader(patch);
|
||||
ClassNode patchNode = new ClassNode(Opcodes.ASM6);
|
||||
cr.accept(patchNode, 0);
|
||||
|
||||
for (Object obj : patchNode.methods)
|
||||
{
|
||||
MethodNode patchMethod = (MethodNode) obj;
|
||||
|
||||
if (patchMethod.access == access && patchMethod.name.equals(name) && patchMethod.desc.equals(descriptor))
|
||||
{
|
||||
if (RefUtils.checkAnnotation(patchMethod, "Overwrite"))
|
||||
{
|
||||
MethodVisitor mv =
|
||||
new MethodVisitor(Opcodes.ASM6, super.visitMethod(access, name, descriptor, signature,
|
||||
exceptions))
|
||||
{
|
||||
};
|
||||
mv.visitCode();
|
||||
patchMethod.accept(new MethodReflector(mv));
|
||||
mv.visitEnd();
|
||||
String s = String.format("%s %s %s %s", className, patchMethod.name,
|
||||
patchMethod.desc, patchMethod.access);
|
||||
OverwriteSanityCheck.methodsUsed.add(s);
|
||||
return mv;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import net.runelite.client.util.RefUtils;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class PrependTransformer extends ClassVisitor
|
||||
{
|
||||
|
||||
private final byte[] patch;
|
||||
private String className;
|
||||
private ClassNode classNode;
|
||||
|
||||
public PrependTransformer(ClassVisitor classVisitor, byte[] patch, ClassNode node)
|
||||
{
|
||||
super(Opcodes.ASM6, classVisitor);
|
||||
this.patch = patch;
|
||||
this.classNode = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
className = name;
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions)
|
||||
{
|
||||
if (patch == null)
|
||||
{
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
ClassReader cr = new ClassReader(patch);
|
||||
ClassNode patchNode = new ClassNode(Opcodes.ASM6);
|
||||
cr.accept(patchNode, 0);
|
||||
for (Object obj : patchNode.methods)
|
||||
{
|
||||
MethodNode patchMethod = (MethodNode) obj;
|
||||
if ((patchMethod.access == access && patchMethod.name.equals("prepend$" + name) &&
|
||||
patchMethod.desc.equals(descriptor)) &&
|
||||
RefUtils.checkAnnotation(patchMethod, "Prepend"))
|
||||
{
|
||||
MethodVisitor mv =
|
||||
new MethodVisitor(Opcodes.ASM6, super.visitMethod(access, name, descriptor, signature,
|
||||
exceptions))
|
||||
{
|
||||
};
|
||||
mv.visitCode();
|
||||
|
||||
AbstractInsnNode node = patchMethod.instructions.getLast();
|
||||
while (!(node instanceof InsnNode))
|
||||
{
|
||||
node = node.getPrevious();
|
||||
}
|
||||
|
||||
if (RefUtils.isReturn(node.getOpcode()))
|
||||
{
|
||||
patchMethod.instructions.remove(node);
|
||||
}
|
||||
|
||||
patchMethod.accept(new MethodReflector(mv));
|
||||
|
||||
for (Object obj2 : classNode.methods)
|
||||
{
|
||||
MethodNode classMethod = (MethodNode) obj2;
|
||||
if (classMethod.access == access && classMethod.name.equals(name) &&
|
||||
classMethod.desc.equals(descriptor))
|
||||
{
|
||||
classMethod.accept(new MethodReflector(mv));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mv.visitEnd();
|
||||
return mv;
|
||||
}
|
||||
}
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
if (patch == null)
|
||||
{
|
||||
super.visitEnd();
|
||||
return;
|
||||
}
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
|
||||
public class ProtectTransformer extends Remapper
|
||||
{
|
||||
|
||||
public String mapFieldName(String owner, String name, String descriptor)
|
||||
{
|
||||
if (name.startsWith("1protect$"))
|
||||
{
|
||||
name = name.substring("1protect$".length());
|
||||
}
|
||||
return super.mapFieldName(owner, name, descriptor);
|
||||
}
|
||||
|
||||
public String mapMethodName(String owner, String name, String descriptor)
|
||||
{
|
||||
if (name.startsWith("1protect$"))
|
||||
{
|
||||
name = name.substring("1protect$".length());
|
||||
}
|
||||
return super.mapMethodName(owner, name, descriptor);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.rs.mixins.transformers;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public abstract class SanityChecker extends ClassVisitor implements Opcodes
|
||||
{
|
||||
protected SanityChecker(int i, ClassVisitor classVisitor)
|
||||
{
|
||||
super(i, classVisitor);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
|
||||
* 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 net.runelite.client.util;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class RefUtils implements Opcodes
|
||||
{
|
||||
|
||||
private static final String TYPE_PREFIX = "us/runelitepl/mixinprocessor/annotations/";
|
||||
|
||||
public static boolean isReturn(int opcode, boolean checkType)
|
||||
{
|
||||
return (opcode == RETURN && !checkType) || opcode == IRETURN || opcode == LRETURN || opcode == DRETURN ||
|
||||
opcode == ARETURN || opcode == FRETURN;
|
||||
}
|
||||
|
||||
public static boolean isReturn(int opcode)
|
||||
{
|
||||
return isReturn(opcode, false);
|
||||
}
|
||||
|
||||
public static boolean checkAnnotation(MethodNode method, String annotation)
|
||||
{
|
||||
if (method.visibleAnnotations != null)
|
||||
{
|
||||
for (Object obj : method.visibleAnnotations)
|
||||
{
|
||||
if (((AnnotationNode) obj).desc.equals(makeAnnotationDesc(annotation)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean checkAnnotation(FieldNode field, String annotation)
|
||||
{
|
||||
if (field.visibleAnnotations != null)
|
||||
{
|
||||
for (Object obj : field.visibleAnnotations)
|
||||
{
|
||||
if (((AnnotationNode) obj).desc.equals(makeAnnotationDesc(annotation)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String makeAnnotationDesc(String annot)
|
||||
{
|
||||
return "L" + TYPE_PREFIX + annot + ";";
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user