Files
runelite/runelite-client/src/main/java/net/runelite/client/RuneLite.java
2019-11-08 00:39:09 +01:00

409 lines
12 KiB
Java

/*
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
* 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;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
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 io.sentry.Sentry;
import io.sentry.SentryClient;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.util.Locale;
import javax.annotation.Nullable;
import javax.inject.Provider;
import javax.inject.Singleton;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.util.EnumConverter;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.events.GameStateChanged;
import net.runelite.client.account.SessionManager;
import net.runelite.client.callback.Hooks;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.chat.CommandManager;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.discord.DiscordService;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.game.ClanManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.LootManager;
import net.runelite.client.game.XpDropManager;
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;
import net.runelite.client.ui.RuneLiteSplashScreen;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.OverlayRenderer;
import net.runelite.client.ui.overlay.WidgetOverlay;
import net.runelite.client.ui.overlay.arrow.ArrowMinimapOverlay;
import net.runelite.client.ui.overlay.arrow.ArrowWorldOverlay;
import net.runelite.client.ui.overlay.infobox.InfoBoxOverlay;
import net.runelite.client.ui.overlay.tooltip.TooltipOverlay;
import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay;
import org.slf4j.LoggerFactory;
@Singleton
@Slf4j
public class RuneLite
{
public static final File RUNELITE_DIR = new File(System.getProperty("user.home"), ".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");
public static final File LOGS_DIR = new File(RUNELITE_DIR, "logs");
public static final Locale SYSTEM_LOCALE = Locale.getDefault();
public static boolean allowPrivateServer = false;
@Getter
private static Injector injector;
@Inject
private PluginManager pluginManager;
@Inject
private ConfigManager configManager;
@Inject
private SessionManager sessionManager;
@Inject
public DiscordService discordService;
@Inject
private ClientSessionManager clientSessionManager;
@Inject
private ClientUI clientUI;
@Inject
private OverlayManager overlayManager;
@Inject
private Provider<ItemManager> itemManager;
@Inject
private Provider<OverlayRenderer> overlayRenderer;
@Inject
private Provider<ClanManager> clanManager;
@Inject
private Provider<ChatMessageManager> chatMessageManager;
@Inject
private Provider<MenuManager> menuManager;
@Inject
private Provider<CommandManager> commandManager;
@Inject
private Provider<InfoBoxOverlay> infoBoxOverlay;
@Inject
private Provider<TooltipOverlay> tooltipOverlay;
@Inject
private Provider<WorldMapOverlay> worldMapOverlay;
@Inject
private Provider<ArrowWorldOverlay> arrowWorldOverlay;
@Inject
private Provider<ArrowMinimapOverlay> arrowMinimapOverlay;
@Inject
private Provider<LootManager> lootManager;
@Inject
private Provider<XpDropManager> xpDropManager;
@Inject
private Provider<ChatboxPanelManager> chatboxPanelManager;
@Inject
private Hooks hooks;
@Inject
private EventBus eventBus;
@Inject
@Nullable
private Client client;
@Inject
private Provider<ModelOutlineRenderer> modelOutlineRenderer;
@Inject
private Scheduler scheduler;
public static void main(String[] args) throws Exception
{
Locale.setDefault(Locale.ENGLISH);
final OptionParser parser = new OptionParser();
parser.accepts("developer-mode", "Enable developer tools");
parser.accepts("debug", "Show extra debugging output");
parser.accepts("no-splash", "Do not show the splash screen");
final ArgumentAcceptingOptionSpec<String> proxyInfo = parser
.accepts("proxy")
.withRequiredArg().ofType(String.class);
final ArgumentAcceptingOptionSpec<ClientUpdateCheckMode> updateMode = parser
.accepts("rs", "Select client type")
.withRequiredArg()
.ofType(ClientUpdateCheckMode.class)
.defaultsTo(ClientUpdateCheckMode.AUTO)
.withValuesConvertedBy(new EnumConverter<ClientUpdateCheckMode>(ClientUpdateCheckMode.class)
{
@Override
public ClientUpdateCheckMode convert(String v)
{
return super.convert(v.toUpperCase());
}
});
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("proxy"))
{
String[] proxy = options.valueOf(proxyInfo).split(":");
if (proxy.length >= 2)
{
System.setProperty("socksProxyHost", proxy[0]);
System.setProperty("socksProxyPort", proxy[1]);
}
if (proxy.length >= 4)
{
System.setProperty("java.net.socks.username", proxy[2]);
System.setProperty("java.net.socks.password", proxy[3]);
final String user = proxy[2];
final char[] pass = proxy[3].toCharArray();
Authenticator.setDefault(new Authenticator()
{
private PasswordAuthentication auth = new PasswordAuthentication(user, pass);
protected PasswordAuthentication getPasswordAuthentication()
{
return auth;
}
});
}
}
SentryClient client = Sentry.init("https://fa31d674e44247fa93966c69a903770f@sentry.io/1811856");
client.setRelease(RuneLiteProperties.getPlusVersion());
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"))
{
RuneLiteSplashScreen.init();
}
final boolean developerMode = options.has("developer-mode");
if (developerMode)
{
boolean assertions = false;
assert assertions = true;
if (!assertions)
{
log.warn("Developers should enable assertions; Add `-ea` to your JVM arguments`");
}
}
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.");
return;
}
RuneLiteSplashScreen.setError("Error while loading!", "Please check your internet connection and your DNS settings.");
});
RuneLiteSplashScreen.stage(0, "Starting OpenOSRS injector");
PROFILES_DIR.mkdirs();
final long start = System.currentTimeMillis();
injector = Guice.createInjector(new RuneLiteModule(
clientLoader,
true));
injector.getInstance(RuneLite.class).start();
final long end = System.currentTimeMillis();
final RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
final long uptime = rb.getUptime();
log.info("Client initialization took {}ms. Uptime: {}ms", end - start, uptime);
}
public void start() throws Exception
{
// Load RuneLite or Vanilla client
final boolean isOutdated = client == null;
if (!isOutdated)
{
// Inject members into client
injector.injectMembers(client);
}
// Load user configuration
RuneLiteSplashScreen.stage(.57, "Loading user config");
configManager.load();
// Load the session, including saved configuration
RuneLiteSplashScreen.stage(.58, "Loading session data");
sessionManager.loadSession();
// Tell the plugin manager if client is outdated or not
pluginManager.setOutdated(isOutdated);
// Load external plugins
pluginManager.loadExternalPlugins();
// Load the plugins, but does not start them yet.
// This will initialize configuration
pluginManager.loadCorePlugins();
RuneLiteSplashScreen.stage(.70, "Finalizing configuration");
// Plugins have provided their config, so set default config
// to main settings
pluginManager.loadDefaultPluginConfiguration();
// Start client session
RuneLiteSplashScreen.stage(.75, "Starting core interface");
clientSessionManager.start();
// Initialize UI
RuneLiteSplashScreen.stage(.80, "Initialize UI");
clientUI.init(this);
// Initialize Discord service
discordService.init();
if (!isOutdated)
{
// Initialize chat colors
chatMessageManager.get().loadColors();
overlayRenderer.get();
clanManager.get();
itemManager.get();
menuManager.get();
chatMessageManager.get();
commandManager.get();
lootManager.get();
xpDropManager.get();
chatboxPanelManager.get();
eventBus.subscribe(GameStateChanged.class, this, hooks::onGameStateChanged);
// Add core overlays
WidgetOverlay.createOverlays(client).forEach(overlayManager::add);
overlayManager.add(infoBoxOverlay.get());
overlayManager.add(worldMapOverlay.get());
overlayManager.add(tooltipOverlay.get());
overlayManager.add(arrowWorldOverlay.get());
overlayManager.add(arrowMinimapOverlay.get());
}
// Start plugins
pluginManager.startCorePlugins();
// Register additional schedulers
if (this.client != null)
{
scheduler.registerObject(modelOutlineRenderer.get());
scheduler.registerObject(clientSessionManager);
}
// Close the splash screen
RuneLiteSplashScreen.close();
clientUI.show();
}
public void shutdown()
{
configManager.sendConfig();
clientSessionManager.shutdown();
discordService.close();
}
@VisibleForTesting
public static void setInjector(Injector injector)
{
RuneLite.injector = injector;
}
}