diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index bcf91bc46d..5e47876079 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -61,6 +61,7 @@ import net.runelite.client.menus.MenuManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginInstantiationException; import net.runelite.client.plugins.PluginManager; +import net.runelite.client.rs.ClientLoader; import net.runelite.client.rs.ClientUpdateCheckMode; import net.runelite.client.task.Scheduler; import net.runelite.client.ui.ClientUI; @@ -87,7 +88,7 @@ public class RuneLite public static final File PROFILES_DIR = new File(RUNELITE_DIR, "profiles"); public static final File PLUGIN_DIR = new File(RUNELITE_DIR, "plugins"); public static final File SCREENSHOT_DIR = new File(RUNELITE_DIR, "screenshots"); - private static final RuneLiteSplashScreen splashScreen = new RuneLiteSplashScreen(); + static final RuneLiteSplashScreen splashScreen = new RuneLiteSplashScreen(); @Getter @@ -183,6 +184,7 @@ public class RuneLite parser.accepts("developer-mode", "Enable developer tools"); parser.accepts("debug", "Show extra debugging output"); parser.accepts("no-splash", "Do not show the splash screen"); + parser.accepts("local-injected", "Use local injected-client"); final ArgumentAcceptingOptionSpec proxyInfo = parser .accepts("proxy") @@ -261,6 +263,11 @@ public class RuneLite logger.setLevel(Level.DEBUG); } + if (options.has("local-injected")) + { + ClientLoader.useLocalInjected = true; + } + Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { log.error("Uncaught exception:", throwable); diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java index 55f658feac..71d44f9a8e 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java @@ -26,20 +26,23 @@ */ package net.runelite.client.rs; +import net.runelite.api.Client; import com.google.common.io.ByteStreams; -import io.sigpipe.jbsdiff.Diff; import io.sigpipe.jbsdiff.InvalidHeaderException; import io.sigpipe.jbsdiff.Patch; import java.applet.Applet; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.security.cert.Certificate; import java.security.cert.CertificateException; @@ -51,17 +54,16 @@ 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 javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; + import static net.runelite.client.RuneLite.RUNELITE_DIR; import static net.runelite.client.rs.ClientUpdateCheckMode.AUTO; import static net.runelite.client.rs.ClientUpdateCheckMode.CUSTOM; import static net.runelite.client.rs.ClientUpdateCheckMode.NONE; -import static net.runelite.client.rs.ClientUpdateCheckMode.PATCH; import net.runelite.http.api.RuneLiteAPI; import okhttp3.Request; import okhttp3.Response; @@ -71,16 +73,15 @@ import org.apache.commons.compress.compressors.CompressorException; @Singleton public class ClientLoader { - private static final File CUSTOMFILE = new File("./injected-client/target/injected-client-1.5.27-SNAPSHOT.jar"); - private static final File PATCHFILE = new File("replace me!"); - private static final File OUTPUT = new File("replace me!"); + private static final File CUSTOMFILE = new File("./injected-client/target/injected-client-1.0-SNAPSHOT.jar"); private final ClientConfigLoader clientConfigLoader; private ClientUpdateCheckMode updateCheckMode; + public static boolean useLocalInjected = false; @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; @@ -88,11 +89,7 @@ public class ClientLoader public Applet load() { - if (updateCheckMode == NONE) - { - return null; - } - + updateCheckMode = CUSTOM; try { Manifest manifest = new Manifest(); @@ -106,8 +103,8 @@ public class ClientLoader 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()) { @@ -154,118 +151,53 @@ public class ClientLoader } } - if (updateCheckMode == PATCH) - { - log.debug("Creating patches"); - int patchCount = 0; - - Map injectedFile = new HashMap<>(); - - loadJar(injectedFile, CUSTOMFILE); - - ByteArrayOutputStream patchOs = new ByteArrayOutputStream(756 * 1024); - Map patchJar = new HashMap<>(); - - for (Map.Entry file : zipFile.entrySet()) - { - byte[] gamepackBytes = file.getValue(); - byte[] injectedBytes = injectedFile.get(file.getKey()); - byte[] patchBytes; - - if (Arrays.equals(gamepackBytes, injectedBytes)) - { - continue; - } - - Diff.diff(gamepackBytes, injectedBytes, patchOs); - patchBytes = patchOs.toByteArray(); - String patchName = file.getKey() + ".bs"; - - patchJar.put(patchName, patchBytes); - patchCount++; - - patchOs.reset(); - } - - log.debug("Created patch files for {} files", patchCount); - saveJar(patchJar, PATCHFILE); - - System.exit(0); - } - - if (updateCheckMode == AUTO) - { - ByteArrayOutputStream patchOs = new ByteArrayOutputStream(756 * 1024); - int patchCount = 0; - - for (Map.Entry file : zipFile.entrySet()) - { - byte[] bytes; - try (InputStream is = ClientLoader.class.getResourceAsStream("/patch/" + file.getKey() + ".bs")) - { - if (is == null) - { - continue; - } - - bytes = ByteStreams.toByteArray(is); - } - - patchOs.reset(); - Patch.patch(file.getValue(), bytes, patchOs); - file.setValue(patchOs.toByteArray()); - - ++patchCount; - } - - log.info("Patched {} classes", patchCount); - } - if (updateCheckMode == CUSTOM) { - loadJar(zipFile, CUSTOMFILE); -//TODO: Change this URL url = new URL("https://raw.githubusercontent.com/runelite-extended/maven-repo/master/artifacts/injected-client.jar"); -//TODO: Change this ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream()); -//TODO: Change this File INJECTED_CLIENT = new File(RUNELITE_DIR+"/injected-client.jar"); -//TODO: Change this INJECTED_CLIENT.mkdirs(); -//TODO: Change this if (INJECTED_CLIENT.exists()) -// { -//TODO: Change this if (getFileSize(INJECTED_CLIENT.toURI().toURL())!= getFileSize(url)) -// { -//TODO: Change this INJECTED_CLIENT.delete(); -//TODO: Change this INJECTED_CLIENT.createNewFile(); -//TODO: Change this System.out.println("Updating Injected Client"); -//TODO: Change this updateInjectedClient(readableByteChannel); -//TODO: Change this } -//TODO: Change this } else { -//TODO: Change this INJECTED_CLIENT.createNewFile(); -//TODO: Change this System.out.println("Initializing Inject Client"); -//TODO: Change this updateInjectedClient(readableByteChannel); -//TODO: Change this } -//TODO: Change this -//TODO: Change this JarInputStream fis = new JarInputStream(new FileInputStream(INJECTED_CLIENT)); -//TODO: Change this byte[] tmp = new byte[4096]; -//TODO: Change this ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024); -//TODO: Change this for (; ; ) -//TODO: Change this { -//TODO: Change this JarEntry metadata = fis.getNextJarEntry(); -//TODO: Change this if (metadata == null) -//TODO: Change this { -//TODO: Change this break; -//TODO: Change this } -//TODO: Change this -//TODO: Change this buffer.reset(); -//TODO: Change this for (; ; ) -//TODO: Change this { -//TODO: Change this int n = fis.read(tmp); -//TODO: Change this if (n <= -1) -//TODO: Change this { -//TODO: Change this break; -//TODO: Change this } -//TODO: Change this buffer.write(tmp, 0, n); -//TODO: Change this } -//TODO: Change this zipFile.replace(metadata.getName(), buffer.toByteArray()); -// } + URL url = new URL("https://raw.githubusercontent.com/runelite-extended/maven-repo/master/artifacts/injected-client.jar"); + ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream()); + File LOCAL_INJECTED_CLIENT = new File("./injected-client/target/injected-client-"+RuneLiteAPI.getVersion()+".jar"); + File INJECTED_CLIENT = new File(RUNELITE_DIR+"/injected-client.jar"); + INJECTED_CLIENT.mkdirs(); + if (INJECTED_CLIENT.exists()) { + if (getFileSize(INJECTED_CLIENT.toURI().toURL())!= getFileSize(url)) { + INJECTED_CLIENT.delete(); + INJECTED_CLIENT.createNewFile(); + System.out.println("Updating Injected Client"); + updateInjectedClient(readableByteChannel); + } + } else { + INJECTED_CLIENT.createNewFile(); + System.out.println("Initializing Inject Client"); + updateInjectedClient(readableByteChannel); + } + JarInputStream fis; + if (useLocalInjected) { + fis = new JarInputStream(new FileInputStream(LOCAL_INJECTED_CLIENT)); + } else { + fis = new JarInputStream(new FileInputStream(INJECTED_CLIENT)); + } + byte[] tmp = new byte[4096]; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024); + for (; ; ) + { + JarEntry metadata = fis.getNextJarEntry(); + if (metadata == null) + { + break; + } + + buffer.reset(); + for (; ; ) + { + int n = fis.read(tmp); + if (n <= -1) + { + break; + } + buffer.write(tmp, 0, n); + } + zipFile.replace(metadata.getName(), buffer.toByteArray()); + } } String initialClass = config.getInitialClass(); @@ -291,15 +223,20 @@ public class ClientLoader Applet rs = (Applet) clientClass.newInstance(); rs.setStub(new RSAppletStub(config)); + if (rs instanceof Client) + { + log.info("client-patch {}", "420 blaze it RL pricks"); + } + return rs; } - catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException | SecurityException | VerificationException | CertificateException | CompressorException | InvalidHeaderException e) + catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException | SecurityException | VerificationException | CertificateException 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); @@ -307,44 +244,35 @@ public class ClientLoader } } - private static int getFileSize(URL url) - { + private static int getFileSize(URL url) { URLConnection conn = null; - try - { + try { conn = url.openConnection(); - if (conn instanceof HttpURLConnection) - { + if(conn instanceof HttpURLConnection) { ((HttpURLConnection)conn).setRequestMethod("HEAD"); } conn.getInputStream(); return conn.getContentLength(); - } - catch (IOException e) - { + } catch (IOException e) { throw new RuntimeException(e); - } - finally - { - if (conn instanceof HttpURLConnection) - { + } finally { + if(conn instanceof HttpURLConnection) { ((HttpURLConnection)conn).disconnect(); } } } - private void updateInjectedClient(ReadableByteChannel readableByteChannel) - { - File INJECTED_CLIENT = new File(RUNELITE_DIR, "injected-client.jar"); - FileOutputStream fileOutputStream; - try - { + private void updateInjectedClient(ReadableByteChannel readableByteChannel) { + File INJECTED_CLIENT = new File(RUNELITE_DIR,"injected-client.jar"); + FileOutputStream fileOutputStream = null; + try { fileOutputStream = new FileOutputStream(INJECTED_CLIENT); + FileChannel fileChannel = fileOutputStream.getChannel(); fileOutputStream.getChannel() .transferFrom(readableByteChannel, 0, Long.MAX_VALUE); - } - catch (IOException e) - { + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { e.printStackTrace(); } } @@ -355,48 +283,4 @@ public class ClientLoader Collection certificates = certificateFactory.generateCertificates(ClientLoader.class.getResourceAsStream("jagex.crt")); return certificates.toArray(new Certificate[0]); } - - private static void saveJar(Map fileMap, File toFile) throws IOException - { - try (JarOutputStream jout = new JarOutputStream(new FileOutputStream(toFile), new Manifest())) - { - for (Map.Entry entry : fileMap.entrySet()) - { - JarEntry e = new JarEntry(entry.getKey()); - jout.putNextEntry(e); - - byte[] data = entry.getValue(); - - jout.write(data); - jout.closeEntry(); - } - } - } - - private static void loadJar(Map toMap, File fromFile) throws IOException - { - JarInputStream fis = new JarInputStream(new FileInputStream(fromFile)); - byte[] tmp = new byte[4096]; - ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024); - for (; ; ) - { - JarEntry metadata = fis.getNextJarEntry(); - if (metadata == null) - { - break; - } - - buffer.reset(); - for (; ; ) - { - int n = fis.read(tmp); - if (n <= -1) - { - break; - } - buffer.write(tmp, 0, n); - } - toMap.put(metadata.getName(), buffer.toByteArray()); - } - } }