diff --git a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java index 1f8ae40ac2..dbcceda631 100644 --- a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java +++ b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java @@ -84,9 +84,8 @@ public class RuneLiteAPI static { - try + try (InputStream in = RuneLiteAPI.class.getResourceAsStream("/runelite.properties")) { - InputStream in = RuneLiteAPI.class.getResourceAsStream("/runelite.properties"); properties.load(in); version = properties.getProperty("runelite.version"); diff --git a/runelite-client/src/main/java/net/runelite/client/ClientSessionManager.java b/runelite-client/src/main/java/net/runelite/client/ClientSessionManager.java index 2ec1b0e6e5..3cbea08ba0 100644 --- a/runelite-client/src/main/java/net/runelite/client/ClientSessionManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ClientSessionManager.java @@ -69,7 +69,7 @@ public class ClientSessionManager sessionClient.pingSession(sessionId) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.from(clientThread)) - .doOnError(e -> this.error((Throwable) e)) + .doOnError(this::error) .subscribe(); } @@ -80,7 +80,7 @@ public class ClientSessionManager sessionClient.delete(sessionId) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.from(clientThread)) - .doOnError(e -> this.error((Throwable) e)) + .doOnError(this::error) .subscribe(); sessionId = null; 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 91e6a2de93..10fe6cc739 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -30,6 +30,8 @@ import com.google.common.annotations.VisibleForTesting; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; +import io.reactivex.Completable; +import io.reactivex.schedulers.Schedulers; import java.io.File; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; @@ -61,6 +63,7 @@ import net.runelite.client.game.chatbox.ChatboxPanelManager; import net.runelite.client.graphics.ModelOutlineRenderer; import net.runelite.client.menus.MenuManager; 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; @@ -85,8 +88,8 @@ public class RuneLite public static final File PLUGIN_DIR = new File(RUNELITE_DIR, "plugins"); public static final File SCREENSHOT_DIR = new File(RUNELITE_DIR, "screenshots"); public static final File LOGS_DIR = new File(RUNELITE_DIR, "logs"); - public static boolean allowPrivateServer = false; public static final Locale SYSTEM_LOCALE = Locale.getDefault(); + public static boolean allowPrivateServer = false; @Getter private static Injector injector; @@ -198,16 +201,30 @@ public class RuneLite parser.accepts("help", "Show this text").forHelp(); OptionSet options = parser.parse(args); + if (options.has("help")) + { + parser.printHelpOn(System.out); + System.exit(0); + } + + if (options.has("debug")) + { + final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + logger.setLevel(Level.DEBUG); + } + if (options.has("bootstrap")) { Bootstrapper.main(false); System.exit(0); } + if (options.has("bootstrap-staging")) { Bootstrapper.main(true); System.exit(0); } + if (options.has("proxy")) { String[] proxy = options.valueOf(proxyInfo).split(":"); @@ -238,10 +255,18 @@ public class RuneLite } } - if (options.has("help")) + final ClientLoader clientLoader = new ClientLoader(options.valueOf(updateMode)); + Completable.fromAction(clientLoader::get) + .subscribeOn(Schedulers.single()) + .subscribe(); + + Completable.fromAction(ClassPreloader::preload) + .subscribeOn(Schedulers.computation()) + .subscribe(); + + if (!options.has("no-splash")) { - parser.printHelpOn(System.out); - System.exit(0); + RuneLiteSplashScreen.init(); } final boolean developerMode = options.has("developer-mode"); @@ -252,27 +277,13 @@ public class RuneLite assert assertions = true; if (!assertions) { - java.util.logging.Logger.getAnonymousLogger().warning("Developers should enable assertions; Add `-ea` to your JVM arguments`"); + log.warn("Developers should enable assertions; Add `-ea` to your JVM arguments`"); } } - if (!options.has("no-splash")) - { - RuneLiteSplashScreen.init(); - } - - RuneLiteSplashScreen.stage(0, "Initializing client"); - - PROFILES_DIR.mkdirs(); - - if (options.has("debug")) - { - final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); - logger.setLevel(Level.DEBUG); - } - Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { + log.error("Uncaught exception:", throwable); if (throwable instanceof AbstractMethodError) { RuneLiteSplashScreen.setError("Out of date!", "Classes are out of date; Build with Gradle again."); @@ -284,13 +295,16 @@ public class RuneLite RuneLiteSplashScreen.stage(0, "Starting OpenOSRS injector"); + PROFILES_DIR.mkdirs(); + final long start = System.currentTimeMillis(); injector = Guice.createInjector(new RuneLiteModule( - options.valueOf(updateMode), + clientLoader, true)); injector.getInstance(RuneLite.class).start(); + final long end = System.currentTimeMillis(); final RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean(); final long uptime = rb.getUptime(); diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java index 2d3b2d95bd..4b6fe543ab 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java @@ -31,6 +31,7 @@ import java.applet.Applet; import java.io.File; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Supplier; import javax.annotation.Nullable; import javax.inject.Singleton; import net.runelite.api.Client; @@ -46,8 +47,6 @@ import net.runelite.client.eventbus.EventBus; import net.runelite.client.game.ItemManager; import net.runelite.client.menus.MenuManager; 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.util.DeferredEventBus; import net.runelite.client.util.ExecutorServiceExceptionLogger; @@ -61,19 +60,18 @@ public class RuneLiteModule extends AbstractModule { private static final int MAX_OKHTTP_CACHE_SIZE = 20 * 1024 * 1024; // 20mb - private final ClientUpdateCheckMode updateCheckMode; + private final Supplier clientLoader; private final boolean developerMode; - public RuneLiteModule(final ClientUpdateCheckMode updateCheckMode, final boolean developerMode) + public RuneLiteModule(final Supplier clientLoader, boolean developerMode) { - this.updateCheckMode = updateCheckMode; + this.clientLoader = clientLoader; this.developerMode = developerMode; } @Override protected void configure() { - bindConstant().annotatedWith(Names.named("updateCheckMode")).to(updateCheckMode); bindConstant().annotatedWith(Names.named("developerMode")).to(developerMode); bind(ScheduledExecutorService.class).toInstance(new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor())); bind(OkHttpClient.class).toInstance(RuneLiteAPI.CLIENT.newBuilder() @@ -102,9 +100,9 @@ public class RuneLiteModule extends AbstractModule @Provides @Singleton - Applet provideApplet(ClientLoader clientLoader) + Applet provideApplet() { - return clientLoader.load(); + return clientLoader.get(); } @Provides diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java index daee89d689..78e5fc33d8 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java @@ -24,12 +24,10 @@ */ package net.runelite.client; -import com.google.inject.Singleton; import java.io.IOException; import java.io.InputStream; import java.util.Properties; -@Singleton public class RuneLiteProperties { private static final String RUNELITE_TITLE = "open.osrs.title"; diff --git a/runelite-client/src/main/java/net/runelite/client/SessionClient.java b/runelite-client/src/main/java/net/runelite/client/SessionClient.java index ce1b3575aa..cea45555bb 100644 --- a/runelite-client/src/main/java/net/runelite/client/SessionClient.java +++ b/runelite-client/src/main/java/net/runelite/client/SessionClient.java @@ -24,7 +24,9 @@ */ package net.runelite.client; +import io.reactivex.Completable; import io.reactivex.Observable; +import java.io.IOException; import java.util.UUID; import net.runelite.http.api.RuneLiteAPI; import okhttp3.HttpUrl; @@ -50,34 +52,36 @@ class SessionClient }); } - Observable pingSession(UUID uuid) + Completable pingSession(UUID uuid) { final HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder() .addPathSegment("ping") .addQueryParameter("session", uuid.toString()) .build(); - return Observable.defer(() -> + return Completable.fromAction(() -> { Request request = new Request.Builder() .url(url) .build(); - try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) { - return Observable.empty(); + if (!response.isSuccessful()) + { + throw new IOException("Unsuccesful ping"); + } } }); } - Observable delete(UUID uuid) + Completable delete(UUID uuid) { final HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder() .addQueryParameter("session", uuid.toString()) .build(); - return Observable.defer(() -> + return Completable.fromAction(() -> { Request request = new Request.Builder() .delete() @@ -85,7 +89,6 @@ class SessionClient .build(); RuneLiteAPI.CLIENT.newCall(request).execute().close(); - return Observable.empty(); }); } } diff --git a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java index ce202b1040..9e13a0bebd 100644 --- a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java +++ b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java @@ -52,10 +52,26 @@ public class EventBus implements EventBusInterface Disposable disposable = getSubject(eventClass) .filter(Objects::nonNull) // Filter out null objects, better safe than sorry .cast(eventClass) // Cast it for easier usage - .subscribe(action, error -> - { - log.error("Error in eventbus", error); - }); + .subscribe(action, error -> log.error("Error in eventbus", error)); + + getCompositeDisposable(lifecycle).add(disposable); + subscriptionList.put(lifecycle, eventClass); + } + + @Override + public void subscribe(Class eventClass, @NonNull Object lifecycle, @NonNull Consumer action, int takeUntil) + { + if (subscriptionList.containsKey(lifecycle) && eventClass.equals(subscriptionList.get(lifecycle))) + { + return; + } + + Disposable disposable = getSubject(eventClass) + .filter(Objects::nonNull) // Filter out null objects, better safe than sorry + .cast(eventClass) // Cast it for easier usage + .take(takeUntil) + .doFinally(() -> unregister(lifecycle)) + .subscribe(action, error -> log.error("Error in eventbus", error)); getCompositeDisposable(lifecycle).add(disposable); subscriptionList.put(lifecycle, eventClass); diff --git a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBusInterface.java b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBusInterface.java index ef75ac265a..d18072891f 100644 --- a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBusInterface.java +++ b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBusInterface.java @@ -8,6 +8,8 @@ public interface EventBusInterface { void subscribe(Class eventClass, @NonNull Object lifecycle, @NonNull Consumer action); + void subscribe(Class eventClass, @NonNull Object lifecycle, @NonNull Consumer action, int takeUntil); + void unregister(@NonNull Object lifecycle); void post(Class eventClass, @NonNull Event event); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java index 874c1fbb3b..79323c9290 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java @@ -28,11 +28,11 @@ package net.runelite.client.plugins.grandexchange; import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; +import com.google.gson.stream.JsonReader; import com.google.inject.Provides; import io.reactivex.schedulers.Schedulers; import java.awt.image.BufferedImage; -import java.io.InputStream; +import java.io.IOException; import java.io.InputStreamReader; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; @@ -85,6 +85,7 @@ import net.runelite.client.ui.NavigationButton; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.StackFormatter; import net.runelite.api.util.Text; +import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.ge.GrandExchangeClient; import net.runelite.http.api.ge.GrandExchangeTrade; import net.runelite.http.api.osbuddy.OSBGrandExchangeClient; @@ -107,7 +108,6 @@ public class GrandExchangePlugin extends Plugin private static final OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient(); private static final String OSB_GE_TEXT = "
OSBuddy Actively traded price: "; private static final String BUY_LIMIT_GE_TEXT = "
Buy limit: "; - private static final Gson GSON = new Gson(); private static final TypeToken> BUY_LIMIT_TOKEN = new TypeToken>() { }; @@ -173,12 +173,14 @@ public class GrandExchangePlugin extends Plugin private boolean enableGELimits; private boolean enableAfford; - private static Map loadGELimits() + private static Map loadGELimits() throws IOException { - final InputStream geLimitData = GrandExchangePlugin.class.getResourceAsStream("ge_limits.json"); - final Map itemGELimits = GSON.fromJson(new InputStreamReader(geLimitData), BUY_LIMIT_TOKEN.getType()); - log.debug("Loaded {} limits", itemGELimits.size()); - return itemGELimits; + try (final JsonReader geLimitData = new JsonReader(new InputStreamReader(GrandExchangePlugin.class.getResourceAsStream("ge_limits.json")))) + { + final Map itemGELimits = RuneLiteAPI.GSON.fromJson(geLimitData, BUY_LIMIT_TOKEN.getType()); + log.debug("Loaded {} limits", itemGELimits.size()); + return itemGELimits; + } } private SavedOffer getOffer(int slot) @@ -188,12 +190,12 @@ public class GrandExchangePlugin extends Plugin { return null; } - return GSON.fromJson(offer, SavedOffer.class); + return RuneLiteAPI.GSON.fromJson(offer, SavedOffer.class); } private void setOffer(int slot, SavedOffer offer) { - configManager.setConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot), GSON.toJson(offer)); + configManager.setConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot), RuneLiteAPI.GSON.toJson(offer)); } private void deleteOffer(int slot) @@ -208,7 +210,7 @@ public class GrandExchangePlugin extends Plugin } @Override - protected void startUp() + protected void startUp() throws Exception { updateConfig(); addSubscriptions(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerXpDropLookup.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerXpDropLookup.java index 458c9421c2..25dfef058c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerXpDropLookup.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerXpDropLookup.java @@ -26,6 +26,7 @@ package net.runelite.client.plugins.slayer; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; @@ -38,14 +39,15 @@ class SlayerXpDropLookup // floating point math equality private static final double EPSILON = 1e-6; - private void loadXpJson() + private void loadXpJson() throws IOException { - final InputStream xpFile = getClass().getResourceAsStream("/slayer_xp.json"); - Gson gson = new Gson(); - xpMap = gson.fromJson(new InputStreamReader(xpFile), new TypeToken>>() + try (final InputStream xpFile = getClass().getResourceAsStream("/slayer_xp.json")) { - - }.getType()); + Gson gson = new Gson(); + xpMap = gson.fromJson(new InputStreamReader(xpFile), new TypeToken>>() + { + }.getType()); + } } /** @@ -129,6 +131,13 @@ class SlayerXpDropLookup SlayerXpDropLookup() { - loadXpJson(); + try + { + loadXpJson(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java index a8230a4e32..704b145fdc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java @@ -43,7 +43,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.inject.Singleton; import javax.swing.SwingUtilities; @@ -84,6 +83,7 @@ import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.util.ExecutorServiceExceptionLogger; import net.runelite.client.util.HotkeyListener; import net.runelite.api.util.Text; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.WorldUtil; import net.runelite.client.util.ping.Ping; import net.runelite.http.api.worlds.World; @@ -215,11 +215,7 @@ public class WorldHopperPlugin extends Plugin panel = new WorldSwitcherPanel(this); - final BufferedImage icon; - synchronized (ImageIO.class) - { - icon = ImageIO.read(getClass().getResourceAsStream("icon.png")); - } + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(WorldHopperPlugin.class, "icon.png"); navButton = NavigationButton.builder() .tooltip("World Switcher") diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java index 1f96828d6b..56b1079678 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java @@ -25,68 +25,92 @@ */ package net.runelite.client.rs; +import io.reactivex.Single; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import net.runelite.http.api.RuneLiteAPI; +import okhttp3.HttpUrl; import okhttp3.Request; import okhttp3.Response; class ClientConfigLoader { - public ClientConfigLoader() + private ClientConfigLoader() { + throw new RuntimeException(); } private static final String CONFIG_URL = "http://oldschool.runescape.com/jav_config.ws"; + private static final int MAX_ATTEMPTS = 16; - static RSConfig fetch() throws IOException + static Single fetch() { - final Request request = new Request.Builder() - .url(CONFIG_URL) - .build(); - - final RSConfig config = new RSConfig(); - - try (final Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) + return Single.create(obs -> { - if (!response.isSuccessful()) + int attempt = 0; + + HostSupplier supplier = null; + HttpUrl url = HttpUrl.parse(CONFIG_URL); + + final RSConfig config = new RSConfig(); + + while (attempt++ < MAX_ATTEMPTS) { - throw new IOException("Unsuccessful response: " + response.message()); - } + final Request request = new Request.Builder() + .url(url) + .build(); - String str; - final BufferedReader in = new BufferedReader(new InputStreamReader(response.body().byteStream())); - while ((str = in.readLine()) != null) - { - int idx = str.indexOf('='); - - if (idx == -1) + try (final Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) { - continue; - } + if (!response.isSuccessful()) + { + if (supplier == null) + { + supplier = new HostSupplier(); + } - String s = str.substring(0, idx); + url = supplier.get(); + continue; + } - switch (s) - { - case "param": - str = str.substring(idx + 1); - idx = str.indexOf('='); - s = str.substring(0, idx); + String str; + final BufferedReader in = new BufferedReader(new InputStreamReader(response.body().byteStream())); + while ((str = in.readLine()) != null) + { + int idx = str.indexOf('='); - config.getAppletProperties().put(s, str.substring(idx + 1)); - break; - case "msg": - // ignore - break; - default: - config.getClassLoaderProperties().put(s, str.substring(idx + 1)); - break; + if (idx == -1) + { + continue; + } + + String s = str.substring(0, idx); + + switch (s) + { + case "param": + str = str.substring(idx + 1); + idx = str.indexOf('='); + s = str.substring(0, idx); + + config.getAppletProperties().put(s, str.substring(idx + 1)); + break; + case "msg": + // ignore + break; + default: + config.getClassLoaderProperties().put(s, str.substring(idx + 1)); + break; + } + } + + obs.onSuccess(config); + return; } } - } - return config; + obs.onError(new IOException("Too many attempts")); + }); } } 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 86c70afac9..4be5803fd0 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 @@ -32,32 +32,44 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; +import java.util.function.Supplier; import lombok.extern.slf4j.Slf4j; import net.runelite.client.RuneLite; import net.runelite.client.ui.RuneLiteSplashScreen; @Slf4j -@Singleton -public class ClientLoader +public class ClientLoader implements Supplier { - private final ClientUpdateCheckMode updateCheckMode; + private ClientUpdateCheckMode updateCheckMode; + private Object client = null; - @Inject - private ClientLoader( - @Named("updateCheckMode") final ClientUpdateCheckMode updateCheckMode) + public ClientLoader(ClientUpdateCheckMode updateCheckMode) { this.updateCheckMode = updateCheckMode; } - public Applet load() + @Override + public synchronized Applet get() + { + if (client == null) + { + client = doLoad(); + } + + if (client instanceof Throwable) + { + throw new RuntimeException((Throwable) client); + } + return (Applet) client; + } + + private Object doLoad() { try { RuneLiteSplashScreen.stage(.2, "Fetching applet viewer config"); - final RSConfig config = ClientConfigLoader.fetch(); + + final RSConfig config = ClientConfigLoader.fetch().blockingGet(); switch (updateCheckMode) { @@ -92,7 +104,7 @@ public class ClientLoader private static Applet loadRLPlus(final RSConfig config) throws ClassNotFoundException, InstantiationException, IllegalAccessException { - RuneLiteSplashScreen.stage(.465, "Starting Old School RuneScape"); + RuneLiteSplashScreen.stage(.465, "Starting Open Old School RuneScape"); ClassLoader rsClassLoader = new ClassLoader(ClientLoader.class.getClassLoader()) { @@ -126,7 +138,7 @@ public class ClientLoader private static Applet loadVanilla(final RSConfig config) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { - RuneLiteSplashScreen.stage(.465, "Starting Old School RuneScape"); + RuneLiteSplashScreen.stage(.465, "Starting Vanilla Old School RuneScape"); final String codebase = config.getCodeBase(); final String initialJar = config.getInitialJar(); diff --git a/runelite-client/src/main/java/net/runelite/client/rs/HostSupplier.java b/runelite-client/src/main/java/net/runelite/client/rs/HostSupplier.java new file mode 100644 index 0000000000..502e72c2c9 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/rs/HostSupplier.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 Abex + * Copyright (c) 2019, Lucas + * 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; + +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.List; +import java.util.Queue; +import java.util.Random; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.worlds.World; +import net.runelite.http.api.worlds.WorldClient; +import net.runelite.http.api.worlds.WorldResult; +import okhttp3.HttpUrl; + +@Slf4j +class HostSupplier implements Supplier +{ + private final Random random = new Random(); + private Queue hosts = new ArrayDeque<>(); + + @Override + public HttpUrl get() + { + if (!hosts.isEmpty()) + { + return hosts.poll(); + } + + List newHosts = new WorldClient(RuneLiteAPI.CLIENT) + .lookupWorlds() + .map(WorldResult::getWorlds) + .blockingSingle() + .stream() + .map(World::getAddress) + .map(HttpUrl::parse) + .collect(Collectors.toList()); + + Collections.shuffle(newHosts, random); + + hosts.addAll(newHosts.subList(0, 16)); + + while (hosts.size() < 2) + { + hosts.add(HttpUrl.parse("oldschool" + (random.nextInt(50) + 1) + ".runescape.COM")); + } + + return hosts.poll(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientPanel.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientPanel.java index 39e2448a89..657d61f508 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientPanel.java @@ -38,7 +38,7 @@ import net.runelite.client.util.StringFileUtils; final class ClientPanel extends JPanel { - public ClientPanel(@Nullable Applet client) + ClientPanel(@Nullable Applet client) { setSize(Constants.GAME_FIXED_SIZE); setMinimumSize(Constants.GAME_FIXED_SIZE); @@ -71,7 +71,7 @@ final class ClientPanel extends JPanel add(client, BorderLayout.CENTER); - // api.renderableThis causes the whole game frame to be redrawn each frame instead + // This causes the whole game frame to be redrawn each frame instead // of only the viewport, so we can hook to MainBufferProvider#draw // and draw anywhere without it leaving artifacts if (client instanceof Client) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java index 1fa67ec575..609a02b757 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java @@ -114,8 +114,8 @@ public class ClientUI private static final String CONFIG_OPACITY_AMOUNT = "opacityPercentage"; private static final int CLIENT_WELL_HIDDEN_MARGIN = 160; private static final int CLIENT_WELL_HIDDEN_MARGIN_TOP = 10; - public static boolean allowInput = false; public static final BufferedImage ICON = ImageUtil.getResourceStreamFromClass(ClientUI.class, "/openosrs.png"); + public static boolean allowInput = false; @Getter private TrayIcon trayIcon; diff --git a/runelite-client/src/main/java/net/runelite/client/ui/FontManager.java b/runelite-client/src/main/java/net/runelite/client/ui/FontManager.java index 5f703bb002..54497b6de9 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/FontManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/FontManager.java @@ -28,6 +28,7 @@ import java.awt.Font; import java.awt.FontFormatException; import java.awt.GraphicsEnvironment; import java.io.IOException; +import java.io.InputStream; import javax.swing.text.StyleContext; public class FontManager @@ -42,31 +43,42 @@ public class FontManager try { - Font font = Font.createFont(Font.TRUETYPE_FONT, - FontManager.class.getResourceAsStream("runescape.ttf")) - .deriveFont(Font.PLAIN, 16); - ge.registerFont(font); + Font font; + + try (InputStream runescapeIn = FontManager.class.getResourceAsStream("runescape.ttf")) + { + font = Font.createFont(Font.TRUETYPE_FONT, + runescapeIn) + .deriveFont(Font.PLAIN, 16); + ge.registerFont(font); + } runescapeFont = StyleContext.getDefaultStyleContext() .getFont(font.getName(), Font.PLAIN, 16); ge.registerFont(runescapeFont); - Font smallFont = Font.createFont(Font.TRUETYPE_FONT, - FontManager.class.getResourceAsStream("runescape_small.ttf")) - .deriveFont(Font.PLAIN, 16); - ge.registerFont(smallFont); + try (InputStream smallIn = FontManager.class.getResourceAsStream("runescape_small.ttf")) + { + font = Font.createFont(Font.TRUETYPE_FONT, + smallIn) + .deriveFont(Font.PLAIN, 16); + ge.registerFont(font); + } runescapeSmallFont = StyleContext.getDefaultStyleContext() - .getFont(smallFont.getName(), Font.PLAIN, 16); + .getFont(font.getName(), Font.PLAIN, 16); ge.registerFont(runescapeSmallFont); - Font boldFont = Font.createFont(Font.TRUETYPE_FONT, - FontManager.class.getResourceAsStream("runescape_bold.ttf")) - .deriveFont(Font.PLAIN, 16); - ge.registerFont(boldFont); + try (InputStream boldIn = FontManager.class.getResourceAsStream("runescape_bold.ttf")) + { + font = Font.createFont(Font.TRUETYPE_FONT, + boldIn) + .deriveFont(Font.PLAIN, 16); + ge.registerFont(font); + } runescapeBoldFont = StyleContext.getDefaultStyleContext() - .getFont(boldFont.getName(), Font.PLAIN, 16); + .getFont(font.getName(), Font.PLAIN, 16); ge.registerFont(runescapeBoldFont); } catch (FontFormatException ex) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/RuneLiteSplashScreen.java b/runelite-client/src/main/java/net/runelite/client/ui/RuneLiteSplashScreen.java index b64fb2355f..cd16bc6f2b 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/RuneLiteSplashScreen.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/RuneLiteSplashScreen.java @@ -26,7 +26,6 @@ package net.runelite.client.ui; import java.awt.BorderLayout; import java.awt.Dimension; -import java.lang.reflect.InvocationTargetException; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JProgressBar; @@ -35,7 +34,6 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.client.ui.components.InfoPanel; import net.runelite.client.ui.components.MessagePanel; -import net.runelite.client.util.ImageUtil; @Slf4j public class RuneLiteSplashScreen extends JFrame @@ -53,7 +51,7 @@ public class RuneLiteSplashScreen extends JFrame this.setSize(FRAME_SIZE); this.setLayout(new BorderLayout()); this.setUndecorated(true); - this.setIconImage(ImageUtil.getResourceStreamFromClass(RuneLiteSplashScreen.class, "/openosrs.png")); + this.setIconImage(ClientUI.ICON); final JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); @@ -112,29 +110,17 @@ public class RuneLiteSplashScreen extends JFrame public static void init() { - try + SwingUtilities.invokeLater(() -> { - SwingUtilities.invokeAndWait(() -> + try { - if (INSTANCE != null) - { - return; - } - - try - { - INSTANCE = new RuneLiteSplashScreen(); - } - catch (Exception e) - { - log.warn("Unable to start splash screen", e); - } - }); - } - catch (InterruptedException | InvocationTargetException bs) - { - throw new RuntimeException(bs); - } + INSTANCE = new RuneLiteSplashScreen(); + } + catch (Exception e) + { + log.warn("Unable to start splash screen", e); + } + }); } public static void close() diff --git a/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java b/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java index a4de492f3d..8c581b2301 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java @@ -36,6 +36,7 @@ import java.awt.image.PixelGrabber; import java.awt.image.RescaleOp; import java.awt.image.WritableRaster; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -361,7 +362,10 @@ public class ImageUtil { synchronized (ImageIO.class) { - return ImageIO.read(c.getResourceAsStream(path)); + try (InputStream in = c.getResourceAsStream(path)) + { + return ImageIO.read(in); + } } } catch (IOException e) diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java index 505a41ec11..42df2955c0 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java @@ -57,8 +57,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import net.runelite.client.rs.ClientUpdateCheckMode; +import org.mockito.runners.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class PluginManagerTest @@ -83,7 +82,7 @@ public class PluginManagerTest public void before() throws IOException { Injector injector = Guice.createInjector(Modules - .override(new RuneLiteModule(ClientUpdateCheckMode.NONE, true)) + .override(new RuneLiteModule(() -> null, true)) .with(BoundFieldModule.of(this))); RuneLite.setInjector(injector); @@ -141,7 +140,7 @@ public class PluginManagerTest { List modules = new ArrayList<>(); modules.add(new GraphvizModule()); - modules.add(new RuneLiteModule(ClientUpdateCheckMode.NONE, true)); + modules.add(new RuneLiteModule(() -> null, true)); PluginManager pluginManager = new PluginManager(true, null, null, null, null, null); pluginManager.loadCorePlugins(); diff --git a/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java b/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java index beb3400927..3955f4a101 100644 --- a/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java +++ b/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java @@ -25,7 +25,6 @@ package net.runelite.client.rs; -import java.io.IOException; import org.junit.Test; /** @@ -35,9 +34,9 @@ import org.junit.Test; public class ClientConfigLoaderTest { @Test - public void test() throws IOException + public void test() { - final RSConfig config = ClientConfigLoader.fetch(); + final RSConfig config = ClientConfigLoader.fetch().blockingGet(); for (String key : config.getClassLoaderProperties().keySet()) {