openrune: reset to upstream client bare

This commit is contained in:
therealunull
2020-12-13 12:42:33 -05:00
parent 9a257666be
commit 98d2a16798
265 changed files with 7149 additions and 23792 deletions

View File

@@ -24,88 +24,114 @@
*/
package net.runelite.client;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.time.temporal.ChronoUnit;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.eventbus.EventBus;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ClientShutdown;
import net.runelite.client.task.Schedule;
import net.runelite.client.util.RunnableExceptionLogger;
import okhttp3.OkHttpClient;
@Singleton
@Slf4j
public class ClientSessionManager
{
private final ScheduledExecutorService executorService;
private final Client client;
private final SessionClient sessionClient;
private ScheduledFuture<?> scheduledFuture;
private UUID sessionId;
@Inject
ClientSessionManager(EventBus eventBus,
ClientSessionManager(ScheduledExecutorService executorService,
@Nullable Client client,
OkHttpClient okHttpClient)
{
this.executorService = executorService;
this.client = client;
this.sessionClient = new SessionClient(okHttpClient);
}
eventBus.subscribe(ClientShutdown.class, this, (e) ->
public void start()
{
try
{
Future<Void> f = shutdown();
if (f != null)
sessionId = sessionClient.open();
log.debug("Opened session {}", sessionId);
}
catch (IOException ex)
{
log.warn("error opening session", ex);
}
scheduledFuture = executorService.scheduleWithFixedDelay(RunnableExceptionLogger.wrap(this::ping), 1, 10, TimeUnit.MINUTES);
}
@Subscribe
private void onClientShutdown(ClientShutdown e)
{
scheduledFuture.cancel(true);
e.waitFor(executorService.submit(() ->
{
try
{
e.waitFor(f);
UUID localUuid = sessionId;
if (localUuid != null)
{
sessionClient.delete(localUuid);
}
}
catch (IOException ex)
{
log.warn(null, ex);
}
sessionId = null;
});
}));
}
void start()
private void ping()
{
sessionClient.openSession()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.single())
.doOnError(this::error)
.subscribe(this::setUuid);
}
@Schedule(period = 10, unit = ChronoUnit.MINUTES, asynchronous = true)
public void ping()
{
if (sessionId == null)
try
{
start();
if (sessionId == null)
{
sessionId = sessionClient.open();
log.debug("Opened session {}", sessionId);
return;
}
}
catch (IOException ex)
{
log.warn("unable to open session", ex);
return;
}
sessionClient.pingSession(sessionId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.single())
.doOnError(this::error)
.subscribe();
}
private Future<Void> shutdown()
{
if (sessionId != null)
boolean loggedIn = false;
if (client != null)
{
return sessionClient.delete(sessionId)
.toFuture();
GameState gameState = client.getGameState();
loggedIn = gameState.getState() >= GameState.LOADING.getState();
}
return null;
}
private void setUuid(UUID uuid)
{
this.sessionId = uuid;
log.debug("Opened session {}.", sessionId);
}
try
{
sessionClient.ping(sessionId, loggedIn);
}
catch (IOException ex)
{
log.warn("Resetting session", ex);
sessionId = null;
}
private void error(Throwable error)
{
log.debug("Error in client session.");
log.trace(null, error);
}
}
}

View File

@@ -24,6 +24,7 @@
*/
package net.runelite.client;
import com.google.common.base.Strings;
import com.google.common.escape.Escaper;
import com.google.common.escape.Escapers;
import com.google.inject.Inject;
@@ -113,7 +114,7 @@ public class Notifier
private final ChatMessageManager chatMessageManager;
private final EventBus eventBus;
private final Path notifyIconPath;
private final boolean terminalNotifierAvailable;
private boolean terminalNotifierAvailable;
private Instant flashStart;
private long mouseLastPressedMillis;
private long lastClipMTime = CLIP_MTIME_UNLOADED;
@@ -137,7 +138,10 @@ public class Notifier
this.notifyIconPath = RuneLite.RUNELITE_DIR.toPath().resolve("icon.png");
// First check if we are running in launcher
this.terminalNotifierAvailable = true;
if (!Strings.isNullOrEmpty(RuneLiteProperties.getLauncherVersion()) && OSType.getOSType() == OSType.MacOS)
{
executorService.execute(() -> terminalNotifierAvailable = isTerminalNotifierAvailable());
}
storeIcon();
}
@@ -149,7 +153,7 @@ public class Notifier
public void notify(String message, TrayIcon.MessageType type)
{
eventBus.post(NotificationFired.class, new NotificationFired(message, type));
eventBus.post(new NotificationFired(message, type));
if (!runeLiteConfig.sendNotificationsWhenFocused() && clientUI.isFocused())
{
@@ -364,7 +368,7 @@ public class Notifier
private static Process sendCommand(final List<String> commands) throws IOException
{
return new ProcessBuilder(commands.toArray(new String[0]))
return new ProcessBuilder(commands.toArray(new String[commands.size()]))
.redirectErrorStream(true)
.start();
}
@@ -373,7 +377,7 @@ public class Notifier
{
if (OSType.getOSType() == OSType.Linux && !Files.exists(notifyIconPath))
{
try (InputStream stream = Notifier.class.getResourceAsStream("/openosrs.png"))
try (InputStream stream = Notifier.class.getResourceAsStream("/runelite.png"))
{
Files.copy(stream, notifyIconPath);
}
@@ -386,21 +390,19 @@ public class Notifier
private boolean isTerminalNotifierAvailable()
{
if (OSType.getOSType() == OSType.MacOS)
try
{
try
{
final Process exec = Runtime.getRuntime().exec(new String[]{"terminal-notifier", "-help"});
exec.waitFor();
return exec.exitValue() == 0;
}
catch (IOException | InterruptedException e)
final Process exec = Runtime.getRuntime().exec(new String[]{"terminal-notifier", "-help"});
if (!exec.waitFor(2, TimeUnit.SECONDS))
{
return false;
}
return exec.exitValue() == 0;
}
catch (IOException | InterruptedException e)
{
return false;
}
return false;
}
private static String toUrgency(TrayIcon.MessageType type)

View File

@@ -26,41 +26,27 @@ package net.runelite.client;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import com.github.zafarkhaja.semver.Version;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.UUID;
import javax.annotation.Nullable;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.swing.SwingUtilities;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.OptionException;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.ValueConversionException;
@@ -69,49 +55,34 @@ 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.api.events.ScriptCallbackEvent;
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.config.LauncherConfig;
import net.runelite.client.config.OpenOSRSConfig;
import net.runelite.client.discord.DiscordService;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.ExternalPluginsLoaded;
import net.runelite.client.externalplugins.ExternalPluginManager;
import net.runelite.client.game.FriendChatManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.LootManager;
import net.runelite.client.game.PlayerManager;
import net.runelite.client.game.WorldService;
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.ExternalPluginManager;
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.DrawManager;
import net.runelite.client.ui.FatalErrorDialog;
import net.runelite.client.ui.SplashScreen;
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.InfoBoxManager;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import net.runelite.client.ui.overlay.tooltip.TooltipOverlay;
import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay;
import net.runelite.client.util.Groups;
import net.runelite.client.util.WorldUtil;
import net.runelite.client.ws.PartyService;
import net.runelite.http.api.RuneLiteAPI;
import net.runelite.http.api.worlds.World;
import net.runelite.http.api.worlds.WorldResult;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import org.slf4j.LoggerFactory;
@@ -120,42 +91,41 @@ import org.slf4j.LoggerFactory;
@Slf4j
public class RuneLite
{
public static final String SYSTEM_VERSION = "0.0.1";
public static final File RUNELITE_DIR = new File(System.getProperty("user.home"), ".runelite");
public static final File CACHE_DIR = new File(RUNELITE_DIR, "cache");
public static final File PLUGINS_DIR = new File(RUNELITE_DIR, "plugins");
public static final File PROFILES_DIR = new File(RUNELITE_DIR, "profiles");
public static final File EXTERNALPLUGIN_DIR = new File(RUNELITE_DIR, "externalmanager");
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 File DEFAULT_CONFIG_FILE = new File(RUNELITE_DIR, "runeliteplus.properties");
public static final Locale SYSTEM_LOCALE = Locale.getDefault();
public static boolean allowPrivateServer = false;
public static String uuid = UUID.randomUUID().toString();
public static final File DEFAULT_SESSION_FILE = new File(RUNELITE_DIR, "session");
public static final File DEFAULT_CONFIG_FILE = new File(RUNELITE_DIR, "settings.properties");
private static final int MAX_OKHTTP_CACHE_SIZE = 20 * 1024 * 1024; // 20mb
@Getter
private static Injector injector;
@Inject
public DiscordService discordService;
@Inject
private WorldService worldService;
@Inject
private PluginManager pluginManager;
@Inject
private ExternalPluginManager externalPluginManager;
@Inject
private EventBus eventBus;
@Inject
private ConfigManager configManager;
@Inject
private DrawManager drawManager;
@Inject
private SessionManager sessionManager;
@Inject
private DiscordService discordService;
@Inject
private ClientSessionManager clientSessionManager;
@@ -163,10 +133,10 @@ public class RuneLite
private ClientUI clientUI;
@Inject
private OverlayManager overlayManager;
private Provider<InfoBoxManager> infoBoxManager;
@Inject
private TooltipManager tooltipManager;
private OverlayManager overlayManager;
@Inject
private Provider<PartyService> partyService;
@@ -178,7 +148,7 @@ public class RuneLite
private Provider<OverlayRenderer> overlayRenderer;
@Inject
private Provider<FriendChatManager> friendChatManager;
private Provider<FriendChatManager> friendsChatManager;
@Inject
private Provider<ChatMessageManager> chatMessageManager;
@@ -189,58 +159,25 @@ public class RuneLite
@Inject
private Provider<CommandManager> commandManager;
@Inject
private Provider<InfoBoxManager> infoBoxManager;
@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<PlayerManager> playerManager;
@Inject
private Provider<ChatboxPanelManager> chatboxPanelManager;
@Inject
private Groups groups;
@Inject
private Hooks hooks;
@Inject
private EventBus eventBus;
private Provider<Hooks> hooks;
@Inject
@Nullable
private Client client;
@Inject
private OpenOSRSConfig openOSRSConfig;
@Inject
private LauncherConfig launcherConfig;
@Inject
private Provider<ModelOutlineRenderer> modelOutlineRenderer;
@Inject
private Scheduler scheduler;
public static void main(String[] args) throws Exception
{
Locale.setDefault(Locale.ENGLISH);
@@ -249,15 +186,13 @@ public class RuneLite
parser.accepts("developer-mode", "Enable developer tools");
parser.accepts("debug", "Show extra debugging output");
parser.accepts("safe-mode", "Disables external plugins and the GPU plugin");
parser.accepts("no-splash", "Do not show the splash screen");
parser.accepts("insecure-skip-tls-verification", "Disables TLS verification");
final ArgumentAcceptingOptionSpec<String> proxyInfo = parser
.accepts("proxy")
.withRequiredArg().ofType(String.class);
final ArgumentAcceptingOptionSpec<Integer> worldInfo = parser
.accepts("world")
.withRequiredArg().ofType(Integer.class);
final ArgumentAcceptingOptionSpec<File> sessionfile = parser.accepts("sessionfile", "Use a specified session file")
.withRequiredArg()
.withValuesConvertedBy(new ConfigFileConverter())
.defaultsTo(DEFAULT_SESSION_FILE);
final ArgumentAcceptingOptionSpec<File> configfile = parser.accepts("config", "Use a specified config file")
.withRequiredArg()
.withValuesConvertedBy(new ConfigFileConverter())
@@ -268,7 +203,7 @@ public class RuneLite
.withRequiredArg()
.ofType(ClientUpdateCheckMode.class)
.defaultsTo(ClientUpdateCheckMode.AUTO)
.withValuesConvertedBy(new EnumConverter<>(ClientUpdateCheckMode.class)
.withValuesConvertedBy(new EnumConverter<ClientUpdateCheckMode>(ClientUpdateCheckMode.class)
{
@Override
public ClientUpdateCheckMode convert(String v)
@@ -278,18 +213,7 @@ public class RuneLite
});
parser.accepts("help", "Show this text").forHelp();
OptionSet options = parser.parse("");
try
{
options = parser.parse(args);
}
catch (OptionException e)
{
log.warn("Error parsing launch args: {}", e.getMessage());
log.warn("Proceeding with no arguments.");
}
OptionSet options = parser.parse(args);
if (options.has("help"))
{
@@ -303,147 +227,92 @@ public class RuneLite
logger.setLevel(Level.DEBUG);
}
if (options.has("proxy"))
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) ->
{
String[] proxy = options.valueOf(proxyInfo).split(":");
if (proxy.length >= 2)
log.error("Uncaught exception:", throwable);
if (throwable instanceof AbstractMethodError)
{
System.setProperty("socksProxyHost", proxy[0]);
System.setProperty("socksProxyPort", proxy[1]);
log.error("Classes are out of date; Build with maven again.");
}
});
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 final PasswordAuthentication auth = new PasswordAuthentication(user, pass);
protected PasswordAuthentication getPasswordAuthentication()
{
return auth;
}
});
}
}
if (options.has("world"))
{
int world = options.valueOf(worldInfo);
System.setProperty("cli.world", String.valueOf(world));
}
final File configFile = resolveLinks(options.valueOf(configfile));
Properties properties = new Properties();
try (FileInputStream in = new FileInputStream(configFile))
{
properties.load(new InputStreamReader(in, StandardCharsets.UTF_8));
try
{
@SuppressWarnings("unchecked") Map<String, String> copy = (Map) Map.copyOf(properties);
copy.forEach((groupAndKey, value) ->
{
final String[] split = groupAndKey.split("\\.", 2);
final String groupName = split[0];
final String key = split[1];
if (!groupName.equals("openosrs"))
{
return;
}
if (key.equals("disableHw") && value.equals("true"))
{
log.info("Disabling HW Accel");
System.setProperty("sun.java2d.noddraw", "true");
}
});
}
catch (Exception ex)
{
log.error("Unexpected error", ex);
}
}
catch (FileNotFoundException ex)
{
log.error("Unable to load settings - no such file");
}
catch (IllegalArgumentException | IOException ex)
{
log.error("Unable to load settings", ex);
}
final OkHttpClient.Builder okHttpClientBuilder = RuneLiteAPI.CLIENT.newBuilder()
OkHttpClient.Builder okHttpClientBuilder = RuneLiteAPI.CLIENT.newBuilder()
.cache(new Cache(new File(CACHE_DIR, "okhttp"), MAX_OKHTTP_CACHE_SIZE));
final boolean insecureSkipTlsVerification = options.has("insecure-skip-tls-verification");
if (insecureSkipTlsVerification)
if (insecureSkipTlsVerification || RuneLiteProperties.isInsecureSkipTlsVerification())
{
setupInsecureTrustManager(okHttpClientBuilder);
}
final OkHttpClient okHttpClient = okHttpClientBuilder.build();
final ClientLoader clientLoader = new ClientLoader(okHttpClient, options.valueOf(updateMode));
Completable.fromAction(clientLoader::get)
.subscribeOn(Schedulers.computation())
.subscribe();
SplashScreen.init();
SplashScreen.stage(0, "Retrieving client", "");
Completable.fromAction(ClassPreloader::preload)
.subscribeOn(Schedulers.computation())
.subscribe();
if (!options.has("no-splash"))
try
{
RuneLiteSplashScreen.init();
}
final ClientLoader clientLoader = new ClientLoader(okHttpClient, options.valueOf(updateMode));
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) ->
{
log.error("Uncaught exception:", throwable);
if (throwable instanceof AbstractMethodError)
new Thread(() ->
{
RuneLiteSplashScreen.setError("Out of date!", "Classes are out of date; Build with Gradle again.");
return;
clientLoader.get();
ClassPreloader.preload();
}, "Preloader").start();
final boolean developerMode = options.has("developer-mode") && RuneLiteProperties.getLauncherVersion() == null;
if (developerMode)
{
boolean assertions = false;
assert assertions = true;
if (!assertions)
{
SwingUtilities.invokeLater(() ->
new FatalErrorDialog("Developers should enable assertions; Add `-ea` to your JVM arguments`")
.addBuildingGuide()
.open());
return;
}
}
RuneLiteSplashScreen.setError("Error while loading!", "Please check your internet connection and your DNS settings.");
});
PROFILES_DIR.mkdirs();
PROFILES_DIR.mkdirs();
log.info("RuneLite {} (launcher version {}) starting up, args: {}",
RuneLiteProperties.getVersion(), RuneLiteProperties.getLauncherVersion() == null ? "unknown" : RuneLiteProperties.getLauncherVersion(),
args.length == 0 ? "none" : String.join(" ", args));
log.info("OpenOSRS {} Runelite {} (launcher version {}) starting up, args: {}",
RuneLiteProperties.getPlusVersion(), RuneLiteProperties.getVersion(), RuneLiteProperties.getLauncherVersion() == null ? "unknown" : RuneLiteProperties.getLauncherVersion(),
args.length == 0 ? "none" : String.join(" ", args));
final long start = System.currentTimeMillis();
final long start = System.currentTimeMillis();
injector = Guice.createInjector(new RuneLiteModule(
okHttpClient,
clientLoader,
developerMode,
options.has("safe-mode"),
options.valueOf(sessionfile),
options.valueOf(configfile)));
injector = Guice.createInjector(new RuneLiteModule(
okHttpClient,
clientLoader,
options.has("safe-mode"),
configFile));
injector.getInstance(RuneLite.class).start();
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);
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);
}
catch (Exception e)
{
log.error("Failure during startup", e);
SwingUtilities.invokeLater(() ->
new FatalErrorDialog("RuneLite has encountered an unexpected error during startup.")
.open());
}
finally
{
SplashScreen.stop();
}
}
@VisibleForTesting
public static void setInjector(Injector injector)
{
RuneLite.injector = injector;
}
private void start() throws Exception
public void start() throws Exception
{
// Load RuneLite or Vanilla client
final boolean isOutdated = client == null;
@@ -454,181 +323,84 @@ public class RuneLite
injector.injectMembers(client);
}
if (RuneLiteProperties.getLauncherVersion() == null || !openOSRSConfig.shareLogs())
{
final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
logger.detachAppender("Sentry");
}
SplashScreen.stage(.57, null, "Loading configuration");
// Load user configuration
RuneLiteSplashScreen.stage(.57, "Loading user config");
configManager.load();
parseLauncherConfig();
// 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 plugin manager
externalPluginManager.startExternalUpdateManager();
externalPluginManager.startExternalPluginManager();
// Update external plugins
externalPluginManager.update();
// Load the plugins, but does not start them yet.
// This will initialize configuration
pluginManager.loadCorePlugins();
externalPluginManager.loadPlugins();
externalPluginManager.loadExternalPlugins();
RuneLiteSplashScreen.stage(.76, "Finalizing configuration");
SplashScreen.stage(.70, null, "Finalizing configuration");
// Plugins have provided their config, so set default config
// to main settings
pluginManager.loadDefaultPluginConfiguration();
pluginManager.loadDefaultPluginConfiguration(null);
// Start client session
RuneLiteSplashScreen.stage(.77, "Starting core interface");
clientSessionManager.start();
eventBus.register(clientSessionManager);
//Set the world if specified via CLI args - will not work until clientUI.init is called
Optional<Integer> worldArg = Optional.ofNullable(System.getProperty("cli.world")).map(Integer::parseInt);
worldArg.ifPresent(this::setWorld);
SplashScreen.stage(.75, null, "Starting core interface");
// Initialize UI
RuneLiteSplashScreen.stage(.80, "Initialize UI");
clientUI.init();
// Initialize Discord service
discordService.init();
// Register event listeners
eventBus.register(clientUI);
eventBus.register(pluginManager);
eventBus.register(externalPluginManager);
eventBus.register(overlayManager);
eventBus.register(drawManager);
eventBus.register(configManager);
eventBus.register(discordService);
if (!isOutdated)
{
// Initialize chat colors
chatMessageManager.get().loadColors();
infoBoxManager.get();
overlayRenderer.get();
friendChatManager.get();
itemManager.get();
menuManager.get();
chatMessageManager.get();
commandManager.get();
lootManager.get();
xpDropManager.get();
playerManager.get();
chatboxPanelManager.get();
partyService.get();
eventBus.subscribe(GameStateChanged.class, this, hooks::onGameStateChanged);
eventBus.subscribe(ScriptCallbackEvent.class, this, hooks::onScriptCallbackEvent);
eventBus.register(infoBoxManager.get());
eventBus.register(partyService.get());
eventBus.register(overlayRenderer.get());
eventBus.register(friendsChatManager.get());
eventBus.register(itemManager.get());
eventBus.register(menuManager.get());
eventBus.register(chatMessageManager.get());
eventBus.register(commandManager.get());
eventBus.register(lootManager.get());
eventBus.register(chatboxPanelManager.get());
eventBus.register(hooks.get());
// Add core overlays
WidgetOverlay.createOverlays(client).forEach(overlayManager::add);
overlayManager.add(worldMapOverlay.get());
overlayManager.add(tooltipOverlay.get());
overlayManager.add(arrowWorldOverlay.get());
overlayManager.add(arrowMinimapOverlay.get());
}
// Start plugins
pluginManager.startPlugins();
eventBus.post(ExternalPluginsLoaded.class, new ExternalPluginsLoaded());
// Register additional schedulers
if (this.client != null)
{
scheduler.registerObject(modelOutlineRenderer.get());
scheduler.registerObject(clientSessionManager);
}
// Close the splash screen
RuneLiteSplashScreen.close();
SplashScreen.stop();
clientUI.show();
}
private void setWorld(int cliWorld)
@VisibleForTesting
public static void setInjector(Injector injector)
{
int correctedWorld = cliWorld < 300 ? cliWorld + 300 : cliWorld;
if (correctedWorld <= 300 || client.getWorld() == correctedWorld)
{
return;
}
final WorldResult worldResult = worldService.getWorlds();
if (worldResult == null)
{
log.warn("Failed to lookup worlds.");
return;
}
final World world = worldResult.findWorld(correctedWorld);
if (world != null)
{
final net.runelite.api.World rsWorld = client.createWorld();
rsWorld.setActivity(world.getActivity());
rsWorld.setAddress(world.getAddress());
rsWorld.setId(world.getId());
rsWorld.setPlayerCount(world.getPlayers());
rsWorld.setLocation(world.getLocation());
rsWorld.setTypes(WorldUtil.toWorldTypes(world.getTypes()));
client.changeWorld(rsWorld);
log.debug("Applied new world {}", correctedWorld);
}
else
{
log.warn("World {} not found.", correctedWorld);
}
}
private void parseLauncherConfig()
{
String launcherVersion = RuneLiteProperties.getLauncherVersion();
if (launcherVersion == null || !Version.valueOf(launcherVersion).greaterThanOrEqualTo(Version.valueOf("2.2.0")))
{
return;
}
if (launcherConfig.useProxy())
{
log.info("Setting proxy.");
String[] proxy = launcherConfig.proxyDetails().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 final PasswordAuthentication auth = new PasswordAuthentication(user, pass);
protected PasswordAuthentication getPasswordAuthentication()
{
return auth;
}
});
}
}
RuneLite.injector = injector;
}
private static class ConfigFileConverter implements ValueConverter<File>
@@ -670,18 +442,6 @@ public class RuneLite
}
}
private static File resolveLinks(File f)
{
try
{
return f.toPath().toRealPath().toFile();
}
catch (IOException e)
{
return f;
}
}
private static void setupInsecureTrustManager(OkHttpClient.Builder okHttpClientBuilder)
{
try

View File

@@ -24,18 +24,13 @@
*/
package net.runelite.client;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.name.Names;
import java.applet.Applet;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import javax.inject.Singleton;
@@ -47,8 +42,6 @@ import net.runelite.client.callback.Hooks;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.config.ChatColorConfig;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.LauncherConfig;
import net.runelite.client.config.OpenOSRSConfig;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.game.ItemManager;
@@ -57,25 +50,27 @@ import net.runelite.client.plugins.PluginManager;
import net.runelite.client.task.Scheduler;
import net.runelite.client.util.DeferredEventBus;
import net.runelite.client.util.ExecutorServiceExceptionLogger;
import net.runelite.client.util.NonScheduledExecutorServiceExceptionLogger;
import net.runelite.http.api.chat.ChatClient;
import okhttp3.OkHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@AllArgsConstructor
public class RuneLiteModule extends AbstractModule
{
private final OkHttpClient okHttpClient;
private final Supplier<Applet> clientLoader;
private final boolean developerMode;
private final boolean safeMode;
private final File sessionfile;
private final File config;
@Override
protected void configure()
{
bindConstant().annotatedWith(Names.named("developerMode")).to(developerMode);
bindConstant().annotatedWith(Names.named("safeMode")).to(safeMode);
bind(File.class).annotatedWith(Names.named("sessionfile")).toInstance(sessionfile);
bind(File.class).annotatedWith(Names.named("config")).toInstance(config);
bind(ScheduledExecutorService.class).toInstance(new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor()));
bind(OkHttpClient.class).toInstance(okHttpClient);
bind(MenuManager.class);
bind(ChatMessageManager.class);
@@ -92,10 +87,6 @@ public class RuneLiteModule extends AbstractModule
bind(EventBus.class)
.annotatedWith(Names.named("Deferred EventBus"))
.to(DeferredEventBus.class);
bind(Logger.class)
.annotatedWith(Names.named("Core Logger"))
.toInstance(LoggerFactory.getLogger(RuneLite.class));
}
@Provides
@@ -119,13 +110,6 @@ public class RuneLiteModule extends AbstractModule
return configManager.getConfig(RuneLiteConfig.class);
}
@Provides
@Singleton
OpenOSRSConfig providePlusConfig(ConfigManager configManager)
{
return configManager.getConfig(OpenOSRSConfig.class);
}
@Provides
@Singleton
ChatColorConfig provideChatColorConfig(ConfigManager configManager)
@@ -133,39 +117,6 @@ public class RuneLiteModule extends AbstractModule
return configManager.getConfig(ChatColorConfig.class);
}
@Provides
@Singleton
LauncherConfig provideLauncherConfig(ConfigManager configManager)
{
return configManager.getConfig(LauncherConfig.class);
}
@Provides
@Singleton
ScheduledExecutorService provideScheduledExecutorService()
{
return new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder()
.setNameFormat("scheduled-%d")
.build()));
}
@Provides
@Singleton
ExecutorService provideExecutorService()
{
int poolSize = 2 * Runtime.getRuntime().availableProcessors();
// Will start up to poolSize threads (because of allowCoreThreadTimeOut) as necessary, and times out
// unused threads after 1 minute
ThreadPoolExecutor executor = new ThreadPoolExecutor(poolSize, poolSize,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
new ThreadFactoryBuilder().setNameFormat("worker-%d").build());
executor.allowCoreThreadTimeOut(true);
return new NonScheduledExecutorServiceExceptionLogger(executor);
}
@Provides
@Singleton
ChatClient provideChatClient(OkHttpClient okHttpClient)

View File

@@ -24,37 +24,38 @@
*/
package net.runelite.client;
import com.google.common.base.Strings;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.annotation.Nullable;
import okhttp3.HttpUrl;
public class RuneLiteProperties
{
private static final String RUNELITE_TITLE = "open.osrs.title";
private static final String RUNELITE_TITLE = "runelite.title";
private static final String RUNELITE_VERSION = "runelite.version";
private static final String RUNELITE_PLUS_VERSION = "open.osrs.version";
private static final String RUNELITE_PLUS_DATE = "open.osrs.builddate";
private static final String RUNESCAPE_VERSION = "runescape.version";
private static final String DISCORD_APP_ID = "open.osrs.discord.appid";
private static final String DISCORD_APP_ID = "runelite.discord.appid";
private static final String DISCORD_INVITE = "runelite.discord.invite";
private static final String GITHUB_LINK = "runelite.github.link";
private static final String WIKI_LINK = "runelite.wiki.link";
private static final String PATREON_LINK = "runelite.patreon.link";
private static final String LAUNCHER_VERSION_PROPERTY = "launcher.version";
private static final String PLUGIN_PATH = "plugin.path";
private static final String PLUGIN_DEVELOPMENT_PATH = "plugin.development.path";
private static final String LAUNCHER_VERSION_PROPERTY = "runelite.launcher.version";
private static final String INSECURE_SKIP_TLS_VERIFICATION_PROPERTY = "runelite.insecure-skip-tls-verification";
private static final String TROUBLESHOOTING_LINK = "runelite.wiki.troubleshooting.link";
private static final String BUILDING_LINK = "runelite.wiki.building.link";
private static final String DNS_CHANGE_LINK = "runelite.dnschange.link";
private static final String JAV_CONFIG = "runelite.jav_config";
private static final String JAV_CONFIG_BACKUP = "runelite.jav_config_backup";
private static final String PLUGINHUB_BASE = "runelite.pluginhub.url";
private static final String PLUGINHUB_VERSION = "runelite.pluginhub.version";
private static final String IMGUR_CLIENT_ID = "runelite.imgur.client.id";
private static final Properties properties = new Properties();
static
{
try (InputStream in = RuneLiteProperties.class.getResourceAsStream("open.osrs.properties"))
try (InputStream in = RuneLiteProperties.class.getResourceAsStream("runelite.properties"))
{
properties.load(in);
}
@@ -66,13 +67,7 @@ public class RuneLiteProperties
public static String getTitle()
{
final StringBuilder sb = new StringBuilder(properties.getProperty(RUNELITE_TITLE));
String proxy;
if ((proxy = System.getProperty("socksProxyHost")) != null)
{
sb.append(String.format(" (%s)", proxy));
}
return sb.toString();
return properties.getProperty(RUNELITE_TITLE);
}
public static String getVersion()
@@ -80,16 +75,6 @@ public class RuneLiteProperties
return properties.getProperty(RUNELITE_VERSION);
}
public static String getPlusVersion()
{
return properties.getProperty(RUNELITE_PLUS_VERSION);
}
public static String getPlusDate()
{
return properties.getProperty(RUNELITE_PLUS_DATE);
}
public static String getRunescapeVersion()
{
return properties.getProperty(RUNESCAPE_VERSION);
@@ -120,6 +105,17 @@ public class RuneLiteProperties
return properties.getProperty(PATREON_LINK);
}
@Nullable
public static String getLauncherVersion()
{
return System.getProperty(LAUNCHER_VERSION_PROPERTY);
}
public static boolean isInsecureSkipTlsVerification()
{
return Boolean.getBoolean(INSECURE_SKIP_TLS_VERIFICATION_PROPERTY);
}
public static String getTroubleshootingLink()
{
return properties.getProperty(TROUBLESHOOTING_LINK);
@@ -135,31 +131,20 @@ public class RuneLiteProperties
return properties.getProperty(DNS_CHANGE_LINK);
}
@Nullable
public static String getLauncherVersion()
public static String getJavConfig()
{
return System.getProperty(LAUNCHER_VERSION_PROPERTY);
return properties.getProperty(JAV_CONFIG);
}
@Nullable
public static String getPluginPath()
public static String getJavConfigBackup()
{
String pluginPath = properties.getProperty(PLUGIN_PATH);
return pluginPath.equals("") ? null : pluginPath;
return properties.getProperty(JAV_CONFIG_BACKUP);
}
public static String[] getPluginDevelopmentPath()
public static HttpUrl getPluginHubBase()
{
// First check if property supplied as environment variable PLUGIN_DEVELOPMENT_PATHS
String developmentPluginPaths = System.getenv(PLUGIN_DEVELOPMENT_PATH.replace('.', '_').toUpperCase());
if (Strings.isNullOrEmpty(developmentPluginPaths))
{
// Otherwise check the property file
developmentPluginPaths = properties.getProperty(PLUGIN_DEVELOPMENT_PATH);
}
return Strings.isNullOrEmpty(developmentPluginPaths) ? new String[0] : developmentPluginPaths.split(";");
String version = System.getProperty(PLUGINHUB_VERSION, properties.getProperty(PLUGINHUB_VERSION));
return HttpUrl.parse(properties.get(PLUGINHUB_BASE) + "/" + version);
}
public static String getImgurClientId()

View File

@@ -24,8 +24,7 @@
*/
package net.runelite.client;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Observable;
import com.google.gson.JsonParseException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -36,6 +35,7 @@ import net.runelite.http.api.RuneLiteAPI;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
@@ -44,73 +44,62 @@ class SessionClient
{
private final OkHttpClient okHttpClient;
Observable<UUID> openSession()
UUID open() throws IOException
{
final HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder()
.addPathSegment("new")
HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder()
.build();
return Observable.fromCallable(() ->
Request request = new Request.Builder()
.post(RequestBody.create(null, new byte[0]))
.url(url)
.build();
try (Response response = okHttpClient.newCall(request).execute())
{
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = okHttpClient.newCall(request).execute())
{
ResponseBody body = response.body();
InputStream in = body.byteStream();
try
{
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), UUID.class);
}
catch (IllegalArgumentException ex)
{
ex.printStackTrace();
return null;
}
}
});
ResponseBody body = response.body();
InputStream in = body.byteStream();
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), UUID.class);
}
catch (JsonParseException | IllegalArgumentException ex) // UUID.fromString can throw IllegalArgumentException
{
throw new IOException(ex);
}
}
Completable pingSession(UUID uuid)
void ping(UUID uuid, boolean loggedIn) throws IOException
{
final HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder()
HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder()
.addPathSegment("ping")
.addQueryParameter("uuid", uuid.toString())
.addQueryParameter("session", uuid.toString())
.addQueryParameter("logged-in", String.valueOf(loggedIn))
.build();
return Completable.fromAction(() ->
{
Request request = new Request.Builder()
.url(url)
.build();
Request request = new Request.Builder()
.post(RequestBody.create(null, new byte[0]))
.url(url)
.build();
try (Response response = okHttpClient.newCall(request).execute())
try (Response response = okHttpClient.newCall(request).execute())
{
if (!response.isSuccessful())
{
if (!response.isSuccessful())
{
throw new IOException("Unsuccessful ping");
}
throw new IOException("Unsuccessful ping");
}
});
}
}
Completable delete(UUID uuid)
void delete(UUID uuid) throws IOException
{
final HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder()
HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder()
.addQueryParameter("session", uuid.toString())
.build();
return Completable.fromAction(() ->
{
Request request = new Request.Builder()
.delete()
.url(url)
.build();
Request request = new Request.Builder()
.delete()
.url(url)
.build();
okHttpClient.newCall(request).execute().close();
});
okHttpClient.newCall(request).execute().close();
}
}

View File

@@ -25,7 +25,6 @@
package net.runelite.client.account;
import com.google.gson.Gson;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -37,11 +36,13 @@ import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.UUID;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.SessionClose;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.util.LinkBrowser;
@@ -55,31 +56,35 @@ import okhttp3.OkHttpClient;
@Slf4j
public class SessionManager
{
private static final File SESSION_FILE = new File(RuneLite.RUNELITE_DIR, "session");
@Getter
private AccountSession accountSession;
private final EventBus eventBus;
private final ConfigManager configManager;
private final WSClient wsClient;
private final File sessionFile;
private final AccountClient accountClient;
@Inject
private SessionManager(
@Named("sessionfile") File sessionfile,
ConfigManager configManager,
EventBus eventBus,
WSClient wsClient,
OkHttpClient okHttpClient)
{
this.configManager = configManager;
this.eventBus = eventBus;
this.wsClient = wsClient;
this.sessionFile = sessionfile;
this.accountClient = new AccountClient(okHttpClient);
this.eventBus.subscribe(LoginResponse.class, this, this::onLoginResponse);
eventBus.register(this);
}
public void loadSession()
{
if (!SESSION_FILE.exists())
if (!sessionFile.exists())
{
log.info("No session file exists");
return;
@@ -87,7 +92,7 @@ public class SessionManager
AccountSession session;
try (FileInputStream in = new FileInputStream(SESSION_FILE))
try (FileInputStream in = new FileInputStream(sessionFile))
{
session = new Gson().fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), AccountSession.class);
@@ -101,26 +106,13 @@ public class SessionManager
// Check if session is still valid
accountClient.setUuid(session.getUuid());
accountClient.sessionCheck()
.subscribeOn(Schedulers.io())
.subscribe(b ->
{
if (!b)
{
log.debug("Loaded session {} is invalid", session.getUuid());
}
else
{
openSession(session, false);
}
}, ex ->
{
if (ex instanceof IOException)
{
log.debug("Unable to verify session", ex);
openSession(session, false);
}
});
if (!accountClient.sessionCheck())
{
log.debug("Loaded session {} is invalid", session.getUuid());
return;
}
openSession(session, false);
}
private void saveSession()
@@ -130,11 +122,11 @@ public class SessionManager
return;
}
try (Writer fw = new OutputStreamWriter(new FileOutputStream(SESSION_FILE), StandardCharsets.UTF_8))
try (Writer fw = new OutputStreamWriter(new FileOutputStream(sessionFile), StandardCharsets.UTF_8))
{
new Gson().toJson(accountSession, fw);
log.debug("Saved session to {}", SESSION_FILE);
log.debug("Saved session to {}", sessionFile);
}
catch (IOException ex)
{
@@ -144,7 +136,7 @@ public class SessionManager
private void deleteSession()
{
SESSION_FILE.delete();
sessionFile.delete();
}
/**
@@ -163,7 +155,14 @@ public class SessionManager
accountSession = session;
eventBus.post(SessionOpen.class, new SessionOpen());
if (session.getUsername() != null)
{
// Initialize config for new session
// If the session isn't logged in yet, don't switch to the new config
configManager.switchSession(session);
}
eventBus.post(new SessionOpen());
}
private void closeSession()
@@ -189,7 +188,10 @@ public class SessionManager
accountSession = null; // No more account
eventBus.post(SessionClose.class, new SessionClose());
// Restore config
configManager.switchSession(null);
eventBus.post(new SessionClose());
}
public void login()
@@ -217,7 +219,8 @@ public class SessionManager
LinkBrowser.browse(login.getOauthUrl());
}
private void onLoginResponse(LoginResponse loginResponse)
@Subscribe
public void onLoginResponse(LoginResponse loginResponse)
{
log.debug("Now logged in as {}", loginResponse.getUsername());

View File

@@ -25,34 +25,22 @@
package net.runelite.client.callback;
import com.google.inject.Inject;
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.function.BooleanSupplier;
import javax.annotation.Nullable;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import org.jetbrains.annotations.NotNull;
@Singleton
@Slf4j
public class ClientThread implements Executor
public class ClientThread
{
private final ConcurrentLinkedQueue<BooleanSupplier> invokes = new ConcurrentLinkedQueue<>();
@Inject
@Nullable
private Client client;
@Inject
private ClientThread()
{
RxJavaPlugins.setSingleSchedulerHandler(old -> Schedulers.from(this));
}
public void invoke(Runnable r)
{
invoke(() ->
@@ -124,14 +112,4 @@ public class ClientThread implements Executor
}
}
}
@Override
public void execute(@NotNull Runnable r)
{
invoke(() ->
{
r.run();
return true;
});
}
}

View File

@@ -24,7 +24,6 @@
*/
package net.runelite.client.callback;
import com.google.inject.Injector;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
@@ -40,31 +39,25 @@ import java.awt.image.VolatileImage;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.BufferProvider;
import net.runelite.api.Client;
import net.runelite.api.Entity;
import net.runelite.api.MainBufferProvider;
import net.runelite.api.NullItemID;
import net.runelite.api.RenderOverview;
import net.runelite.api.Skill;
import net.runelite.api.WorldMapManager;
import net.runelite.api.events.BeforeMenuRender;
import net.runelite.api.events.BeforeRender;
import net.runelite.api.events.Event;
import net.runelite.api.events.FakeXpDrop;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.hooks.Callbacks;
import net.runelite.api.hooks.DrawCallbacks;
import net.runelite.api.widgets.Widget;
import static net.runelite.api.widgets.WidgetInfo.WORLD_MAP_VIEW;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.Notifier;
import net.runelite.client.RuneLite;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.DrawFinished;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.KeyManager;
import net.runelite.client.input.MouseManager;
import net.runelite.client.task.Scheduler;
@@ -75,7 +68,6 @@ import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.OverlayRenderer;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.util.DeferredEventBus;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.RSTimeUnit;
/**
@@ -89,19 +81,17 @@ public class Hooks implements Callbacks
{
private static final long CHECK = RSTimeUnit.GAME_TICKS.getDuration().toNanos(); // ns - how often to run checks
private static final Injector injector = RuneLite.getInjector();
private static final Client client = injector.getInstance(Client.class);
public static final OverlayRenderer renderer = injector.getInstance(OverlayRenderer.class);
private static final OverlayManager overlayManager = injector.getInstance(OverlayManager.class);
private static final GameTick GAME_TICK = new GameTick();
private static final BeforeRender BEFORE_RENDER = new BeforeRender();
private static final GameTick GAME_TICK = GameTick.INSTANCE;
private static final BeforeRender BEFORE_RENDER = BeforeRender.INSTANCE;
private static final DrawFinished drawFinishedEvent = new DrawFinished();
@Inject
private Client client;
private int mouseX = 0;
private int mouseY = 0;
private final Image cursor = ImageUtil.getResourceStreamFromClass(Hooks.class, "cursor.png");
@Inject
private OverlayRenderer renderer;
@Inject
private OverlayManager overlayManager;
@Inject
private EventBus eventBus;
@@ -145,7 +135,7 @@ public class Hooks implements Callbacks
private boolean shouldProcessGameTick;
private static MainBufferProvider lastMainBufferProvider;
public static Graphics2D lastGraphics;
private static Graphics2D lastGraphics;
/**
* Get the Graphics2D for the MainBufferProvider image
@@ -170,15 +160,15 @@ public class Hooks implements Callbacks
}
@Override
public <T extends Event, E extends T> void post(Class<T> eventClass, E event)
public void post(Object event)
{
eventBus.post(eventClass, event);
eventBus.post(event);
}
@Override
public <T extends Event, E extends T> void postDeferred(Class<T> eventClass, E event)
public void postDeferred(Object event)
{
deferredEventBus.post(eventClass, event);
deferredEventBus.post(event);
}
@Override
@@ -190,13 +180,13 @@ public class Hooks implements Callbacks
deferredEventBus.replay();
eventBus.post(GameTick.class, GameTick.INSTANCE);
eventBus.post(GAME_TICK);
int tick = client.getTickCount();
client.setTickCount(tick + 1);
}
eventBus.post(BeforeRender.class, BeforeRender.INSTANCE);
eventBus.post(BEFORE_RENDER);
clientThread.invoke();
@@ -293,16 +283,12 @@ public class Hooks implements Callbacks
@Override
public MouseEvent mouseDragged(MouseEvent mouseEvent)
{
mouseX = mouseEvent.getX();
mouseY = mouseEvent.getY();
return mouseManager.processMouseDragged(mouseEvent);
}
@Override
public MouseEvent mouseMoved(MouseEvent mouseEvent)
{
mouseX = mouseEvent.getX();
mouseY = mouseEvent.getY();
return mouseManager.processMouseMoved(mouseEvent);
}
@@ -405,22 +391,6 @@ public class Hooks implements Callbacks
finalImage = image;
}
if (client.isMirrored())
{
drawFinishedEvent.image = copy(finalImage);
drawFinishedEvent.image.getGraphics().drawImage(cursor, mouseX, mouseY, null);
eventBus.post(DrawFinished.class, drawFinishedEvent);
}
try
{
renderer.render((Graphics2D)finalImage.getGraphics(), OverlayLayer.AFTER_MIRROR);
}
catch (Exception ex)
{
log.warn("Error during post-mirror rendering", ex);
}
// Draw the image onto the game canvas
graphics.drawImage(finalImage, 0, 0, client.getCanvas());
@@ -431,6 +401,8 @@ public class Hooks implements Callbacks
/**
* Copy an image
* @param src
* @return
*/
private static Image copy(Image src)
{
@@ -475,7 +447,8 @@ public class Hooks implements Callbacks
}
}
public static void drawAfterWidgets()
@Override
public void drawAfterWidgets()
{
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
Graphics2D graphics2d = getGraphics(bufferProvider);
@@ -495,6 +468,7 @@ public class Hooks implements Callbacks
overlayManager.getItemWidgets().clear();
}
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
switch (gameStateChanged.getGameState())
@@ -530,38 +504,6 @@ public class Hooks implements Callbacks
deferredEventBus.replay();
}
public static void renderDraw(Entity entity, int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, long hash)
{
DrawCallbacks drawCallbacks = client.getDrawCallbacks();
if (drawCallbacks != null)
{
drawCallbacks.draw(entity, orientation, pitchSin, pitchCos, yawSin, yawCos, x, y, z, hash);
}
else
{
entity.draw(orientation, pitchSin, pitchCos, yawSin, yawCos, x, y, z, hash);
}
}
public static void clearColorBuffer(int x, int y, int width, int height, int color)
{
BufferProvider bp = client.getBufferProvider();
int canvasWidth = bp.getWidth();
int[] pixels = bp.getPixels();
int pixelPos = y * canvasWidth + x;
int pixelJump = canvasWidth - width;
for (int cy = y; cy < y + height; cy++)
{
for (int cx = x; cx < x + width; cx++)
{
pixels[pixelPos++] = 0;
}
pixelPos += pixelJump;
}
}
@Override
public void drawItem(int itemId, WidgetItem widgetItem)
{
@@ -572,13 +514,7 @@ public class Hooks implements Callbacks
}
}
public static boolean drawMenu()
{
BeforeMenuRender event = new BeforeMenuRender();
client.getCallbacks().post(BeforeMenuRender.class, event);
return event.isConsumed();
}
@Subscribe
public void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent)
{
if (!scriptCallbackEvent.getEventName().equals("fakeXpDrop"))
@@ -597,6 +533,6 @@ public class Hooks implements Callbacks
skill,
xp
);
eventBus.post(FakeXpDrop.class, fakeXpDrop);
eventBus.post(fakeXpDrop);
}
}
}

View File

@@ -41,21 +41,20 @@ import net.runelite.client.events.ChatboxInput;
import net.runelite.client.events.PrivateMessageInput;
@Singleton
public class ChatCommandManager
public class ChatCommandManager implements ChatboxInputListener
{
private final Map<String, ChatCommand> commands = new ConcurrentHashMap<>();
private final Client client;
private final ScheduledExecutorService scheduledExecutorService;
@Inject
private ChatCommandManager(EventBus eventBus, Client client, ScheduledExecutorService scheduledExecutorService)
private ChatCommandManager(EventBus eventBus, CommandManager commandManager, Client client, ScheduledExecutorService scheduledExecutorService)
{
this.client = client;
this.scheduledExecutorService = scheduledExecutorService;
eventBus.subscribe(ChatboxInput.class, this, this::onChatboxInput);
eventBus.subscribe(PrivateMessageInput.class, this, this::onPrivateMessageInput);
eventBus.subscribe(ChatMessage.class, this, this::onChatMessage);
eventBus.register(this);
commandManager.register(this);
}
public void registerCommand(String command, BiConsumer<ChatMessage, String> execute)
@@ -83,7 +82,8 @@ public class ChatCommandManager
commands.remove(command.toLowerCase());
}
private void onChatMessage(ChatMessage chatMessage)
@Subscribe
public void onChatMessage(ChatMessage chatMessage)
{
if (client.getGameState() != GameState.LOGGED_IN)
{
@@ -106,6 +106,11 @@ public class ChatCommandManager
String message = chatMessage.getMessage();
String command = extractCommand(message);
if (command == null)
{
return;
}
ChatCommand chatCommand = commands.get(command.toLowerCase());
if (chatCommand == null)
{
@@ -122,8 +127,8 @@ public class ChatCommandManager
}
}
@Subscribe // just for show
private void onChatboxInput(ChatboxInput chatboxInput)
@Override
public boolean onChatboxInput(ChatboxInput chatboxInput)
{
String message = chatboxInput.getValue();
if (message.startsWith("/"))
@@ -131,30 +136,51 @@ public class ChatCommandManager
message = message.substring(1); // friends chat input
}
onInput(chatboxInput, message);
}
@Subscribe // just for show
private void onPrivateMessageInput(PrivateMessageInput input)
{
onInput(input, input.getMessage());
}
private void onInput(ChatInput chatInput, String message)
{
String command = extractCommand(message);
if (command == null)
{
return false;
}
ChatCommand chatCommand = commands.get(command.toLowerCase());
if (chatCommand == null)
{
return;
return false;
}
BiPredicate<ChatInput, String> input = chatCommand.getInput();
if (input != null && input.test(chatInput, message))
if (input == null)
{
chatInput.setStop();
return false;
}
return input.test(chatboxInput, message);
}
@Override
public boolean onPrivateMessageInput(PrivateMessageInput privateMessageInput)
{
final String message = privateMessageInput.getMessage();
String command = extractCommand(message);
if (command == null)
{
return false;
}
ChatCommand chatCommand = commands.get(command.toLowerCase());
if (chatCommand == null)
{
return false;
}
BiPredicate<ChatInput, String> input = chatCommand.getInput();
if (input == null)
{
return false;
}
return input.test(privateMessageInput, message);
}
private static String extractCommand(String message)

View File

@@ -25,8 +25,8 @@
package net.runelite.client.chat;
import java.awt.Color;
import net.runelite.api.util.Text;
import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.Text;
public class ChatMessageBuilder
{

View File

@@ -24,8 +24,10 @@
*/
package net.runelite.client.chat;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import java.awt.Color;
import java.util.Arrays;
@@ -44,20 +46,20 @@ import net.runelite.api.MessageNode;
import net.runelite.api.Player;
import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage;
import net.runelite.client.events.ConfigChanged;
import net.runelite.api.events.ResizeableChanged;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ChatColorConfig;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.ui.JagexColors;
import net.runelite.client.util.ColorUtil;
@Singleton
public class ChatMessageManager
{
private static final Set<Integer> TUTORIAL_ISLAND_REGIONS = Set.of(12336, 12335, 12592, 12080, 12079, 12436);
private static final Set<Integer> TUTORIAL_ISLAND_REGIONS = ImmutableSet.of(12336, 12335, 12592, 12080, 12079, 12436);
private final Multimap<ChatMessageType, ChatColor> colorCache = HashMultimap.create();
private final Client client;
@@ -68,23 +70,17 @@ public class ChatMessageManager
@Inject
private ChatMessageManager(
final Client client,
final ChatColorConfig chatColorConfig,
final ClientThread clientThread,
final EventBus eventbus)
Client client,
ChatColorConfig chatColorConfig,
ClientThread clientThread)
{
this.client = client;
this.chatColorConfig = chatColorConfig;
this.clientThread = clientThread;
eventbus.subscribe(VarbitChanged.class, this, this::onVarbitChanged);
eventbus.subscribe(ResizeableChanged.class, this, this::onResizeableChanged);
eventbus.subscribe(ConfigChanged.class, this, this::onConfigChanged);
eventbus.subscribe(ChatMessage.class, this, this::onChatMessage);
eventbus.subscribe(ScriptCallbackEvent.class, this, this::onScriptCallbackEvent);
}
private void onVarbitChanged(VarbitChanged event)
@Subscribe
public void onVarbitChanged(VarbitChanged event)
{
int setting = client.getVar(Varbits.TRANSPARENT_CHATBOX);
@@ -95,12 +91,14 @@ public class ChatMessageManager
}
}
private void onResizeableChanged(ResizeableChanged event)
@Subscribe
public void onResizeableChanged(ResizeableChanged event)
{
refreshAll();
}
private void onConfigChanged(ConfigChanged event)
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("textrecolor"))
{
@@ -109,7 +107,8 @@ public class ChatMessageManager
}
}
void onChatMessage(ChatMessage chatMessage)
@Subscribe(priority = -1) // run after all plugins
public void onChatMessage(ChatMessage chatMessage)
{
MessageNode messageNode = chatMessage.getMessageNode();
ChatMessageType chatMessageType = chatMessage.getType();
@@ -174,7 +173,8 @@ public class ChatMessageManager
}
}
private void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent)
@Subscribe
public void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent)
{
final String eventName = scriptCallbackEvent.getEventName();
@@ -571,17 +571,11 @@ public class ChatMessageManager
return;
}
//guard case for google MoreObjects#firstNonNull
if (message.getValue() == null && message.getRuneLiteFormattedMessage() == null)
{
return;
}
// this updates chat cycle
client.addChatMessage(
message.getType(),
Objects.requireNonNullElse(message.getName(), ""),
Objects.requireNonNullElse(message.getValue(), message.getRuneLiteFormattedMessage()),
MoreObjects.firstNonNull(message.getName(), ""),
MoreObjects.firstNonNull(message.getValue(), message.getRuneLiteFormattedMessage()),
message.getSender());
// Get last message from line buffer (the one we just added)
@@ -591,7 +585,7 @@ public class ChatMessageManager
// Update the message with RuneLite additions
line.setRuneLiteFormatMessage(message.getRuneLiteFormattedMessage());
if (message.getTimestamp() != 0)
{
line.setTimestamp(message.getTimestamp());

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,25 +22,14 @@
* (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.discord;
package net.runelite.client.chat;
/**
* Discord reply type for request
*/
public enum DiscordReplyType
import net.runelite.client.events.ChatboxInput;
import net.runelite.client.events.PrivateMessageInput;
public interface ChatboxInputListener
{
/**
* Used to decline a request
*/
NO,
boolean onChatboxInput(ChatboxInput chatboxInput);
/**
* Used to accept a request
*/
YES,
/**
* Currently unused response, treated like NO.
*/
IGNORE
boolean onPrivateMessageInput(PrivateMessageInput privateMessageInput);
}

View File

@@ -26,6 +26,8 @@
package net.runelite.client.chat;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
@@ -36,6 +38,7 @@ import net.runelite.api.events.CommandExecuted;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ChatboxInput;
import net.runelite.client.events.PrivateMessageInput;
@@ -52,20 +55,27 @@ public class CommandManager
private final ClientThread clientThread;
private boolean sending;
private final List<ChatboxInputListener> chatboxInputListenerList = new CopyOnWriteArrayList<>();
@Inject
private CommandManager(
final Client client,
final EventBus eventBus,
final ClientThread clientThread
)
private CommandManager(Client client, EventBus eventBus, ClientThread clientThread)
{
this.client = client;
this.eventBus = eventBus;
this.clientThread = clientThread;
eventBus.subscribe(ScriptCallbackEvent.class, this, this::onScriptCallbackEvent);
}
public void register(ChatboxInputListener chatboxInputListener)
{
chatboxInputListenerList.add(chatboxInputListener);
}
public void unregister(ChatboxInputListener chatboxInputListener)
{
chatboxInputListenerList.remove(chatboxInputListener);
}
@Subscribe
private void onScriptCallbackEvent(ScriptCallbackEvent event)
{
if (sending)
@@ -105,7 +115,7 @@ public class CommandManager
String[] args = Arrays.copyOfRange(split, 1, split.length);
CommandExecuted commandExecuted = new CommandExecuted(command, args);
eventBus.post(CommandExecuted.class, commandExecuted);
eventBus.post(commandExecuted);
}
private void handleInput(ScriptCallbackEvent event)
@@ -134,10 +144,13 @@ public class CommandManager
clientThread.invoke(() -> sendChatboxInput(chatType, typedText));
}
};
boolean stop = false;
for (ChatboxInputListener chatboxInputListener : chatboxInputListenerList)
{
stop |= chatboxInputListener.onChatboxInput(chatboxInput);
}
eventBus.post(ChatboxInput.class, chatboxInput);
if (chatboxInput.isStop())
if (stop)
{
// input was blocked.
stringStack[stringStackCount - 1] = ""; // prevent script from sending
@@ -171,9 +184,13 @@ public class CommandManager
}
};
eventBus.post(PrivateMessageInput.class, privateMessageInput);
boolean stop = false;
for (ChatboxInputListener chatboxInputListener : chatboxInputListenerList)
{
stop |= chatboxInputListener.onPrivateMessageInput(privateMessageInput);
}
if (privateMessageInput.isStop())
if (stop)
{
intStack[intStackCount - 1] = 1;
client.setStringStackSize(stringStackCount - 2); // remove both target and message

View File

@@ -37,4 +37,6 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Alpha {}
public @interface Alpha
{
}

View File

@@ -1,3 +0,0 @@
package net.runelite.client.config;
public class Button {}

View File

@@ -30,34 +30,28 @@ import net.runelite.client.ui.JagexColors;
@ConfigGroup("textrecolor")
public interface ChatColorConfig extends Config
{
@ConfigTitleSection(
keyName = "opaqueTitle",
@ConfigSection(
name = "Opaque",
description = "",
position = 1
description = "The options that control the colours for the Opaque Chatbox",
position = 0,
closedByDefault = true
)
default Title opaqueTitle()
{
return new Title();
}
String opaqueSection = "opaqueSection";
@ConfigTitleSection(
keyName = "transparentTitle",
@ConfigSection(
name = "Transparent",
description = "",
position = 1
description = "The options that control the colours for the Transparent Chatbox",
position = 50,
closedByDefault = true
)
default Title transparentTitle()
{
return new Title();
}
String transparentSection = "transparentSection";
@ConfigItem(
position = 1,
keyName = "opaquePublicChat",
name = "Public chat",
description = "Color of Public chat",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaquePublicChat();
@@ -66,7 +60,7 @@ public interface ChatColorConfig extends Config
keyName = "opaquePublicChatHighlight",
name = "Public chat highlight",
description = "Color of highlights in Public chat",
titleSection = "opaqueTitle"
section = opaqueSection
)
default Color opaquePublicChatHighlight()
{
@@ -78,7 +72,7 @@ public interface ChatColorConfig extends Config
keyName = "opaquePrivateMessageSent",
name = "Sent private messages",
description = "Color of Private messages you've sent",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaquePrivateMessageSent();
@@ -87,7 +81,7 @@ public interface ChatColorConfig extends Config
keyName = "opaquePrivateMessageSentHighlight",
name = "Sent private messages highlight",
description = "Color of highlights in Private messages you've sent",
titleSection = "opaqueTitle"
section = opaqueSection
)
default Color opaquePrivateMessageSentHighlight()
{
@@ -99,7 +93,7 @@ public interface ChatColorConfig extends Config
keyName = "opaquePrivateMessageReceived",
name = "Received private messages",
description = "Color of Private messages you've received",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaquePrivateMessageReceived();
@@ -108,7 +102,7 @@ public interface ChatColorConfig extends Config
keyName = "opaquePrivateMessageReceivedHighlight",
name = "Received private messages highlight",
description = "Color of highlights in Private messages you've received",
titleSection = "opaqueTitle"
section = opaqueSection
)
default Color opaquePrivateMessageReceivedHighlight()
{
@@ -120,7 +114,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueClanChatInfo",
name = "Friends chat info",
description = "Friends Chat Information (eg. when joining a channel)",
titleSection = "opaqueTitle"
section = opaqueSection
)
default Color opaqueFriendsChatInfo()
{
@@ -132,7 +126,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueClanChatInfoHighlight",
name = "Friends chat info highlight",
description = "Friends Chat Information highlight (used for the Raids plugin)",
titleSection = "opaqueTitle"
section = opaqueSection
)
default Color opaqueFriendsChatInfoHighlight()
{
@@ -144,7 +138,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueClanChatMessage",
name = "Friends chat message",
description = "Color of Friends chat messages",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueFriendsChatMessage();
@@ -153,7 +147,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueClanChatMessageHighlight",
name = "Friends chat message highlight",
description = "Color of highlights in Friends Chat messages",
titleSection = "opaqueTitle"
section = opaqueSection
)
default Color opaqueFriendsChatMessageHighlight()
{
@@ -165,7 +159,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueAutochatMessage",
name = "Autochat",
description = "Color of Autochat messages",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueAutochatMessage();
@@ -174,7 +168,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueAutochatMessageHighlight",
name = "Autochat highlight",
description = "Color of highlights in Autochat messages",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueAutochatMessageHighlight();
@@ -183,7 +177,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueTradeChatMessage",
name = "Trade chat",
description = "Color of Trade Chat Messages",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueTradeChatMessage();
@@ -192,7 +186,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueTradeChatMessageHighlight",
name = "Trade chat highlight",
description = "Color of highlights in Trade Chat Messages",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueTradeChatMessageHighlight();
@@ -201,7 +195,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueServerMessage",
name = "Server message",
description = "Color of Server Messages (eg. 'Welcome to RuneScape')",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueServerMessage();
@@ -210,7 +204,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueServerMessageHighlight",
name = "Server message highlight",
description = "Color of highlights in Server Messages",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueServerMessageHighlight();
@@ -219,7 +213,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueGameMessage",
name = "Game message",
description = "Color of Game Messages",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueGameMessage();
@@ -228,7 +222,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueGameMessageHighlight",
name = "Game message highlight",
description = "Color of highlights in Game Messages",
titleSection = "opaqueTitle"
section = opaqueSection
)
default Color opaqueGameMessageHighlight()
{
@@ -240,7 +234,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueExamine",
name = "Examine",
description = "Color of Examine Text",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueExamine();
@@ -249,7 +243,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueExamineHighlight",
name = "Examine highlight",
description = "Color of highlights in Examine Text",
titleSection = "opaqueTitle"
section = opaqueSection
)
default Color opaqueExamineHighlight()
{
@@ -261,7 +255,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueFiltered",
name = "Filtered",
description = "Color of Filtered Text (messages that aren't shown when Game messages are filtered)",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueFiltered();
@@ -270,7 +264,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueFilteredHighlight",
name = "Filtered highlight",
description = "Color of highlights in Filtered Text",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueFilteredHighlight();
@@ -279,7 +273,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueUsername",
name = "Usernames",
description = "Color of Usernames",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueUsername();
@@ -288,7 +282,7 @@ public interface ChatColorConfig extends Config
keyName = "opaquePrivateUsernames",
name = "Private chat usernames",
description = "Color of Usernames in Private Chat",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaquePrivateUsernames();
@@ -297,7 +291,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueClanChannelName",
name = "Friends chat channel name",
description = "Color of Friends chat channel name",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueFriendsChatChannelName();
@@ -306,7 +300,7 @@ public interface ChatColorConfig extends Config
keyName = "opaqueClanUsernames",
name = "Friends chat usernames",
description = "Color of usernames in Friends chat",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaqueFriendsChatUsernames();
@@ -315,7 +309,7 @@ public interface ChatColorConfig extends Config
keyName = "opaquePublicFriendUsernames",
name = "Public friend usernames",
description = "Color of Friend Usernames in Public Chat",
titleSection = "opaqueTitle"
section = opaqueSection
)
Color opaquePublicFriendUsernames();
@@ -324,7 +318,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentPublicChat",
name = "Public chat (transparent)",
description = "Color of Public chat (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentPublicChat();
@@ -333,7 +327,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentPublicChatHighlight",
name = "Public chat highlight (transparent)",
description = "Color of highlights in Public chat (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
default Color transparentPublicChatHighlight()
{
@@ -345,7 +339,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentPrivateMessageSent",
name = "Sent private messages (transparent)",
description = "Color of Private messages you've sent (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentPrivateMessageSent();
@@ -354,7 +348,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentPrivateMessageSentHighlight",
name = "Sent private messages highlight (transparent)",
description = "Color of highlights in Private messages you've sent (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
default Color transparentPrivateMessageSentHighlight()
{
@@ -366,7 +360,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentPrivateMessageReceived",
name = "Received private messages (transparent)",
description = "Color of Private messages you've received (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentPrivateMessageReceived();
@@ -375,7 +369,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentPrivateMessageReceivedHighlight",
name = "Received private messages highlight (transparent)",
description = "Color of highlights in Private messages you've received (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
default Color transparentPrivateMessageReceivedHighlight()
{
@@ -387,7 +381,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentClanChatInfo",
name = "Friends chat info (transparent)",
description = "Friends chat information (eg. when joining a channel) (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
default Color transparentFriendsChatInfo()
{
@@ -399,7 +393,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentClanChatInfoHighlight",
name = "Friends chat info highlight (transparent)",
description = "Friends chat information highlight (used for the Raids plugin) (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
default Color transparentFriendsChatInfoHighlight()
{
@@ -411,7 +405,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentClanChatMessage",
name = "Friends chat message (transparent)",
description = "Color of Friends chat messages (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentFriendsChatMessage();
@@ -420,7 +414,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentClanChatMessageHighlight",
name = "Friends chat message highlight (transparent)",
description = "Color of highlights in Friends chat messages (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
default Color transparentFriendsChatMessageHighlight()
{
@@ -432,7 +426,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentAutochatMessage",
name = "Autochat (transparent)",
description = "Color of Autochat messages (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentAutochatMessage();
@@ -441,7 +435,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentAutochatMessageHighlight",
name = "Autochat highlight (transparent)",
description = "Color of highlights in Autochat messages (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentAutochatMessageHighlight();
@@ -450,7 +444,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentTradeChatMessage",
name = "Trade chat (transparent)",
description = "Color of Trade Chat Messages (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentTradeChatMessage();
@@ -459,7 +453,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentTradeChatMessageHighlight",
name = "Trade chat highlight (transparent)",
description = "Color of highlights in Trade Chat Messages (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentTradeChatMessageHighlight();
@@ -468,7 +462,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentServerMessage",
name = "Server message (transparent)",
description = "Color of Server Messages (eg. 'Welcome to RuneScape') (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentServerMessage();
@@ -477,7 +471,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentServerMessageHighlight",
name = "Server message highlight (transparent)",
description = "Color of highlights in Server Messages (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentServerMessageHighlight();
@@ -486,7 +480,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentGameMessage",
name = "Game message (transparent)",
description = "Color of Game Messages (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentGameMessage();
@@ -495,7 +489,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentGameMessageHighlight",
name = "Game message highlight (transparent)",
description = "Color of highlights in Game Messages (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
default Color transparentGameMessageHighlight()
{
@@ -507,7 +501,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentExamine",
name = "Examine (transparent)",
description = "Color of Examine Text (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentExamine();
@@ -516,7 +510,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentExamineHighlight",
name = "Examine highlight (transparent)",
description = "Color of highlights in Examine Text (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
default Color transparentExamineHighlight()
{
@@ -528,7 +522,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentFiltered",
name = "Filtered (transparent)",
description = "Color of Filtered Text (messages that aren't shown when Game messages are filtered) (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentFiltered();
@@ -537,7 +531,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentFilteredHighlight",
name = "Filtered highlight (transparent)",
description = "Color of highlights in Filtered Text (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentFilteredHighlight();
@@ -546,7 +540,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentUsername",
name = "Usernames (transparent)",
description = "Color of Usernames (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentUsername();
@@ -555,7 +549,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentPrivateUsernames",
name = "Private chat usernames (transparent)",
description = "Color of Usernames in Private Chat (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentPrivateUsernames();
@@ -564,7 +558,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentClanChannelName",
name = "Friends chat channel name (transparent)",
description = "Color of Friends chat channel name (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentFriendsChatChannelName();
@@ -573,7 +567,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentClanUsernames",
name = "Friends chat usernames (transparent)",
description = "Color of usernames in Friends chat (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentFriendsChatUsernames();
@@ -582,7 +576,7 @@ public interface ChatColorConfig extends Config
keyName = "transparentPublicFriendUsernames",
name = "Public friend usernames (transparent)",
description = "Color of Friend Usernames in Public Chat (transparent)",
titleSection = "transparentTitle"
section = transparentSection
)
Color transparentPublicFriendUsernames();
}

View File

@@ -24,4 +24,6 @@
*/
package net.runelite.client.config;
public interface Config {}
public interface Config
{
}

View File

@@ -24,22 +24,20 @@
*/
package net.runelite.client.config;
import java.util.Collection;
import lombok.Getter;
import java.util.Collection;
@Getter
public class ConfigDescriptor
{
private final ConfigGroup group;
private final Collection<ConfigSection> sections;
private final Collection<ConfigTitleSection> titleSections;
private final Collection<ConfigSectionDescriptor> sections;
private final Collection<ConfigItemDescriptor> items;
public ConfigDescriptor(ConfigGroup group, Collection<ConfigSection> sections, Collection<ConfigTitleSection> titleSections, Collection<ConfigItemDescriptor> items)
public ConfigDescriptor(ConfigGroup group, Collection<ConfigSectionDescriptor> sections, Collection<ConfigItemDescriptor> items)
{
this.group = group;
this.sections = sections;
this.titleSections = titleSections;
this.items = items;
}
}
}

View File

@@ -26,11 +26,11 @@ package net.runelite.client.config;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.util.ReflectUtil;
@Slf4j
class ConfigInvocationHandler implements InvocationHandler
@@ -100,7 +100,7 @@ class ConfigInvocationHandler implements InvocationHandler
// Convert value to return type
Class<?> returnType = method.getReturnType();
try
{
Object objectValue = ConfigManager.stringToObject(value, returnType);
@@ -112,11 +112,7 @@ class ConfigInvocationHandler implements InvocationHandler
log.warn("Unable to unmarshal {}.{} ", group.value(), item.keyName(), e);
if (method.isDefault())
{
Object defaultValue = callDefaultMethod(proxy, method, null);
manager.setConfiguration(group.value(), item.keyName(), defaultValue);
return defaultValue;
return callDefaultMethod(proxy, method, null);
}
return null;
}
@@ -127,7 +123,7 @@ class ConfigInvocationHandler implements InvocationHandler
if (args.length != 1)
{
throw new RuntimeException("Invalid number of arguents to configuration method");
throw new RuntimeException("Invalid number of arguments to configuration method");
}
Object newValue = args[0];
@@ -169,7 +165,7 @@ class ConfigInvocationHandler implements InvocationHandler
static Object callDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable
{
Class<?> declaringClass = method.getDeclaringClass();
return MethodHandles.privateLookupIn(declaringClass, MethodHandles.lookup())
return ReflectUtil.privateLookupIn(declaringClass)
.unreflectSpecial(method, declaringClass)
.bindTo(proxy)
.invokeWithArguments(args);
@@ -180,4 +176,4 @@ class ConfigInvocationHandler implements InvocationHandler
log.trace("cache invalidate");
cache.invalidateAll();
}
}
}

View File

@@ -33,143 +33,19 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
public @interface ConfigItem
{
/**
* If there is a section set, it will display in order
* starting from lowest value and ending at highest value
* in that specific section. Else, it will display in order
* for the config panel in a whole.
*
* @return The index of the config item.
*/
int position() default -1;
/**
* This is not visible to users
*
* @return name used for finding the config item
* from the properties map. Hence, KEY name.
*/
String keyName();
/**
* This is the name that is shown to users when looking
* at the config panel.
* <p>
* Choose a name carefully, as there is a maximum width
* that depends on the users DPI scaling. Short is best.
*
* @return display name for the config item.
*/
String name();
/**
* This will be shown to the user if they are hovering
* the config item in the config panel.
*
* @return the description of the config item.
*/
String description();
/**
* If this is set to true, the config field will be
* hidden. You are able to change this value at runtime
* by having another config field unhide it {@link #unhide()}
*/
boolean hidden() default false;
/**
* This is only used for {@link Boolean} config fields.
* <p>
* If this is set, then a warning(y/n) will be displayed
* when the user enables said config field. If they accept
* then the value will be set updated.
*
* @return a warning for enabling the config field.
*/
String warning() default "";
/**
* This is only used for {@link String} config fields.
* <p>
* If this is set to true, any input from the user
* will be hidden, and not displayed. This should
* be used for any sensitive information that may
* be accidentally leaked.
* <p>
* For example; api keys.
*/
boolean secret() default false;
/**
* If this is set, it will look for a section
* by that {@link ConfigSection#name()}, if it exists,
* it will insert the config item under that
* section in order.
*
* @return title of the section.
*/
String section() default "";
/**
* If this is set, it will look for a title section
* by that {@link ConfigTitleSection#name()}, if it exists,
* it will insert the config item under that
* section in order.
*
* @return title of the section.
*/
String titleSection() default "";
/**
* If this is set, it will look for a config item
* by that name. If it is hidden, it will unhide the item.
*
* @return {@link #name()} to unhide.
*/
String unhide() default "";
String unhideValue() default "";
/**
* If this is set, it will look for a config item
* by that name. If it is not hidden, it will hide the item.
*
* @return {@link #name()} to hide.
*/
String hide() default "";
String hideValue() default "";
/**
* If this is set, it will look for a config item
* by the name provided, if that config item is enabled
* then this item will also be enabled.
*/
String enabledBy() default "";
String enabledByValue() default "";
/**
* If this is set, it will look for a config item
* by the name provided, if that config item is disabled
* then this item will also be disabled.
*/
String disabledBy() default "";
String disabledByValue() default "";
boolean parse() default false;
Class<?> clazz() default void.class;
String method() default "";
/**
* Use this to indicate the enum class that is going to be used in the multiple select config.
* This implementation made debugging problems with multiple selects a lot easier
*
* @return The Enum that will be used for the multiple select
*/
Class<? extends Enum> enumClass() default Enum.class;
}

View File

@@ -27,11 +27,29 @@ package net.runelite.client.config;
import lombok.Value;
@Value
public class ConfigItemDescriptor
public class ConfigItemDescriptor implements ConfigObject
{
private final ConfigItem item;
private final Class<?> type;
private final Range range;
private final Alpha alpha;
private final Units units;
@Override
public String key()
{
return item.keyName();
}
@Override
public String name()
{
return item.name();
}
@Override
public int position()
{
return item.position();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* Copyright (c) 2020, Hydrox6 <ikada@protonmail.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,11 +22,11 @@
* (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.ui.overlay.components.table;
package net.runelite.client.config;
public enum TableAlignment
public interface ConfigObject
{
LEFT,
CENTER,
RIGHT
String key();
String name();
int position();
}

View File

@@ -30,79 +30,14 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Target(ElementType.FIELD)
public @interface ConfigSection
{
/**
* Displayed position of the section.
*
* @return The index of the section.
*/
int position();
/**
* This is not visible to users
*
* @return name used for finding the config section
* from the properties map. Hence, KEY name.
*/
String keyName();
/**
* This is the name that is shown to users when looking
* at the config panel.
* <p>
* Choose a name carefully, as there is a maximum width
* that depends on the users DPI scaling. Short is best.
*
* @return display name for the config section.
*/
String name();
/**
* This will be shown to the user if they are hovering
* the config item in the config panel.
*
* @return the description of the config item.
*/
String description();
/**
* Setting this will tell the panel
* that this section should be placed beneath
* said section.
*
* @return parent section.
*/
String section() default "";
int position();
/**
* NOT USED.
*/
String titleSection() default "";
/**
* NOT USED.
*/
boolean hidden() default false;
/**
* NOT USED.
*/
String unhide() default "";
/**
* NOT USED.
*/
String unhideValue() default "";
/**
* NOT USED.
*/
String hide() default "";
/**
* NOT USED.
*/
String hideValue() default "";
boolean closedByDefault() default false;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Woox <https://github.com/wooxsolo>
* Copyright (c) 2020, Hydrox6 <ikada@protonmail.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,15 +22,31 @@
* (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.graphics;
package net.runelite.client.config;
import lombok.RequiredArgsConstructor;
import lombok.Value;
@Value
@RequiredArgsConstructor
class PixelDistanceAlpha
public class ConfigSectionDescriptor implements ConfigObject
{
private final int outerAlpha;
private final int distArrayPos;
private final String key;
private final ConfigSection section;
@Override
public String key()
{
return key;
}
@Override
public String name()
{
return section.name();
}
@Override
public int position()
{
return section.position();
}
}

View File

@@ -1,112 +0,0 @@
/*
* Copyright (c) 2019, Hydrox6 <ikada@protonmail.ch>
* 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.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ConfigTitleSection
{
/**
* Displayed position of the title section.
*
* @return The index of the title section.
*/
int position();
/**
* This is not visible to users
*
* @return name used for finding the config section
* from the properties map. Hence, KEY name.
*/
String keyName();
/**
* This is the name that is shown to users when looking
* at the config panel.
* <p>
* Choose a name carefully, as there is a maximum width
* that depends on the users DPI scaling. Short is best.
*
* @return display name for the config title section.
*/
String name();
/**
* This will be shown to the user if they are hovering
* the config item in the config panel.
*
* @return the description of the config item.
*/
String description();
/**
* Setting this will tell the panel
* that this title should be placed beneath
* said section.
*
* @return parent section.
*/
String section() default "";
/**
* Setting this will tell the panel
* that this title should be placed beneath
* said title.
*
* @return parent title section.
*/
String titleSection() default "";
/**
* NOT USED.
*/
boolean hidden() default false;
/**
* NOT USED.
*/
String unhide() default "";
/**
* NOT USED.
*/
String unhideValue() default "";
/**
* NOT USED.
*/
String hide() default "";
/**
* NOT USED.
*/
String hideValue() default "";
}

View File

@@ -24,11 +24,12 @@
*/
package net.runelite.client.config;
import java.awt.Font;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Getter;
import net.runelite.client.ui.FontManager;
import java.awt.Font;
@Getter
@RequiredArgsConstructor
public enum FontType

View File

@@ -60,7 +60,7 @@ public class Keybind
private final int keyCode;
private final int modifiers;
Keybind(int keyCode, int modifiers, boolean ignoreModifiers)
protected Keybind(int keyCode, int modifiers, boolean ignoreModifiers)
{
modifiers &= KEYBOARD_MODIFIER_MASK;
@@ -108,7 +108,7 @@ public class Keybind
return matches(e, false);
}
boolean matches(KeyEvent e, boolean ignoreModifiers)
protected boolean matches(KeyEvent e, boolean ignoreModifiers)
{
if (NOT_SET.equals(this))
{
@@ -177,7 +177,7 @@ public class Keybind
return mod;
}
private static String getModifiersExText(int modifiers)
public static String getModifiersExText(int modifiers)
{
StringBuilder buf = new StringBuilder();
if ((modifiers & InputEvent.META_DOWN_MASK) != 0)

View File

@@ -1,174 +0,0 @@
/*
* Copyright (c) 2019 Owain van Brakel <https://github.com/Owain94>
* 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.config;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ConfigGroup("openosrs")
public interface LauncherConfig extends Config
{
@Getter(AccessLevel.PRIVATE)
@AllArgsConstructor
enum BootstrapMode
{
STABLE("Stable"),
NIGHTLY("Nightly");
private String name;
@Override
public String toString()
{
return getName();
}
}
@ConfigTitleSection(
keyName = "launcherTitle",
name = "Launcher",
description = "",
position = -1
)
default Title launcherTitle()
{
return new Title();
}
@ConfigTitleSection(
keyName = "updateChannelTitle",
name = "Update channel",
description = "",
position = 1,
titleSection = "launcherTitle"
)
default Title updateChannelTitle()
{
return new Title();
}
@ConfigItem(
position = 2,
keyName = "askMode",
name = "Prompt for update channel",
description = "Ask for nightly or stable every startup",
titleSection = "updateChannelTitle"
)
default boolean askMode()
{
return true;
}
@ConfigItem(
keyName = "bootstrapMode",
name = "Update channel",
description = "Select the update channel",
titleSection = "updateChannelTitle",
position = 3,
hide = "askMode"
)
default BootstrapMode bootstrapMode()
{
return BootstrapMode.STABLE;
}
@ConfigTitleSection(
keyName = "miscLauncherTitle",
name = "Miscellaneous",
description = "",
position = 4,
titleSection = "launcherTitle"
)
default Title miscLauncherTitle()
{
return new Title();
}
@ConfigItem(
position = 5,
keyName = "disableHw",
name = "Disable hardware acceleration",
description = "Enable this if you have graphical issues",
titleSection = "miscLauncherTitle",
warning = "Toggling this setting requires a restart of the client"
)
default boolean disableHw()
{
return false;
}
@ConfigTitleSection(
keyName = "advancedTitle",
name = "Advanced",
description = "",
position = 6,
titleSection = "launcherTitle"
)
default Title advancedTitle()
{
return new Title();
}
@ConfigItem(
position = 7,
keyName = "noJvm",
name = "Use system java (caution!)",
description = "Enable this if you want to make use of the system java version instead of the launcher bundled version",
titleSection = "advancedTitle",
warning = "Toggling this setting requires a restart of the client"
)
default boolean noJvm()
{
return false;
}
@ConfigItem(
position = 8,
keyName = "useProxy",
name = "Use SOCKS5 proxy",
description = "Enable the client to use a proxy",
titleSection = "advancedTitle",
warning = "Toggling this setting requires a restart of the client"
)
default boolean useProxy()
{
return false;
}
@ConfigItem(
keyName = "proxyDetails",
name = "Proxy details",
description = "The format for this field is ip:port or ip:port:user:pass",
titleSection = "advancedTitle",
position = 9,
hidden = true,
unhide = "useProxy"
)
default String proxyDetails()
{
return "";
}
}

View File

@@ -1,373 +0,0 @@
/*
*
* Copyright (c) 2019, Zeruth <TheRealNull@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.config;
import java.awt.Color;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.client.plugins.ExternalPluginManager;
@ConfigGroup("openosrs")
public interface OpenOSRSConfig extends Config
{
@Getter(AccessLevel.PUBLIC)
@AllArgsConstructor
enum SortStyle
{
CATEGORY("Category"),
ALPHABETICALLY("Alphabetically"),
REPOSITORY("Repository");
private String name;
@Override
public String toString()
{
return getName();
}
}
@ConfigTitleSection(
keyName = "logTitle",
name = "Error data",
description = "",
position = 1
)
default Title logTitle()
{
return new Title();
}
@ConfigItem(
position = 3,
keyName = "shareLogs",
name = "Share anonymous error data",
description = "Share anonymous error data with the OpenOSRS developers",
titleSection = "logTitle"
)
default boolean shareLogs()
{
return true;
}
@ConfigTitleSection(
keyName = "pluginsTitle",
name = "Plugins",
description = "",
position = 1
)
default Title pluginsTitle()
{
return new Title();
}
@ConfigTitleSection(
keyName = "pluginSortingTitle",
name = "Sorting",
description = "",
position = 2,
titleSection = "pluginsTitle"
)
default Title pluginSortingTitle()
{
return new Title();
}
@ConfigItem(
position = 3,
keyName = "pluginSortMode",
name = "Sorting mode",
description = "Sorts plugins ",
titleSection = "pluginSortingTitle"
)
default SortStyle pluginSortMode()
{
return SortStyle.CATEGORY;
}
@ConfigItem(
position = 4,
keyName = "enableCategories",
name = "Categorize plugins",
description = "Show sections in the plugin list for each plugin type",
titleSection = "pluginSortingTitle",
hidden = true,
unhide = "pluginSortMode",
unhideValue = "Category"
)
default boolean enableCategories()
{
return true;
}
@ConfigTitleSection(
keyName = "pluginsColorTitle",
name = "Colors",
description = "",
position = 5,
titleSection = "pluginsTitle"
)
default Title pluginsColorTitle()
{
return new Title();
}
@ConfigItem(
position = 6,
keyName = "enabledColors",
name = "Enable plugin colors",
description = "Configure whether or not the plugins list should be colorcoded",
titleSection = "pluginsColorTitle"
)
default boolean enabledColors()
{
return true;
}
@Alpha
@ConfigItem(
position = 7,
keyName = "pvmColor",
name = "PvM color",
description = "Configure the color of PvM related plugins",
titleSection = "pluginsColorTitle",
hidden = true,
unhide = "enabledColors"
)
default Color pvmColor()
{
return new Color(119, 221, 119, 255);
}
@Alpha
@ConfigItem(
position = 8,
keyName = "skillingColor",
name = "Skilling color",
description = "Configure the color of skilling related plugins",
titleSection = "pluginsColorTitle",
hidden = true,
unhide = "enabledColors"
)
default Color skillingColor()
{
return new Color(252, 252, 100, 255);
}
@Alpha
@ConfigItem(
position = 9,
keyName = "pvpColor",
name = "PvP color",
description = "Configure the color of PvP related plugins",
titleSection = "pluginsColorTitle",
hidden = true,
unhide = "enabledColors"
)
default Color pvpColor()
{
return new Color(255, 105, 97, 255);
}
@Alpha
@ConfigItem(
position = 10,
keyName = "utilityColor",
name = "Utility color",
description = "Configure the color of utility related plugins",
titleSection = "pluginsColorTitle",
hidden = true,
unhide = "enabledColors"
)
default Color utilityColor()
{
return new Color(144, 212, 237, 255);
}
@Alpha
@ConfigItem(
position = 11,
keyName = "minigameColor",
name = "Minigame color",
description = "Configure the color of minigame related plugins",
titleSection = "pluginsColorTitle",
hidden = true,
unhide = "enabledColors"
)
default Color minigameColor()
{
return new Color(235, 130, 66, 255);
}
@Alpha
@ConfigItem(
position = 12,
keyName = "miscellaneousColor",
name = "Miscellaneous color",
description = "Configure the color of miscellaneous related plugins",
titleSection = "pluginsColorTitle",
hidden = true,
unhide = "enabledColors"
)
default Color miscellaneousColor()
{
return new Color(243, 85, 136, 255);
}
@Alpha
@ConfigItem(
position = 13,
keyName = "gamemodeColor",
name = "Gamemode color",
description = "Configure the color of gamemode plugins",
titleSection = "pluginsColorTitle",
hidden = true,
unhide = "enabledColors"
)
default Color gamemodeColor()
{
return new Color(244, 239, 211, 255);
}
@ConfigTitleSection(
keyName = "opacityTitle",
name = "Opacity",
description = "",
position = 17
)
default Title opacityTitle()
{
return new Title();
}
@ConfigItem(
keyName = "enableOpacity",
name = "Enable opacity",
description = "Enables opacity for the whole window.<br>NOTE: This only stays enabled if your pc supports this!",
position = 18,
titleSection = "opacityTitle"
)
default boolean enableOpacity()
{
return false;
}
@Range(
min = 15,
max = 100
)
@ConfigItem(
keyName = "opacityPercentage",
name = "Opacity percentage",
description = "Changes the opacity of the window if opacity is enabled",
position = 19,
titleSection = "opacityTitle"
)
@Units(Units.PERCENT)
default int opacityPercentage()
{
return 100;
}
@ConfigTitleSection(
keyName = "miscTitle",
name = "Miscellaneous",
description = "",
position = 20
)
default Title miscTitle()
{
return new Title();
}
@ConfigItem(
keyName = "localSync",
name = "Sync local instances",
description = "Enables multiple local instances of OpenOSRS to communicate (this enables syncing plugin state and config options)",
position = 21,
titleSection = "miscTitle"
)
default boolean localSync()
{
return true;
}
@ConfigItem(
keyName = "keyboardPin",
name = "Keyboard bank pin",
description = "Enables you to type your bank pin",
position = 22,
titleSection = "miscTitle"
)
default boolean keyboardPin()
{
return false;
}
@ConfigItem(
keyName = "detachHotkey",
name = "Detach Cam",
description = "Detach Camera hotkey, press this and it will activate detatched camera.",
position = 23,
titleSection = "miscTitle"
)
default Keybind detachHotkey()
{
return Keybind.NOT_SET;
}
@ConfigItem(
keyName = "externalRepositories",
name = "",
description = "",
hidden = true
)
default String getExternalRepositories()
{
return ExternalPluginManager.DEFAULT_PLUGIN_REPOS;
}
@ConfigItem(
keyName = "externalRepositories",
name = "",
description = "",
hidden = true
)
void setExternalRepositories(String val);
@ConfigItem(
keyName = "warning",
name = "",
description = "",
hidden = true
)
default boolean warning()
{
return true;
}
}

View File

@@ -38,25 +38,34 @@ public interface RuneLiteConfig extends Config
{
String GROUP_NAME = "runelite";
@ConfigTitleSection(
keyName = "uiTitle",
name = "User interface",
description = "",
@ConfigSection(
name = "Window Settings",
description = "Settings relating to the client's window and frame",
position = 0
)
String windowSettings = "windowSettings";
@ConfigSection(
name = "Notification Settings",
description = "Settings relating to notifications",
position = 1
)
default Title uiTitle()
{
return new Title();
}
String notificationSettings = "notificationSettings";
@ConfigSection(
name = "Overlay Settings",
description = "Settings relating to fonts",
position = 2
)
String overlaySettings = "overlaySettings";
@ConfigItem(
keyName = "gameSize",
name = "Game size",
description = "The game will resize to this resolution upon starting the client",
position = 2,
titleSection = "uiTitle"
position = 10,
section = windowSettings
)
@Units(Units.PIXELS)
default Dimension gameSize()
{
return Constants.GAME_FIXED_SIZE;
@@ -66,8 +75,8 @@ public interface RuneLiteConfig extends Config
keyName = "automaticResizeType",
name = "Resize type",
description = "Choose how the window should resize when opening and closing panels",
position = 3,
titleSection = "uiTitle"
position = 11,
section = windowSettings
)
default ExpandResizeType automaticResizeType()
{
@@ -78,8 +87,8 @@ public interface RuneLiteConfig extends Config
keyName = "lockWindowSize",
name = "Lock window size",
description = "Determines if the window resizing is allowed or not",
position = 4,
titleSection = "uiTitle"
position = 12,
section = windowSettings
)
default boolean lockWindowSize()
{
@@ -90,82 +99,61 @@ public interface RuneLiteConfig extends Config
keyName = "containInScreen2",
name = "Contain in screen",
description = "Makes the client stay contained in the screen when attempted to move out of it.<br>Note: 'Always' only works if custom chrome is enabled.",
position = 5,
titleSection = "uiTitle"
position = 13,
section = windowSettings
)
default ContainableFrame.Mode containInScreen()
{
return ContainableFrame.Mode.RESIZING;
}
@ConfigItem(
keyName = "uiEnableCustomChrome",
name = "Enable custom window chrome",
description = "Use Runelite's custom window title and borders.",
warning = "Please restart your client after changing this setting.",
position = 6,
titleSection = "uiTitle"
)
default boolean enableCustomChrome()
{
return true;
}
@ConfigItem(
keyName = "borderless",
name = "Windowed borderless",
description = "Use windowed borderless mode",
warning = "Please restart your client after changing this setting.",
position = 7,
titleSection = "uiTitle"
)
default boolean borderless()
{
return false;
}
@ConfigItem(
keyName = "usernameInTitle",
name = "Show display name in title",
description = "Toggles displaying of local player's display name in client title",
position = 8,
titleSection = "uiTitle"
)
default boolean usernameInTitle()
{
return true;
}
@ConfigTitleSection(
keyName = "miscTitle",
name = "Miscellaneous",
description = "",
position = 9
)
default Title miscTitle()
{
return new Title();
}
@ConfigItem(
keyName = "rememberScreenBounds",
name = "Remember client position",
description = "Save the position and size of the client after exiting",
position = 10,
titleSection = "miscTitle"
position = 14,
section = windowSettings
)
default boolean rememberScreenBounds()
{
return true;
}
@ConfigItem(
keyName = "uiEnableCustomChrome",
name = "Enable custom window chrome",
description = "Use Runelite's custom window title and borders.",
warning = "Please restart your client after changing this setting",
position = 15,
section = windowSettings
)
default boolean enableCustomChrome()
{
return true;
}
@Range(
min = 10,
max = 100
)
@ConfigItem(
keyName = "uiWindowOpacity",
name = "Window opacity",
description = "Set the windows opacity. Requires \"Enable custom window chrome\" to be enabled.",
position = 16,
section = windowSettings
)
default int windowOpacity()
{
return 100;
}
@ConfigItem(
keyName = "gameAlwaysOnTop",
name = "Enable client always on top",
description = "The game will always be on the top of the screen",
position = 11,
titleSection = "miscTitle"
position = 17,
section = windowSettings
)
default boolean gameAlwaysOnTop()
{
@@ -176,57 +164,32 @@ public interface RuneLiteConfig extends Config
keyName = "warningOnExit",
name = "Display warning on exit",
description = "Toggles a warning popup when trying to exit the client",
position = 12,
titleSection = "miscTitle"
position = 18,
section = windowSettings
)
default WarningOnExit warningOnExit()
{
return WarningOnExit.LOGGED_IN;
}
@Range(max = 100, min = 0)
@ConfigItem(
keyName = "volume",
name = "Runelite Volume",
description = "Sets the volume of custom Runelite sounds (not the client sounds)",
position = 13,
titleSection = "miscTitle"
keyName = "usernameInTitle",
name = "Show display name in title",
description = "Toggles displaying of local player's display name in client title",
position = 19,
section = windowSettings
)
@Units(Units.PERCENT)
default int volume()
default boolean usernameInTitle()
{
return 100;
}
@ConfigItem(
keyName = "tooltipPosition",
name = "Tooltip Position",
description = "Configures whether to show the tooltip above or under the cursor",
position = 14,
titleSection = "miscTitle"
)
default TooltipPositionType tooltipPosition()
{
return TooltipPositionType.UNDER_CURSOR;
}
@ConfigTitleSection(
keyName = "notificationsTitle",
name = "Notifications",
description = "",
position = 15
)
default Title notificationsTitle()
{
return new Title();
return true;
}
@ConfigItem(
keyName = "notificationTray",
name = "Enable tray notifications",
description = "Enables tray notifications",
position = 16,
titleSection = "notificationsTitle"
position = 20,
section = notificationSettings
)
default boolean enableTrayNotifications()
{
@@ -237,8 +200,8 @@ public interface RuneLiteConfig extends Config
keyName = "notificationRequestFocus",
name = "Request focus on notification",
description = "Configures the window focus request type on notification",
position = 17,
titleSection = "notificationsTitle"
position = 21,
section = notificationSettings
)
default RequestFocusType notificationRequestFocus()
{
@@ -249,8 +212,8 @@ public interface RuneLiteConfig extends Config
keyName = "notificationSound",
name = "Notification sound",
description = "Enables the playing of a beep sound when notifications are displayed",
position = 18,
titleSection = "notificationsTitle"
position = 22,
section = notificationSettings
)
default Notifier.NativeCustomOff notificationSound()
{
@@ -261,8 +224,8 @@ public interface RuneLiteConfig extends Config
keyName = "notificationGameMessage",
name = "Enable game message notifications",
description = "Puts a notification message in the chatbox",
position = 19,
titleSection = "notificationsTitle"
position = 23,
section = notificationSettings
)
default boolean enableGameMessageNotification()
{
@@ -270,11 +233,11 @@ public interface RuneLiteConfig extends Config
}
@ConfigItem(
keyName = "notificationFlash",
name = "Enable flash notification",
keyName = "flashNotification",
name = "Flash notification",
description = "Flashes the game frame as a notification",
position = 20,
titleSection = "notificationsTitle"
position = 24,
section = notificationSettings
)
default FlashNotification flashNotification()
{
@@ -285,8 +248,8 @@ public interface RuneLiteConfig extends Config
keyName = "notificationFocused",
name = "Send notifications when focused",
description = "Toggles all notifications for when the client is focused",
position = 21,
titleSection = "notificationsTitle"
position = 25,
section = notificationSettings
)
default boolean sendNotificationsWhenFocused()
{
@@ -298,31 +261,20 @@ public interface RuneLiteConfig extends Config
keyName = "notificationFlashColor",
name = "Notification Flash Color",
description = "Sets the color of the notification flashes.",
position = 22,
titleSection = "notificationsTitle"
position = 26,
section = notificationSettings
)
default Color notificationFlashColor()
{
return new Color(255, 0, 0, 70);
}
@ConfigTitleSection(
keyName = "fontTitle",
name = "Font",
description = "",
position = 23
)
default Title fontTitle()
{
return new Title();
}
@ConfigItem(
keyName = "fontType",
name = "Dynamic Overlay Font",
description = "Configures what font type is used for in-game overlays such as player name, ground items, etc.",
position = 24,
titleSection = "fontTitle"
position = 30,
section = overlaySettings
)
default FontType fontType()
{
@@ -333,8 +285,8 @@ public interface RuneLiteConfig extends Config
keyName = "tooltipFontType",
name = "Tooltip Font",
description = "Configures what font type is used for in-game tooltips such as food stats, NPC names, etc.",
position = 25,
titleSection = "fontTitle"
position = 31,
section = overlaySettings
)
default FontType tooltipFontType()
{
@@ -345,31 +297,20 @@ public interface RuneLiteConfig extends Config
keyName = "interfaceFontType",
name = "Interface Overlay Font",
description = "Configures what font type is used for in-game interface overlays such as panels, opponent info, clue scrolls etc.",
position = 26,
titleSection = "fontTitle"
position = 32,
section = overlaySettings
)
default FontType interfaceFontType()
{
return FontType.REGULAR;
}
@ConfigTitleSection(
keyName = "overlayTitle",
name = "Overlays",
description = "",
position = 27
)
default Title overlayTitle()
{
return new Title();
}
@ConfigItem(
keyName = "menuEntryShift",
name = "Require Shift for overlay menu",
description = "Overlay right-click menu will require shift to be added",
position = 28,
titleSection = "overlayTitle"
position = 33,
section = overlaySettings
)
default boolean menuEntryShift()
{
@@ -377,47 +318,23 @@ public interface RuneLiteConfig extends Config
}
@ConfigItem(
keyName = "overlayBackgroundColor",
name = "Overlay Color",
description = "Configures the background color of infoboxes and overlays",
position = 29,
titleSection = "overlayTitle"
keyName = "tooltipPosition",
name = "Tooltip Position",
description = "Configures whether to show the tooltip above or under the cursor",
position = 35,
section = overlaySettings
)
@Alpha
default Color overlayBackgroundColor()
default TooltipPositionType tooltipPosition()
{
return ComponentConstants.STANDARD_BACKGROUND_COLOR;
}
@ConfigTitleSection(
keyName = "infoboxTitle",
name = "Infoboxes",
description = "",
position = 30
)
default Title infoboxTitle()
{
return new Title();
}
@ConfigItem(
keyName = "infoBoxTextOutline",
name = "Outline infobox text",
description = "Draw a full outline instead of a simple shadow for infobox text",
position = 31,
titleSection = "infoboxTitle"
)
default boolean infoBoxTextOutline()
{
return false;
return TooltipPositionType.UNDER_CURSOR;
}
@ConfigItem(
keyName = "infoBoxVertical",
name = "Display infoboxes vertically",
description = "Toggles the infoboxes to display vertically",
position = 32,
titleSection = "infoboxTitle",
position = 40,
section = overlaySettings,
hidden = true
)
default boolean infoBoxVertical()
@@ -429,8 +346,8 @@ public interface RuneLiteConfig extends Config
keyName = "infoBoxSize",
name = "Infobox size",
description = "Configures the size of each infobox in pixels",
position = 33,
titleSection = "infoboxTitle"
position = 42,
section = overlaySettings
)
@Units(Units.PIXELS)
default int infoBoxSize()
@@ -438,23 +355,48 @@ public interface RuneLiteConfig extends Config
return 35;
}
@ConfigTitleSection(
keyName = "keybindsTitle",
name = "Key binds",
description = "",
position = 34
@ConfigItem(
keyName = "infoBoxTextOutline",
name = "Outline infobox text",
description = "Draw a full outline instead of a simple shadow for infobox text",
position = 43,
section = overlaySettings
)
default Title keybindsTitle()
default boolean infoBoxTextOutline()
{
return new Title();
return false;
}
@ConfigItem(
keyName = "overlayBackgroundColor",
name = "Overlay Color",
description = "Configures the background color of infoboxes and overlays",
position = 44,
section = overlaySettings
)
@Alpha
default Color overlayBackgroundColor()
{
return ComponentConstants.STANDARD_BACKGROUND_COLOR;
}
@ConfigItem(
keyName = "blockExtraMouseButtons",
name = "Block Extra Mouse Buttons",
description = "Blocks extra mouse buttons (4 and above)",
position = 44
)
default boolean blockExtraMouseButtons()
{
return true;
}
@ConfigItem(
keyName = "sidebarToggleKey",
name = "Sidebar Toggle Key",
description = "The key that will toggle the sidebar (accepts modifiers)",
position = 35,
titleSection = "keybindsTitle"
position = 45,
section = windowSettings
)
default Keybind sidebarToggleKey()
{
@@ -465,23 +407,11 @@ public interface RuneLiteConfig extends Config
keyName = "panelToggleKey",
name = "Plugin Panel Toggle Key",
description = "The key that will toggle the current or last opened plugin panel (accepts modifiers)",
position = 36,
titleSection = "keybindsTitle"
position = 46,
section = windowSettings
)
default Keybind panelToggleKey()
{
return new Keybind(KeyEvent.VK_F12, InputEvent.CTRL_DOWN_MASK);
}
@ConfigItem(
keyName = "blockExtraMouseButtons",
name = "Block Extra Mouse Buttons",
description = "Blocks extra mouse buttons (4 and above)",
position = 37,
titleSection = "keybindsTitle"
)
default boolean blockExtraMouseButtons()
{
return false;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* Copyright (c) 2020 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,20 +22,24 @@
* (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.ui.overlay.components.table;
package net.runelite.client.config;
import java.awt.Color;
import java.util.Collections;
import java.util.List;
import lombok.Builder;
import lombok.Data;
/**
* A profile/save of a OSRS account. Each account can 1 profile per {@link RuneScapeProfileType}
* (ie Standard/League/DMM}.
*/
@Data
@Builder
public class TableRow
public class RuneScapeProfile
{
Color rowColor;
TableAlignment rowAlignment;
@Builder.Default
List<TableElement> elements = Collections.emptyList();
private final String displayName;
private final RuneScapeProfileType type;
private final byte[] loginHash;
/**
* Profile key used to save configs for this profile to the config store. This will
* always start with {@link ConfigManager#RSPROFILE_GROUP}
*/
private final String key;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Craftiii4 <craftiii4@gmail.com>
* Copyright (c) 2020 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,27 +24,36 @@
*/
package net.runelite.client.config;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
import java.util.function.Predicate;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.runelite.api.Client;
import net.runelite.api.WorldType;
public class ConfigPanelItem
@Getter
@RequiredArgsConstructor
public enum RuneScapeProfileType
{
STANDARD(client -> true),
BETA(client -> client.getWorldType().contains(WorldType.TOURNAMENT)),
DEADMAN(client -> client.getWorldType().contains(WorldType.DEADMAN)),
TRAILBLAZER_LEAGUE(client -> client.getWorldType().contains(WorldType.LEAGUE)),
;
@Getter(AccessLevel.PUBLIC)
private ConfigPanelItem parent;
private final Predicate<Client> test;
@Getter(AccessLevel.PUBLIC)
private List<ConfigPanelItem> children;
@Getter(AccessLevel.PUBLIC)
private ConfigItemDescriptor item;
public ConfigPanelItem(ConfigPanelItem parent, ConfigItemDescriptor item)
public static RuneScapeProfileType getCurrent(Client client)
{
this.parent = parent;
this.children = new ArrayList<>();
this.item = item;
RuneScapeProfileType[] types = values();
for (int i = types.length - 1; i >= 0; i--)
{
RuneScapeProfileType type = types[i];
if (types[i].test.test(client))
{
return type;
}
}
return STANDARD;
}
}
}

View File

@@ -1,3 +0,0 @@
package net.runelite.client.config;
public class Title {}

View File

@@ -42,12 +42,8 @@ public @interface Units
String MINUTES = " mins";
String PERCENT = "%";
String PIXELS = "px";
String POINTS = "pt";
String SECONDS = "s";
String TICKS = " ticks";
String LEVELS = " lvls";
String FPS = " fps";
String GP = " GP";
String value();
}

View File

@@ -1,91 +0,0 @@
package net.runelite.client.database;
import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import static net.runelite.client.RuneLite.RUNELITE_DIR;
import org.h2.jdbcx.JdbcDataSource;
import org.jooq.DSLContext;
import org.jooq.SQLDialect;
import org.jooq.conf.Settings;
import org.jooq.impl.DSL;
@Singleton
@Slf4j
public class DatabaseManager
{
private static final String DB_URL = "jdbc:h2:" + RUNELITE_DIR + File.separator + "RunelitePlus;AUTO_SERVER=TRUE";
// Database credentials
private static final String USER = "RLP";
private static final String PASS = "";
private Connection connection;
DatabaseManager()
{
System.getProperties().setProperty("org.jooq.no-logo", "true");
}
private void connect()
{
if (connection != null)
{
return;
}
JdbcDataSource ds = new JdbcDataSource();
ds.setURL(DatabaseManager.DB_URL);
ds.setUser(DatabaseManager.USER);
ds.setPassword(DatabaseManager.PASS);
try
{
connection = ds.getConnection();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
Connection getConnection()
{
connect();
return connection;
}
public DSLContext getDsl()
{
Settings settings = new Settings();
settings.setExecuteLogging(false);
return DSL.using(connection, SQLDialect.H2, settings);
}
public boolean checkTableExists(String table)
{
boolean tableExists = false;
connect();
try
{
ResultSet rset = connection.getMetaData().getTables(null, null, table.toUpperCase(), null);
if (rset.next())
{
tableExists = true;
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return tableExists;
}
}

View File

@@ -1,42 +0,0 @@
package net.runelite.client.database;
import java.sql.Connection;
import org.jooq.codegen.GenerationTool;
import org.jooq.meta.h2.H2Database;
import org.jooq.meta.jaxb.Configuration;
import org.jooq.meta.jaxb.Database;
import org.jooq.meta.jaxb.Generator;
import org.jooq.meta.jaxb.Target;
public class GenerateClasses
{
public static void main(String... args)
{
DatabaseManager databaseManager = new DatabaseManager();
try (Connection c = databaseManager.getConnection())
{
Configuration configuration = new Configuration()
.withGenerator(new Generator()
.withDatabase(new Database()
.withName(H2Database.class.getCanonicalName())
.withIncludes(".*")
.withExcludes("")
.withInputSchema("PUBLIC")
)
.withTarget(new Target()
.withPackageName("net.runelite.client.database.data")
.withDirectory("runelite-client/src/main/java/")
)
);
GenerationTool tool = new GenerationTool();
tool.setConnection(c);
tool.run(configuration);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

View File

@@ -1,62 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.processing.Generated;
import org.jooq.Schema;
import org.jooq.impl.CatalogImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class DefaultCatalog extends CatalogImpl
{
private static final long serialVersionUID = -102989253;
/**
* The reference instance of <code></code>
*/
public static final DefaultCatalog DEFAULT_CATALOG = new DefaultCatalog();
/**
* The schema <code>PUBLIC</code>.
*/
public final Public PUBLIC = net.runelite.client.database.data.Public.PUBLIC;
/**
* No further instances allowed
*/
private DefaultCatalog()
{
super("");
}
@Override
public final List<Schema> getSchemas()
{
List result = new ArrayList();
result.addAll(getSchemas0());
return result;
}
private final List<Schema> getSchemas0()
{
return Arrays.<Schema>asList(
Public.PUBLIC);
}
}

View File

@@ -1,60 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.tables.Loottrackerevents;
import net.runelite.client.database.data.tables.Loottrackerlink;
import net.runelite.client.database.data.tables.Loottrackerloot;
import net.runelite.client.database.data.tables.TmorphSets;
import net.runelite.client.database.data.tables.User;
import org.jooq.Index;
import org.jooq.OrderField;
import org.jooq.impl.Internal;
/**
* A class modelling indexes of tables of the <code>PUBLIC</code> schema.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class Indexes
{
// -------------------------------------------------------------------------
// INDEX definitions
// -------------------------------------------------------------------------
public static final Index PRIMARY_KEY_B = Indexes0.PRIMARY_KEY_B;
public static final Index FK_LOOTTRACKERDROP_INDEX_6 = Indexes0.FK_LOOTTRACKERDROP_INDEX_6;
public static final Index FK_LOOTTRACKEREVENT_INDEX_6 = Indexes0.FK_LOOTTRACKEREVENT_INDEX_6;
public static final Index FK_USER_INDEX_6 = Indexes0.FK_USER_INDEX_6;
public static final Index PRIMARY_KEY_6 = Indexes0.PRIMARY_KEY_6;
public static final Index TMORPH_SETS_SET_NAME_UINDEX = Indexes0.TMORPH_SETS_SET_NAME_UINDEX;
public static final Index PRIMARY_KEY_2 = Indexes0.PRIMARY_KEY_2;
public static final Index UN_USERNAME_INDEX_2 = Indexes0.UN_USERNAME_INDEX_2;
// -------------------------------------------------------------------------
// [#1459] distribute members to avoid static initialisers > 64kb
// -------------------------------------------------------------------------
private static class Indexes0
{
public static Index PRIMARY_KEY_B = Internal.createIndex("PRIMARY_KEY_B", Loottrackerevents.LOOTTRACKEREVENTS, new OrderField[]{Loottrackerevents.LOOTTRACKEREVENTS.UNIQUEID}, true);
public static Index FK_LOOTTRACKERDROP_INDEX_6 = Internal.createIndex("FK_LOOTTRACKERDROP_INDEX_6", Loottrackerlink.LOOTTRACKERLINK, new OrderField[]{Loottrackerlink.LOOTTRACKERLINK.DROPUNIQUEID}, false);
public static Index FK_LOOTTRACKEREVENT_INDEX_6 = Internal.createIndex("FK_LOOTTRACKEREVENT_INDEX_6", Loottrackerlink.LOOTTRACKERLINK, new OrderField[]{Loottrackerlink.LOOTTRACKERLINK.EVENTUNIQUEID}, false);
public static Index FK_USER_INDEX_6 = Internal.createIndex("FK_USER_INDEX_6", Loottrackerlink.LOOTTRACKERLINK, new OrderField[]{Loottrackerlink.LOOTTRACKERLINK.USERUNIQUEID}, false);
public static Index PRIMARY_KEY_6 = Internal.createIndex("PRIMARY_KEY_6", Loottrackerloot.LOOTTRACKERLOOT, new OrderField[]{Loottrackerloot.LOOTTRACKERLOOT.UNIQUEID}, true);
public static Index TMORPH_SETS_SET_NAME_UINDEX = Internal.createIndex("TMORPH_SETS_SET_NAME_UINDEX", TmorphSets.TMORPH_SETS, new OrderField[]{TmorphSets.TMORPH_SETS.SET_NAME}, true);
public static Index PRIMARY_KEY_2 = Internal.createIndex("PRIMARY_KEY_2", User.USER, new OrderField[]{User.USER.UNIQUEID}, true);
public static Index UN_USERNAME_INDEX_2 = Internal.createIndex("UN_USERNAME_INDEX_2", User.USER, new OrderField[]{User.USER.USERNAME}, true);
}
}

View File

@@ -1,76 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.tables.Loottrackerevents;
import net.runelite.client.database.data.tables.Loottrackerlink;
import net.runelite.client.database.data.tables.Loottrackerloot;
import net.runelite.client.database.data.tables.User;
import net.runelite.client.database.data.tables.records.LoottrackereventsRecord;
import net.runelite.client.database.data.tables.records.LoottrackerlinkRecord;
import net.runelite.client.database.data.tables.records.LoottrackerlootRecord;
import net.runelite.client.database.data.tables.records.UserRecord;
import org.jooq.ForeignKey;
import org.jooq.UniqueKey;
import org.jooq.impl.Internal;
/**
* A class modelling foreign key relationships and constraints of tables of
* the <code>PUBLIC</code> schema.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class Keys
{
// -------------------------------------------------------------------------
// IDENTITY definitions
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// UNIQUE and PRIMARY KEY definitions
// -------------------------------------------------------------------------
public static final UniqueKey<LoottrackereventsRecord> PK_LOOTTRACKEREVENTS = UniqueKeys0.PK_LOOTTRACKEREVENTS;
public static final UniqueKey<LoottrackerlootRecord> PK_LOOTTRACKERDROPS = UniqueKeys0.PK_LOOTTRACKERDROPS;
public static final UniqueKey<UserRecord> PK_USER = UniqueKeys0.PK_USER;
public static final UniqueKey<UserRecord> UN_USERNAME = UniqueKeys0.UN_USERNAME;
// -------------------------------------------------------------------------
// FOREIGN KEY definitions
// -------------------------------------------------------------------------
public static final ForeignKey<LoottrackerlinkRecord, LoottrackereventsRecord> FK_LOOTTRACKEREVENT = ForeignKeys0.FK_LOOTTRACKEREVENT;
public static final ForeignKey<LoottrackerlinkRecord, LoottrackerlootRecord> FK_LOOTTRACKERDROP = ForeignKeys0.FK_LOOTTRACKERDROP;
public static final ForeignKey<LoottrackerlinkRecord, UserRecord> FK_USER = ForeignKeys0.FK_USER;
// -------------------------------------------------------------------------
// [#1459] distribute members to avoid static initialisers > 64kb
// -------------------------------------------------------------------------
private static class UniqueKeys0
{
public static final UniqueKey<LoottrackereventsRecord> PK_LOOTTRACKEREVENTS = Internal.createUniqueKey(Loottrackerevents.LOOTTRACKEREVENTS, "PK_LOOTTRACKEREVENTS", Loottrackerevents.LOOTTRACKEREVENTS.UNIQUEID);
public static final UniqueKey<LoottrackerlootRecord> PK_LOOTTRACKERDROPS = Internal.createUniqueKey(Loottrackerloot.LOOTTRACKERLOOT, "PK_LOOTTRACKERDROPS", Loottrackerloot.LOOTTRACKERLOOT.UNIQUEID);
public static final UniqueKey<UserRecord> PK_USER = Internal.createUniqueKey(User.USER, "PK_USER", User.USER.UNIQUEID);
public static final UniqueKey<UserRecord> UN_USERNAME = Internal.createUniqueKey(User.USER, "UN_USERNAME", User.USER.USERNAME);
}
private static class ForeignKeys0
{
public static final ForeignKey<LoottrackerlinkRecord, LoottrackereventsRecord> FK_LOOTTRACKEREVENT = Internal.createForeignKey(net.runelite.client.database.data.Keys.PK_LOOTTRACKEREVENTS, Loottrackerlink.LOOTTRACKERLINK, "FK_LOOTTRACKEREVENT", Loottrackerlink.LOOTTRACKERLINK.EVENTUNIQUEID);
public static final ForeignKey<LoottrackerlinkRecord, LoottrackerlootRecord> FK_LOOTTRACKERDROP = Internal.createForeignKey(net.runelite.client.database.data.Keys.PK_LOOTTRACKERDROPS, Loottrackerlink.LOOTTRACKERLINK, "FK_LOOTTRACKERDROP", Loottrackerlink.LOOTTRACKERLINK.DROPUNIQUEID);
public static final ForeignKey<LoottrackerlinkRecord, UserRecord> FK_USER = Internal.createForeignKey(net.runelite.client.database.data.Keys.PK_USER, Loottrackerlink.LOOTTRACKERLINK, "FK_USER", Loottrackerlink.LOOTTRACKERLINK.USERUNIQUEID);
}
}

View File

@@ -1,99 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.tables.Loottrackerevents;
import net.runelite.client.database.data.tables.Loottrackerlink;
import net.runelite.client.database.data.tables.Loottrackerloot;
import net.runelite.client.database.data.tables.TmorphSets;
import net.runelite.client.database.data.tables.User;
import org.jooq.Catalog;
import org.jooq.Table;
import org.jooq.impl.SchemaImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class Public extends SchemaImpl
{
private static final long serialVersionUID = 1268129010;
/**
* The reference instance of <code>PUBLIC</code>
*/
public static final Public PUBLIC = new Public();
/**
* The table <code>PUBLIC.LOOTTRACKEREVENTS</code>.
*/
public final Loottrackerevents LOOTTRACKEREVENTS = net.runelite.client.database.data.tables.Loottrackerevents.LOOTTRACKEREVENTS;
/**
* The table <code>PUBLIC.LOOTTRACKERLINK</code>.
*/
public final Loottrackerlink LOOTTRACKERLINK = net.runelite.client.database.data.tables.Loottrackerlink.LOOTTRACKERLINK;
/**
* The table <code>PUBLIC.LOOTTRACKERLOOT</code>.
*/
public final Loottrackerloot LOOTTRACKERLOOT = net.runelite.client.database.data.tables.Loottrackerloot.LOOTTRACKERLOOT;
/**
* The table <code>PUBLIC.TMORPH_SETS</code>.
*/
public final TmorphSets TMORPH_SETS = net.runelite.client.database.data.tables.TmorphSets.TMORPH_SETS;
/**
* The table <code>PUBLIC.USER</code>.
*/
public final User USER = net.runelite.client.database.data.tables.User.USER;
/**
* No further instances allowed
*/
private Public()
{
super("PUBLIC", null);
}
@Override
public Catalog getCatalog()
{
return DefaultCatalog.DEFAULT_CATALOG;
}
@Override
public final List<Table<?>> getTables()
{
List result = new ArrayList();
result.addAll(getTables0());
return result;
}
private final List<Table<?>> getTables0()
{
return Arrays.<Table<?>>asList(
Loottrackerevents.LOOTTRACKEREVENTS,
Loottrackerlink.LOOTTRACKERLINK,
Loottrackerloot.LOOTTRACKERLOOT,
TmorphSets.TMORPH_SETS,
User.USER);
}
}

View File

@@ -1,53 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.tables.Loottrackerevents;
import net.runelite.client.database.data.tables.Loottrackerlink;
import net.runelite.client.database.data.tables.Loottrackerloot;
import net.runelite.client.database.data.tables.TmorphSets;
import net.runelite.client.database.data.tables.User;
/**
* Convenience access to all tables in PUBLIC
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class Tables
{
/**
* The table <code>PUBLIC.LOOTTRACKEREVENTS</code>.
*/
public static final Loottrackerevents LOOTTRACKEREVENTS = Loottrackerevents.LOOTTRACKEREVENTS;
/**
* The table <code>PUBLIC.LOOTTRACKERLINK</code>.
*/
public static final Loottrackerlink LOOTTRACKERLINK = Loottrackerlink.LOOTTRACKERLINK;
/**
* The table <code>PUBLIC.LOOTTRACKERLOOT</code>.
*/
public static final Loottrackerloot LOOTTRACKERLOOT = Loottrackerloot.LOOTTRACKERLOOT;
/**
* The table <code>PUBLIC.TMORPH_SETS</code>.
*/
public static final TmorphSets TMORPH_SETS = TmorphSets.TMORPH_SETS;
/**
* The table <code>PUBLIC.USER</code>.
*/
public static final User USER = User.USER;
}

View File

@@ -1,182 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.Indexes;
import net.runelite.client.database.data.Keys;
import net.runelite.client.database.data.Public;
import net.runelite.client.database.data.tables.records.LoottrackereventsRecord;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Index;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.Row4;
import org.jooq.Schema;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.UniqueKey;
import org.jooq.impl.DSL;
import org.jooq.impl.TableImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class Loottrackerevents extends TableImpl<LoottrackereventsRecord>
{
private static final long serialVersionUID = 1578403652;
/**
* The reference instance of <code>PUBLIC.LOOTTRACKEREVENTS</code>
*/
public static final Loottrackerevents LOOTTRACKEREVENTS = new Loottrackerevents();
/**
* The class holding records for this type
*/
@Override
public Class<LoottrackereventsRecord> getRecordType()
{
return LoottrackereventsRecord.class;
}
/**
* The column <code>PUBLIC.LOOTTRACKEREVENTS.UNIQUEID</code>.
*/
public final TableField<LoottrackereventsRecord, UUID> UNIQUEID = createField(DSL.name("UNIQUEID"), org.jooq.impl.SQLDataType.UUID.nullable(false), this, "");
/**
* The column <code>PUBLIC.LOOTTRACKEREVENTS.EVENTID</code>.
*/
public final TableField<LoottrackereventsRecord, String> EVENTID = createField(DSL.name("EVENTID"), org.jooq.impl.SQLDataType.VARCHAR(255).nullable(false), this, "");
/**
* The column <code>PUBLIC.LOOTTRACKEREVENTS.TYPE</code>.
*/
public final TableField<LoottrackereventsRecord, String> TYPE = createField(DSL.name("TYPE"), org.jooq.impl.SQLDataType.VARCHAR(255).nullable(false), this, "");
/**
* The column <code>PUBLIC.LOOTTRACKEREVENTS.TIME</code>.
*/
public final TableField<LoottrackereventsRecord, Timestamp> TIME = createField(DSL.name("TIME"), org.jooq.impl.SQLDataType.TIMESTAMP.precision(6).nullable(false), this, "");
/**
* Create a <code>PUBLIC.LOOTTRACKEREVENTS</code> table reference
*/
public Loottrackerevents()
{
this(DSL.name("LOOTTRACKEREVENTS"), null);
}
/**
* Create an aliased <code>PUBLIC.LOOTTRACKEREVENTS</code> table reference
*/
public Loottrackerevents(String alias)
{
this(DSL.name(alias), LOOTTRACKEREVENTS);
}
/**
* Create an aliased <code>PUBLIC.LOOTTRACKEREVENTS</code> table reference
*/
public Loottrackerevents(Name alias)
{
this(alias, LOOTTRACKEREVENTS);
}
private Loottrackerevents(Name alias, Table<LoottrackereventsRecord> aliased)
{
this(alias, aliased, null);
}
private Loottrackerevents(Name alias, Table<LoottrackereventsRecord> aliased, Field<?>[] parameters)
{
super(alias, null, aliased, parameters, DSL.comment(""));
}
public <O extends Record> Loottrackerevents(Table<O> child, ForeignKey<O, LoottrackereventsRecord> key)
{
super(child, key, LOOTTRACKEREVENTS);
}
@Override
public Schema getSchema()
{
return Public.PUBLIC;
}
@Override
public List<Index> getIndexes()
{
return Arrays.<Index>asList(Indexes.PRIMARY_KEY_B);
}
@Override
public UniqueKey<LoottrackereventsRecord> getPrimaryKey()
{
return Keys.PK_LOOTTRACKEREVENTS;
}
@Override
public List<UniqueKey<LoottrackereventsRecord>> getKeys()
{
return Arrays.<UniqueKey<LoottrackereventsRecord>>asList(Keys.PK_LOOTTRACKEREVENTS);
}
@Override
public Loottrackerevents as(String alias)
{
return new Loottrackerevents(DSL.name(alias), this);
}
@Override
public Loottrackerevents as(Name alias)
{
return new Loottrackerevents(alias, this);
}
/**
* Rename this table
*/
@Override
public Loottrackerevents rename(String name)
{
return new Loottrackerevents(DSL.name(name), null);
}
/**
* Rename this table
*/
@Override
public Loottrackerevents rename(Name name)
{
return new Loottrackerevents(name, null);
}
// -------------------------------------------------------------------------
// Row4 type methods
// -------------------------------------------------------------------------
@Override
public Row4<UUID, String, String, Timestamp> fieldsRow()
{
return (Row4) super.fieldsRow();
}
}

View File

@@ -1,189 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.Indexes;
import net.runelite.client.database.data.Keys;
import net.runelite.client.database.data.Public;
import net.runelite.client.database.data.tables.records.LoottrackerlinkRecord;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Index;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.Row4;
import org.jooq.Schema;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.impl.DSL;
import org.jooq.impl.TableImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class Loottrackerlink extends TableImpl<LoottrackerlinkRecord>
{
private static final long serialVersionUID = -1694278583;
/**
* The reference instance of <code>PUBLIC.LOOTTRACKERLINK</code>
*/
public static final Loottrackerlink LOOTTRACKERLINK = new Loottrackerlink();
/**
* The class holding records for this type
*/
@Override
public Class<LoottrackerlinkRecord> getRecordType()
{
return LoottrackerlinkRecord.class;
}
/**
* The column <code>PUBLIC.LOOTTRACKERLINK.LINKUNIQUEID</code>.
*/
public final TableField<LoottrackerlinkRecord, UUID> LINKUNIQUEID = createField(DSL.name("LINKUNIQUEID"), org.jooq.impl.SQLDataType.UUID.nullable(false), this, "");
/**
* The column <code>PUBLIC.LOOTTRACKERLINK.EVENTUNIQUEID</code>.
*/
public final TableField<LoottrackerlinkRecord, UUID> EVENTUNIQUEID = createField(DSL.name("EVENTUNIQUEID"), org.jooq.impl.SQLDataType.UUID.nullable(false), this, "");
/**
* The column <code>PUBLIC.LOOTTRACKERLINK.DROPUNIQUEID</code>.
*/
public final TableField<LoottrackerlinkRecord, UUID> DROPUNIQUEID = createField(DSL.name("DROPUNIQUEID"), org.jooq.impl.SQLDataType.UUID.nullable(false), this, "");
/**
* The column <code>PUBLIC.LOOTTRACKERLINK.USERUNIQUEID</code>.
*/
public final TableField<LoottrackerlinkRecord, UUID> USERUNIQUEID = createField(DSL.name("USERUNIQUEID"), org.jooq.impl.SQLDataType.UUID.nullable(false), this, "");
/**
* Create a <code>PUBLIC.LOOTTRACKERLINK</code> table reference
*/
public Loottrackerlink()
{
this(DSL.name("LOOTTRACKERLINK"), null);
}
/**
* Create an aliased <code>PUBLIC.LOOTTRACKERLINK</code> table reference
*/
public Loottrackerlink(String alias)
{
this(DSL.name(alias), LOOTTRACKERLINK);
}
/**
* Create an aliased <code>PUBLIC.LOOTTRACKERLINK</code> table reference
*/
public Loottrackerlink(Name alias)
{
this(alias, LOOTTRACKERLINK);
}
private Loottrackerlink(Name alias, Table<LoottrackerlinkRecord> aliased)
{
this(alias, aliased, null);
}
private Loottrackerlink(Name alias, Table<LoottrackerlinkRecord> aliased, Field<?>[] parameters)
{
super(alias, null, aliased, parameters, DSL.comment(""));
}
public <O extends Record> Loottrackerlink(Table<O> child, ForeignKey<O, LoottrackerlinkRecord> key)
{
super(child, key, LOOTTRACKERLINK);
}
@Override
public Schema getSchema()
{
return Public.PUBLIC;
}
@Override
public List<Index> getIndexes()
{
return Arrays.<Index>asList(Indexes.FK_LOOTTRACKERDROP_INDEX_6, Indexes.FK_LOOTTRACKEREVENT_INDEX_6, Indexes.FK_USER_INDEX_6);
}
@Override
public List<ForeignKey<LoottrackerlinkRecord, ?>> getReferences()
{
return Arrays.<ForeignKey<LoottrackerlinkRecord, ?>>asList(Keys.FK_LOOTTRACKEREVENT, Keys.FK_LOOTTRACKERDROP, Keys.FK_USER);
}
public Loottrackerevents loottrackerevents()
{
return new Loottrackerevents(this, Keys.FK_LOOTTRACKEREVENT);
}
public Loottrackerloot loottrackerloot()
{
return new Loottrackerloot(this, Keys.FK_LOOTTRACKERDROP);
}
public User user()
{
return new User(this, Keys.FK_USER);
}
@Override
public Loottrackerlink as(String alias)
{
return new Loottrackerlink(DSL.name(alias), this);
}
@Override
public Loottrackerlink as(Name alias)
{
return new Loottrackerlink(alias, this);
}
/**
* Rename this table
*/
@Override
public Loottrackerlink rename(String name)
{
return new Loottrackerlink(DSL.name(name), null);
}
/**
* Rename this table
*/
@Override
public Loottrackerlink rename(Name name)
{
return new Loottrackerlink(name, null);
}
// -------------------------------------------------------------------------
// Row4 type methods
// -------------------------------------------------------------------------
@Override
public Row4<UUID, UUID, UUID, UUID> fieldsRow()
{
return (Row4) super.fieldsRow();
}
}

View File

@@ -1,176 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.Indexes;
import net.runelite.client.database.data.Keys;
import net.runelite.client.database.data.Public;
import net.runelite.client.database.data.tables.records.LoottrackerlootRecord;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Index;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.Row3;
import org.jooq.Schema;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.UniqueKey;
import org.jooq.impl.DSL;
import org.jooq.impl.TableImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class Loottrackerloot extends TableImpl<LoottrackerlootRecord>
{
private static final long serialVersionUID = 1461948279;
/**
* The reference instance of <code>PUBLIC.LOOTTRACKERLOOT</code>
*/
public static final Loottrackerloot LOOTTRACKERLOOT = new Loottrackerloot();
/**
* The class holding records for this type
*/
@Override
public Class<LoottrackerlootRecord> getRecordType()
{
return LoottrackerlootRecord.class;
}
/**
* The column <code>PUBLIC.LOOTTRACKERLOOT.UNIQUEID</code>.
*/
public final TableField<LoottrackerlootRecord, UUID> UNIQUEID = createField(DSL.name("UNIQUEID"), org.jooq.impl.SQLDataType.UUID.nullable(false), this, "");
/**
* The column <code>PUBLIC.LOOTTRACKERLOOT.ITEMID</code>.
*/
public final TableField<LoottrackerlootRecord, Integer> ITEMID = createField(DSL.name("ITEMID"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>PUBLIC.LOOTTRACKERLOOT.QUANTITY</code>.
*/
public final TableField<LoottrackerlootRecord, Integer> QUANTITY = createField(DSL.name("QUANTITY"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* Create a <code>PUBLIC.LOOTTRACKERLOOT</code> table reference
*/
public Loottrackerloot()
{
this(DSL.name("LOOTTRACKERLOOT"), null);
}
/**
* Create an aliased <code>PUBLIC.LOOTTRACKERLOOT</code> table reference
*/
public Loottrackerloot(String alias)
{
this(DSL.name(alias), LOOTTRACKERLOOT);
}
/**
* Create an aliased <code>PUBLIC.LOOTTRACKERLOOT</code> table reference
*/
public Loottrackerloot(Name alias)
{
this(alias, LOOTTRACKERLOOT);
}
private Loottrackerloot(Name alias, Table<LoottrackerlootRecord> aliased)
{
this(alias, aliased, null);
}
private Loottrackerloot(Name alias, Table<LoottrackerlootRecord> aliased, Field<?>[] parameters)
{
super(alias, null, aliased, parameters, DSL.comment(""));
}
public <O extends Record> Loottrackerloot(Table<O> child, ForeignKey<O, LoottrackerlootRecord> key)
{
super(child, key, LOOTTRACKERLOOT);
}
@Override
public Schema getSchema()
{
return Public.PUBLIC;
}
@Override
public List<Index> getIndexes()
{
return Arrays.<Index>asList(Indexes.PRIMARY_KEY_6);
}
@Override
public UniqueKey<LoottrackerlootRecord> getPrimaryKey()
{
return Keys.PK_LOOTTRACKERDROPS;
}
@Override
public List<UniqueKey<LoottrackerlootRecord>> getKeys()
{
return Arrays.<UniqueKey<LoottrackerlootRecord>>asList(Keys.PK_LOOTTRACKERDROPS);
}
@Override
public Loottrackerloot as(String alias)
{
return new Loottrackerloot(DSL.name(alias), this);
}
@Override
public Loottrackerloot as(Name alias)
{
return new Loottrackerloot(alias, this);
}
/**
* Rename this table
*/
@Override
public Loottrackerloot rename(String name)
{
return new Loottrackerloot(DSL.name(name), null);
}
/**
* Rename this table
*/
@Override
public Loottrackerloot rename(Name name)
{
return new Loottrackerloot(name, null);
}
// -------------------------------------------------------------------------
// Row3 type methods
// -------------------------------------------------------------------------
@Override
public Row3<UUID, Integer, Integer> fieldsRow()
{
return (Row3) super.fieldsRow();
}
}

View File

@@ -1,196 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables;
import java.util.Arrays;
import java.util.List;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.Indexes;
import net.runelite.client.database.data.Public;
import net.runelite.client.database.data.tables.records.TmorphSetsRecord;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Index;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.Row10;
import org.jooq.Schema;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.impl.DSL;
import org.jooq.impl.TableImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class TmorphSets extends TableImpl<TmorphSetsRecord>
{
private static final long serialVersionUID = -2027086786;
/**
* The reference instance of <code>PUBLIC.TMORPH_SETS</code>
*/
public static final TmorphSets TMORPH_SETS = new TmorphSets();
/**
* The class holding records for this type
*/
@Override
public Class<TmorphSetsRecord> getRecordType()
{
return TmorphSetsRecord.class;
}
/**
* The column <code>PUBLIC.TMORPH_SETS.SET_NAME</code>.
*/
public final TableField<TmorphSetsRecord, String> SET_NAME = createField(DSL.name("SET_NAME"), org.jooq.impl.SQLDataType.VARCHAR(255).nullable(false), this, "");
/**
* The column <code>PUBLIC.TMORPH_SETS.HELMET</code>.
*/
public final TableField<TmorphSetsRecord, Integer> HELMET = createField(DSL.name("HELMET"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>PUBLIC.TMORPH_SETS.CAPE</code>.
*/
public final TableField<TmorphSetsRecord, Integer> CAPE = createField(DSL.name("CAPE"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>PUBLIC.TMORPH_SETS.AMULET</code>.
*/
public final TableField<TmorphSetsRecord, Integer> AMULET = createField(DSL.name("AMULET"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>PUBLIC.TMORPH_SETS.WEAPON</code>.
*/
public final TableField<TmorphSetsRecord, Integer> WEAPON = createField(DSL.name("WEAPON"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>PUBLIC.TMORPH_SETS.TORSO</code>.
*/
public final TableField<TmorphSetsRecord, Integer> TORSO = createField(DSL.name("TORSO"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>PUBLIC.TMORPH_SETS.SHIELD</code>.
*/
public final TableField<TmorphSetsRecord, Integer> SHIELD = createField(DSL.name("SHIELD"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>PUBLIC.TMORPH_SETS.LEGS</code>.
*/
public final TableField<TmorphSetsRecord, Integer> LEGS = createField(DSL.name("LEGS"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>PUBLIC.TMORPH_SETS.HANDS</code>.
*/
public final TableField<TmorphSetsRecord, Integer> HANDS = createField(DSL.name("HANDS"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>PUBLIC.TMORPH_SETS.BOOTS</code>.
*/
public final TableField<TmorphSetsRecord, Integer> BOOTS = createField(DSL.name("BOOTS"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");
/**
* Create a <code>PUBLIC.TMORPH_SETS</code> table reference
*/
public TmorphSets()
{
this(DSL.name("TMORPH_SETS"), null);
}
/**
* Create an aliased <code>PUBLIC.TMORPH_SETS</code> table reference
*/
public TmorphSets(String alias)
{
this(DSL.name(alias), TMORPH_SETS);
}
/**
* Create an aliased <code>PUBLIC.TMORPH_SETS</code> table reference
*/
public TmorphSets(Name alias)
{
this(alias, TMORPH_SETS);
}
private TmorphSets(Name alias, Table<TmorphSetsRecord> aliased)
{
this(alias, aliased, null);
}
private TmorphSets(Name alias, Table<TmorphSetsRecord> aliased, Field<?>[] parameters)
{
super(alias, null, aliased, parameters, DSL.comment(""));
}
public <O extends Record> TmorphSets(Table<O> child, ForeignKey<O, TmorphSetsRecord> key)
{
super(child, key, TMORPH_SETS);
}
@Override
public Schema getSchema()
{
return Public.PUBLIC;
}
@Override
public List<Index> getIndexes()
{
return Arrays.<Index>asList(Indexes.TMORPH_SETS_SET_NAME_UINDEX);
}
@Override
public TmorphSets as(String alias)
{
return new TmorphSets(DSL.name(alias), this);
}
@Override
public TmorphSets as(Name alias)
{
return new TmorphSets(alias, this);
}
/**
* Rename this table
*/
@Override
public TmorphSets rename(String name)
{
return new TmorphSets(DSL.name(name), null);
}
/**
* Rename this table
*/
@Override
public TmorphSets rename(Name name)
{
return new TmorphSets(name, null);
}
// -------------------------------------------------------------------------
// Row10 type methods
// -------------------------------------------------------------------------
@Override
public Row10<String, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer> fieldsRow()
{
return (Row10) super.fieldsRow();
}
}

View File

@@ -1,171 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.Indexes;
import net.runelite.client.database.data.Keys;
import net.runelite.client.database.data.Public;
import net.runelite.client.database.data.tables.records.UserRecord;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Index;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.Row2;
import org.jooq.Schema;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.UniqueKey;
import org.jooq.impl.DSL;
import org.jooq.impl.TableImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class User extends TableImpl<UserRecord>
{
private static final long serialVersionUID = -668009102;
/**
* The reference instance of <code>PUBLIC.USER</code>
*/
public static final User USER = new User();
/**
* The class holding records for this type
*/
@Override
public Class<UserRecord> getRecordType()
{
return UserRecord.class;
}
/**
* The column <code>PUBLIC.USER.UNIQUEID</code>.
*/
public final TableField<UserRecord, UUID> UNIQUEID = createField(DSL.name("UNIQUEID"), org.jooq.impl.SQLDataType.UUID.nullable(false), this, "");
/**
* The column <code>PUBLIC.USER.USERNAME</code>.
*/
public final TableField<UserRecord, String> USERNAME = createField(DSL.name("USERNAME"), org.jooq.impl.SQLDataType.VARCHAR(12).nullable(false), this, "");
/**
* Create a <code>PUBLIC.USER</code> table reference
*/
public User()
{
this(DSL.name("USER"), null);
}
/**
* Create an aliased <code>PUBLIC.USER</code> table reference
*/
public User(String alias)
{
this(DSL.name(alias), USER);
}
/**
* Create an aliased <code>PUBLIC.USER</code> table reference
*/
public User(Name alias)
{
this(alias, USER);
}
private User(Name alias, Table<UserRecord> aliased)
{
this(alias, aliased, null);
}
private User(Name alias, Table<UserRecord> aliased, Field<?>[] parameters)
{
super(alias, null, aliased, parameters, DSL.comment(""));
}
public <O extends Record> User(Table<O> child, ForeignKey<O, UserRecord> key)
{
super(child, key, USER);
}
@Override
public Schema getSchema()
{
return Public.PUBLIC;
}
@Override
public List<Index> getIndexes()
{
return Arrays.<Index>asList(Indexes.PRIMARY_KEY_2, Indexes.UN_USERNAME_INDEX_2);
}
@Override
public UniqueKey<UserRecord> getPrimaryKey()
{
return Keys.PK_USER;
}
@Override
public List<UniqueKey<UserRecord>> getKeys()
{
return Arrays.<UniqueKey<UserRecord>>asList(Keys.PK_USER, Keys.UN_USERNAME);
}
@Override
public User as(String alias)
{
return new User(DSL.name(alias), this);
}
@Override
public User as(Name alias)
{
return new User(alias, this);
}
/**
* Rename this table
*/
@Override
public User rename(String name)
{
return new User(DSL.name(name), null);
}
/**
* Rename this table
*/
@Override
public User rename(Name name)
{
return new User(name, null);
}
// -------------------------------------------------------------------------
// Row2 type methods
// -------------------------------------------------------------------------
@Override
public Row2<UUID, String> fieldsRow()
{
return (Row2) super.fieldsRow();
}
}

View File

@@ -1,258 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables.records;
import java.sql.Timestamp;
import java.util.UUID;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.tables.Loottrackerevents;
import org.jooq.Field;
import org.jooq.Record1;
import org.jooq.Record4;
import org.jooq.Row4;
import org.jooq.impl.UpdatableRecordImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class LoottrackereventsRecord extends UpdatableRecordImpl<LoottrackereventsRecord> implements Record4<UUID, String, String, Timestamp>
{
private static final long serialVersionUID = -1418522415;
/**
* Setter for <code>PUBLIC.LOOTTRACKEREVENTS.UNIQUEID</code>.
*/
public void setUniqueid(UUID value)
{
set(0, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKEREVENTS.UNIQUEID</code>.
*/
public UUID getUniqueid()
{
return (UUID) get(0);
}
/**
* Setter for <code>PUBLIC.LOOTTRACKEREVENTS.EVENTID</code>.
*/
public void setEventid(String value)
{
set(1, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKEREVENTS.EVENTID</code>.
*/
public String getEventid()
{
return (String) get(1);
}
/**
* Setter for <code>PUBLIC.LOOTTRACKEREVENTS.TYPE</code>.
*/
public void setType(String value)
{
set(2, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKEREVENTS.TYPE</code>.
*/
public String getType()
{
return (String) get(2);
}
/**
* Setter for <code>PUBLIC.LOOTTRACKEREVENTS.TIME</code>.
*/
public void setTime(Timestamp value)
{
set(3, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKEREVENTS.TIME</code>.
*/
public Timestamp getTime()
{
return (Timestamp) get(3);
}
// -------------------------------------------------------------------------
// Primary key information
// -------------------------------------------------------------------------
@Override
public Record1<UUID> key()
{
return (Record1) super.key();
}
// -------------------------------------------------------------------------
// Record4 type implementation
// -------------------------------------------------------------------------
@Override
public Row4<UUID, String, String, Timestamp> fieldsRow()
{
return (Row4) super.fieldsRow();
}
@Override
public Row4<UUID, String, String, Timestamp> valuesRow()
{
return (Row4) super.valuesRow();
}
@Override
public Field<UUID> field1()
{
return Loottrackerevents.LOOTTRACKEREVENTS.UNIQUEID;
}
@Override
public Field<String> field2()
{
return Loottrackerevents.LOOTTRACKEREVENTS.EVENTID;
}
@Override
public Field<String> field3()
{
return Loottrackerevents.LOOTTRACKEREVENTS.TYPE;
}
@Override
public Field<Timestamp> field4()
{
return Loottrackerevents.LOOTTRACKEREVENTS.TIME;
}
@Override
public UUID component1()
{
return getUniqueid();
}
@Override
public String component2()
{
return getEventid();
}
@Override
public String component3()
{
return getType();
}
@Override
public Timestamp component4()
{
return getTime();
}
@Override
public UUID value1()
{
return getUniqueid();
}
@Override
public String value2()
{
return getEventid();
}
@Override
public String value3()
{
return getType();
}
@Override
public Timestamp value4()
{
return getTime();
}
@Override
public LoottrackereventsRecord value1(UUID value)
{
setUniqueid(value);
return this;
}
@Override
public LoottrackereventsRecord value2(String value)
{
setEventid(value);
return this;
}
@Override
public LoottrackereventsRecord value3(String value)
{
setType(value);
return this;
}
@Override
public LoottrackereventsRecord value4(Timestamp value)
{
setTime(value);
return this;
}
@Override
public LoottrackereventsRecord values(UUID value1, String value2, String value3, Timestamp value4)
{
value1(value1);
value2(value2);
value3(value3);
value4(value4);
return this;
}
// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
/**
* Create a detached LoottrackereventsRecord
*/
public LoottrackereventsRecord()
{
super(Loottrackerevents.LOOTTRACKEREVENTS);
}
/**
* Create a detached, initialised LoottrackereventsRecord
*/
public LoottrackereventsRecord(UUID uniqueid, String eventid, String type, Timestamp time)
{
super(Loottrackerevents.LOOTTRACKEREVENTS);
set(0, uniqueid);
set(1, eventid);
set(2, type);
set(3, time);
}
}

View File

@@ -1,246 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables.records;
import java.util.UUID;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.tables.Loottrackerlink;
import org.jooq.Field;
import org.jooq.Record4;
import org.jooq.Row4;
import org.jooq.impl.TableRecordImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class LoottrackerlinkRecord extends TableRecordImpl<LoottrackerlinkRecord> implements Record4<UUID, UUID, UUID, UUID>
{
private static final long serialVersionUID = -1701074584;
/**
* Setter for <code>PUBLIC.LOOTTRACKERLINK.LINKUNIQUEID</code>.
*/
public void setLinkuniqueid(UUID value)
{
set(0, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKERLINK.LINKUNIQUEID</code>.
*/
public UUID getLinkuniqueid()
{
return (UUID) get(0);
}
/**
* Setter for <code>PUBLIC.LOOTTRACKERLINK.EVENTUNIQUEID</code>.
*/
public void setEventuniqueid(UUID value)
{
set(1, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKERLINK.EVENTUNIQUEID</code>.
*/
public UUID getEventuniqueid()
{
return (UUID) get(1);
}
/**
* Setter for <code>PUBLIC.LOOTTRACKERLINK.DROPUNIQUEID</code>.
*/
public void setDropuniqueid(UUID value)
{
set(2, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKERLINK.DROPUNIQUEID</code>.
*/
public UUID getDropuniqueid()
{
return (UUID) get(2);
}
/**
* Setter for <code>PUBLIC.LOOTTRACKERLINK.USERUNIQUEID</code>.
*/
public void setUseruniqueid(UUID value)
{
set(3, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKERLINK.USERUNIQUEID</code>.
*/
public UUID getUseruniqueid()
{
return (UUID) get(3);
}
// -------------------------------------------------------------------------
// Record4 type implementation
// -------------------------------------------------------------------------
@Override
public Row4<UUID, UUID, UUID, UUID> fieldsRow()
{
return (Row4) super.fieldsRow();
}
@Override
public Row4<UUID, UUID, UUID, UUID> valuesRow()
{
return (Row4) super.valuesRow();
}
@Override
public Field<UUID> field1()
{
return Loottrackerlink.LOOTTRACKERLINK.LINKUNIQUEID;
}
@Override
public Field<UUID> field2()
{
return Loottrackerlink.LOOTTRACKERLINK.EVENTUNIQUEID;
}
@Override
public Field<UUID> field3()
{
return Loottrackerlink.LOOTTRACKERLINK.DROPUNIQUEID;
}
@Override
public Field<UUID> field4()
{
return Loottrackerlink.LOOTTRACKERLINK.USERUNIQUEID;
}
@Override
public UUID component1()
{
return getLinkuniqueid();
}
@Override
public UUID component2()
{
return getEventuniqueid();
}
@Override
public UUID component3()
{
return getDropuniqueid();
}
@Override
public UUID component4()
{
return getUseruniqueid();
}
@Override
public UUID value1()
{
return getLinkuniqueid();
}
@Override
public UUID value2()
{
return getEventuniqueid();
}
@Override
public UUID value3()
{
return getDropuniqueid();
}
@Override
public UUID value4()
{
return getUseruniqueid();
}
@Override
public LoottrackerlinkRecord value1(UUID value)
{
setLinkuniqueid(value);
return this;
}
@Override
public LoottrackerlinkRecord value2(UUID value)
{
setEventuniqueid(value);
return this;
}
@Override
public LoottrackerlinkRecord value3(UUID value)
{
setDropuniqueid(value);
return this;
}
@Override
public LoottrackerlinkRecord value4(UUID value)
{
setUseruniqueid(value);
return this;
}
@Override
public LoottrackerlinkRecord values(UUID value1, UUID value2, UUID value3, UUID value4)
{
value1(value1);
value2(value2);
value3(value3);
value4(value4);
return this;
}
// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
/**
* Create a detached LoottrackerlinkRecord
*/
public LoottrackerlinkRecord()
{
super(Loottrackerlink.LOOTTRACKERLINK);
}
/**
* Create a detached, initialised LoottrackerlinkRecord
*/
public LoottrackerlinkRecord(UUID linkuniqueid, UUID eventuniqueid, UUID dropuniqueid, UUID useruniqueid)
{
super(Loottrackerlink.LOOTTRACKERLINK);
set(0, linkuniqueid);
set(1, eventuniqueid);
set(2, dropuniqueid);
set(3, useruniqueid);
}
}

View File

@@ -1,214 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables.records;
import java.util.UUID;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.tables.Loottrackerloot;
import org.jooq.Field;
import org.jooq.Record1;
import org.jooq.Record3;
import org.jooq.Row3;
import org.jooq.impl.UpdatableRecordImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class LoottrackerlootRecord extends UpdatableRecordImpl<LoottrackerlootRecord> implements Record3<UUID, Integer, Integer>
{
private static final long serialVersionUID = 693470968;
/**
* Setter for <code>PUBLIC.LOOTTRACKERLOOT.UNIQUEID</code>.
*/
public void setUniqueid(UUID value)
{
set(0, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKERLOOT.UNIQUEID</code>.
*/
public UUID getUniqueid()
{
return (UUID) get(0);
}
/**
* Setter for <code>PUBLIC.LOOTTRACKERLOOT.ITEMID</code>.
*/
public void setItemid(Integer value)
{
set(1, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKERLOOT.ITEMID</code>.
*/
public Integer getItemid()
{
return (Integer) get(1);
}
/**
* Setter for <code>PUBLIC.LOOTTRACKERLOOT.QUANTITY</code>.
*/
public void setQuantity(Integer value)
{
set(2, value);
}
/**
* Getter for <code>PUBLIC.LOOTTRACKERLOOT.QUANTITY</code>.
*/
public Integer getQuantity()
{
return (Integer) get(2);
}
// -------------------------------------------------------------------------
// Primary key information
// -------------------------------------------------------------------------
@Override
public Record1<UUID> key()
{
return (Record1) super.key();
}
// -------------------------------------------------------------------------
// Record3 type implementation
// -------------------------------------------------------------------------
@Override
public Row3<UUID, Integer, Integer> fieldsRow()
{
return (Row3) super.fieldsRow();
}
@Override
public Row3<UUID, Integer, Integer> valuesRow()
{
return (Row3) super.valuesRow();
}
@Override
public Field<UUID> field1()
{
return Loottrackerloot.LOOTTRACKERLOOT.UNIQUEID;
}
@Override
public Field<Integer> field2()
{
return Loottrackerloot.LOOTTRACKERLOOT.ITEMID;
}
@Override
public Field<Integer> field3()
{
return Loottrackerloot.LOOTTRACKERLOOT.QUANTITY;
}
@Override
public UUID component1()
{
return getUniqueid();
}
@Override
public Integer component2()
{
return getItemid();
}
@Override
public Integer component3()
{
return getQuantity();
}
@Override
public UUID value1()
{
return getUniqueid();
}
@Override
public Integer value2()
{
return getItemid();
}
@Override
public Integer value3()
{
return getQuantity();
}
@Override
public LoottrackerlootRecord value1(UUID value)
{
setUniqueid(value);
return this;
}
@Override
public LoottrackerlootRecord value2(Integer value)
{
setItemid(value);
return this;
}
@Override
public LoottrackerlootRecord value3(Integer value)
{
setQuantity(value);
return this;
}
@Override
public LoottrackerlootRecord values(UUID value1, Integer value2, Integer value3)
{
value1(value1);
value2(value2);
value3(value3);
return this;
}
// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
/**
* Create a detached LoottrackerlootRecord
*/
public LoottrackerlootRecord()
{
super(Loottrackerloot.LOOTTRACKERLOOT);
}
/**
* Create a detached, initialised LoottrackerlootRecord
*/
public LoottrackerlootRecord(UUID uniqueid, Integer itemid, Integer quantity)
{
super(Loottrackerloot.LOOTTRACKERLOOT);
set(0, uniqueid);
set(1, itemid);
set(2, quantity);
}
}

View File

@@ -1,503 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables.records;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.tables.TmorphSets;
import org.jooq.Field;
import org.jooq.Record10;
import org.jooq.Row10;
import org.jooq.impl.TableRecordImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class TmorphSetsRecord extends TableRecordImpl<TmorphSetsRecord> implements Record10<String, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer>
{
private static final long serialVersionUID = 546214401;
/**
* Setter for <code>PUBLIC.TMORPH_SETS.SET_NAME</code>.
*/
public void setSetName(String value)
{
set(0, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.SET_NAME</code>.
*/
public String getSetName()
{
return (String) get(0);
}
/**
* Setter for <code>PUBLIC.TMORPH_SETS.HELMET</code>.
*/
public void setHelmet(Integer value)
{
set(1, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.HELMET</code>.
*/
public Integer getHelmet()
{
return (Integer) get(1);
}
/**
* Setter for <code>PUBLIC.TMORPH_SETS.CAPE</code>.
*/
public void setCape(Integer value)
{
set(2, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.CAPE</code>.
*/
public Integer getCape()
{
return (Integer) get(2);
}
/**
* Setter for <code>PUBLIC.TMORPH_SETS.AMULET</code>.
*/
public void setAmulet(Integer value)
{
set(3, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.AMULET</code>.
*/
public Integer getAmulet()
{
return (Integer) get(3);
}
/**
* Setter for <code>PUBLIC.TMORPH_SETS.WEAPON</code>.
*/
public void setWeapon(Integer value)
{
set(4, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.WEAPON</code>.
*/
public Integer getWeapon()
{
return (Integer) get(4);
}
/**
* Setter for <code>PUBLIC.TMORPH_SETS.TORSO</code>.
*/
public void setTorso(Integer value)
{
set(5, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.TORSO</code>.
*/
public Integer getTorso()
{
return (Integer) get(5);
}
/**
* Setter for <code>PUBLIC.TMORPH_SETS.SHIELD</code>.
*/
public void setShield(Integer value)
{
set(6, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.SHIELD</code>.
*/
public Integer getShield()
{
return (Integer) get(6);
}
/**
* Setter for <code>PUBLIC.TMORPH_SETS.LEGS</code>.
*/
public void setLegs(Integer value)
{
set(7, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.LEGS</code>.
*/
public Integer getLegs()
{
return (Integer) get(7);
}
/**
* Setter for <code>PUBLIC.TMORPH_SETS.HANDS</code>.
*/
public void setHands(Integer value)
{
set(8, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.HANDS</code>.
*/
public Integer getHands()
{
return (Integer) get(8);
}
/**
* Setter for <code>PUBLIC.TMORPH_SETS.BOOTS</code>.
*/
public void setBoots(Integer value)
{
set(9, value);
}
/**
* Getter for <code>PUBLIC.TMORPH_SETS.BOOTS</code>.
*/
public Integer getBoots()
{
return (Integer) get(9);
}
// -------------------------------------------------------------------------
// Record10 type implementation
// -------------------------------------------------------------------------
@Override
public Row10<String, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer> fieldsRow()
{
return (Row10) super.fieldsRow();
}
@Override
public Row10<String, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer> valuesRow()
{
return (Row10) super.valuesRow();
}
@Override
public Field<String> field1()
{
return TmorphSets.TMORPH_SETS.SET_NAME;
}
@Override
public Field<Integer> field2()
{
return TmorphSets.TMORPH_SETS.HELMET;
}
@Override
public Field<Integer> field3()
{
return TmorphSets.TMORPH_SETS.CAPE;
}
@Override
public Field<Integer> field4()
{
return TmorphSets.TMORPH_SETS.AMULET;
}
@Override
public Field<Integer> field5()
{
return TmorphSets.TMORPH_SETS.WEAPON;
}
@Override
public Field<Integer> field6()
{
return TmorphSets.TMORPH_SETS.TORSO;
}
@Override
public Field<Integer> field7()
{
return TmorphSets.TMORPH_SETS.SHIELD;
}
@Override
public Field<Integer> field8()
{
return TmorphSets.TMORPH_SETS.LEGS;
}
@Override
public Field<Integer> field9()
{
return TmorphSets.TMORPH_SETS.HANDS;
}
@Override
public Field<Integer> field10()
{
return TmorphSets.TMORPH_SETS.BOOTS;
}
@Override
public String component1()
{
return getSetName();
}
@Override
public Integer component2()
{
return getHelmet();
}
@Override
public Integer component3()
{
return getCape();
}
@Override
public Integer component4()
{
return getAmulet();
}
@Override
public Integer component5()
{
return getWeapon();
}
@Override
public Integer component6()
{
return getTorso();
}
@Override
public Integer component7()
{
return getShield();
}
@Override
public Integer component8()
{
return getLegs();
}
@Override
public Integer component9()
{
return getHands();
}
@Override
public Integer component10()
{
return getBoots();
}
@Override
public String value1()
{
return getSetName();
}
@Override
public Integer value2()
{
return getHelmet();
}
@Override
public Integer value3()
{
return getCape();
}
@Override
public Integer value4()
{
return getAmulet();
}
@Override
public Integer value5()
{
return getWeapon();
}
@Override
public Integer value6()
{
return getTorso();
}
@Override
public Integer value7()
{
return getShield();
}
@Override
public Integer value8()
{
return getLegs();
}
@Override
public Integer value9()
{
return getHands();
}
@Override
public Integer value10()
{
return getBoots();
}
@Override
public TmorphSetsRecord value1(String value)
{
setSetName(value);
return this;
}
@Override
public TmorphSetsRecord value2(Integer value)
{
setHelmet(value);
return this;
}
@Override
public TmorphSetsRecord value3(Integer value)
{
setCape(value);
return this;
}
@Override
public TmorphSetsRecord value4(Integer value)
{
setAmulet(value);
return this;
}
@Override
public TmorphSetsRecord value5(Integer value)
{
setWeapon(value);
return this;
}
@Override
public TmorphSetsRecord value6(Integer value)
{
setTorso(value);
return this;
}
@Override
public TmorphSetsRecord value7(Integer value)
{
setShield(value);
return this;
}
@Override
public TmorphSetsRecord value8(Integer value)
{
setLegs(value);
return this;
}
@Override
public TmorphSetsRecord value9(Integer value)
{
setHands(value);
return this;
}
@Override
public TmorphSetsRecord value10(Integer value)
{
setBoots(value);
return this;
}
@Override
public TmorphSetsRecord values(String value1, Integer value2, Integer value3, Integer value4, Integer value5, Integer value6, Integer value7, Integer value8, Integer value9, Integer value10)
{
value1(value1);
value2(value2);
value3(value3);
value4(value4);
value5(value5);
value6(value6);
value7(value7);
value8(value8);
value9(value9);
value10(value10);
return this;
}
// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
/**
* Create a detached TmorphSetsRecord
*/
public TmorphSetsRecord()
{
super(TmorphSets.TMORPH_SETS);
}
/**
* Create a detached, initialised TmorphSetsRecord
*/
public TmorphSetsRecord(String setName, Integer helmet, Integer cape, Integer amulet, Integer weapon, Integer torso, Integer shield, Integer legs, Integer hands, Integer boots)
{
super(TmorphSets.TMORPH_SETS);
set(0, setName);
set(1, helmet);
set(2, cape);
set(3, amulet);
set(4, weapon);
set(5, torso);
set(6, shield);
set(7, legs);
set(8, hands);
set(9, boots);
}
}

View File

@@ -1,171 +0,0 @@
/*
* This file is generated by jOOQ.
*/
package net.runelite.client.database.data.tables.records;
import java.util.UUID;
import javax.annotation.processing.Generated;
import net.runelite.client.database.data.tables.User;
import org.jooq.Field;
import org.jooq.Record1;
import org.jooq.Record2;
import org.jooq.Row2;
import org.jooq.impl.UpdatableRecordImpl;
/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.12.3"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({"all", "unchecked", "rawtypes"})
public class UserRecord extends UpdatableRecordImpl<UserRecord> implements Record2<UUID, String>
{
private static final long serialVersionUID = 2077804101;
/**
* Setter for <code>PUBLIC.USER.UNIQUEID</code>.
*/
public void setUniqueid(UUID value)
{
set(0, value);
}
/**
* Getter for <code>PUBLIC.USER.UNIQUEID</code>.
*/
public UUID getUniqueid()
{
return (UUID) get(0);
}
/**
* Setter for <code>PUBLIC.USER.USERNAME</code>.
*/
public void setUsername(String value)
{
set(1, value);
}
/**
* Getter for <code>PUBLIC.USER.USERNAME</code>.
*/
public String getUsername()
{
return (String) get(1);
}
// -------------------------------------------------------------------------
// Primary key information
// -------------------------------------------------------------------------
@Override
public Record1<UUID> key()
{
return (Record1) super.key();
}
// -------------------------------------------------------------------------
// Record2 type implementation
// -------------------------------------------------------------------------
@Override
public Row2<UUID, String> fieldsRow()
{
return (Row2) super.fieldsRow();
}
@Override
public Row2<UUID, String> valuesRow()
{
return (Row2) super.valuesRow();
}
@Override
public Field<UUID> field1()
{
return User.USER.UNIQUEID;
}
@Override
public Field<String> field2()
{
return User.USER.USERNAME;
}
@Override
public UUID component1()
{
return getUniqueid();
}
@Override
public String component2()
{
return getUsername();
}
@Override
public UUID value1()
{
return getUniqueid();
}
@Override
public String value2()
{
return getUsername();
}
@Override
public UserRecord value1(UUID value)
{
setUniqueid(value);
return this;
}
@Override
public UserRecord value2(String value)
{
setUsername(value);
return this;
}
@Override
public UserRecord values(UUID value1, String value2)
{
value1(value1);
value2(value2);
return this;
}
// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
/**
* Create a detached UserRecord
*/
public UserRecord()
{
super(User.USER);
}
/**
* Create a detached, initialised UserRecord
*/
public UserRecord(UUID uniqueid, String username)
{
super(User.USER);
set(0, uniqueid);
set(1, username);
}
}

View File

@@ -198,7 +198,7 @@ public class DiscordService implements AutoCloseable
{
log.info("Discord RPC service is ready with user {}.", user.username);
currentUser = user;
eventBus.post(DiscordReady.class, new DiscordReady(
eventBus.post(new DiscordReady(
user.userId,
user.username,
user.discriminator,
@@ -208,31 +208,31 @@ public class DiscordService implements AutoCloseable
private void disconnected(int errorCode, String message)
{
log.debug("Discord disconnected {}: {}", errorCode, message);
eventBus.post(DiscordDisconnected.class, new DiscordDisconnected(errorCode, message));
eventBus.post(new DiscordDisconnected(errorCode, message));
}
private void errored(int errorCode, String message)
{
log.warn("Discord error: {} - {}", errorCode, message);
eventBus.post(DiscordErrored.class, new DiscordErrored(errorCode, message));
eventBus.post(new DiscordErrored(errorCode, message));
}
private void joinGame(String joinSecret)
{
log.debug("Discord join game: {}", joinSecret);
eventBus.post(DiscordJoinGame.class, new DiscordJoinGame(joinSecret));
eventBus.post(new DiscordJoinGame(joinSecret));
}
private void spectateGame(String spectateSecret)
{
log.debug("Discord spectate game: {}", spectateSecret);
eventBus.post(DiscordSpectateGame.class, new DiscordSpectateGame(spectateSecret));
eventBus.post(new DiscordSpectateGame(spectateSecret));
}
private void joinRequest(DiscordUser user)
{
log.debug("Discord join request: {}", user);
eventBus.post(DiscordJoinRequest.class, new DiscordJoinRequest(
eventBus.post(new DiscordJoinRequest(
user.userId,
user.username,
user.discriminator,

View File

@@ -25,13 +25,12 @@
package net.runelite.client.discord.events;
import lombok.Value;
import net.runelite.api.events.Event;
/**
* Called when the RPC connection has been severed
*/
@Value
public class DiscordDisconnected implements Event
public class DiscordDisconnected
{
/**
* Discord error code

View File

@@ -25,13 +25,12 @@
package net.runelite.client.discord.events;
import lombok.Value;
import net.runelite.api.events.Event;
/**
* Called when an internal error is caught within the SDK
*/
@Value
public class DiscordErrored implements Event
public class DiscordErrored
{
/**
* Discord error code.

View File

@@ -25,13 +25,12 @@
package net.runelite.client.discord.events;
import lombok.Value;
import net.runelite.api.events.Event;
/**
* Called when the logged in user joined a game
*/
@Value
public class DiscordJoinGame implements Event
public class DiscordJoinGame
{
/**
* Obfuscated data of your choosing used as join secret

View File

@@ -25,13 +25,12 @@
package net.runelite.client.discord.events;
import lombok.Value;
import net.runelite.api.events.Event;
/**
* Called when another discord user wants to join the game of the logged in user
*/
@Value
public class DiscordJoinRequest implements Event
public class DiscordJoinRequest
{
/**
* The userId for the user that requests to join

View File

@@ -25,13 +25,12 @@
package net.runelite.client.discord.events;
import lombok.Value;
import net.runelite.api.events.Event;
/**
* Called when the RPC connection has been established
*/
@Value
public class DiscordReady implements Event
public class DiscordReady
{
/**
* The userId for the active user

View File

@@ -25,13 +25,12 @@
package net.runelite.client.discord.events;
import lombok.Value;
import net.runelite.api.events.Event;
/**
* Called when the logged in user joined to spectate a game
*/
@Value
public class DiscordSpectateGame implements Event
public class DiscordSpectateGame
{
/**
* Obfuscated data of your choosing used as spectate secret

View File

@@ -1,85 +0,0 @@
package net.runelite.client.eventbus;
import com.google.common.collect.ImmutableSet;
import io.reactivex.rxjava3.functions.Consumer;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import static java.lang.invoke.MethodType.methodType;
import java.lang.reflect.Method;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.events.Event;
@Slf4j
public class AccessorGenerator
{
public static Set<Subscription> scanSubscribes(Lookup caller, Object ref)
{
ImmutableSet.Builder<Subscription> builder = ImmutableSet.builder();
final Class<?> refClass = ref.getClass();
caller = getPrivateAccess(refClass, caller).in(refClass);
for (Method method : refClass.getDeclaredMethods())
{
Subscribe sub = method.getAnnotation(Subscribe.class);
if (sub != null)
{
final Consumer accessor;
final Class paramType = method.getParameterTypes()[0];
try
{
accessor = getConsumerFor(caller, ref, method);
}
catch (Throwable t)
{
log.warn("Creating consumer lambda for {} failed!", method, t);
continue;
}
builder.add(new Subscription(paramType, accessor, sub.takeUntil(), sub.subscribe(), sub.observe()));
}
}
return builder.build();
}
@SuppressWarnings("unchecked")
private static <EVENT extends Event> Consumer<EVENT> getConsumerFor(Lookup caller, Object ref, Method method) throws Throwable
{
final MethodHandle methodHandle = caller.unreflect(method);
final MethodType actualConsumer = methodHandle.type().dropParameterTypes(0, 1);
final MethodType eventsConsumer = actualConsumer.erase();
final MethodType factoryType = methodType(Consumer.class, ref.getClass());
final CallSite callsite = LambdaMetafactory.metafactory(
caller, // To get past security checks
"accept", // The name of the method to implement inside the lambda type
factoryType, // Signature of the factory method
eventsConsumer, // Signature of function implementation
methodHandle, // Target method
actualConsumer // Target method signature
);
final MethodHandle factory = callsite.getTarget();
return (Consumer<EVENT>) factory.invoke(ref);
}
private static Lookup getPrivateAccess(Class<?> into, Lookup from)
{
try
{
return MethodHandles.privateLookupIn(into, from);
}
catch (IllegalAccessException a)
{
log.warn("Failed to get private access in {} from {}", into, from, a);
return from;
}
}
}

View File

@@ -1,117 +1,230 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* Copyright (c) 2018, Abex
* 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.eventbus;
import com.jakewharton.rxrelay3.PublishRelay;
import com.jakewharton.rxrelay3.Relay;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.ObservableTransformer;
import io.reactivex.rxjava3.core.Scheduler;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Consumer;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Comparator;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.events.Event;
import net.runelite.client.config.OpenOSRSConfig;
import net.runelite.client.util.ReflectUtil;
@Slf4j
@Singleton
public class EventBus implements EventBusInterface
@RequiredArgsConstructor
@ThreadSafe
public class EventBus
{
private final Map<Object, Object> subscriptionList = new HashMap<>();
private final Map<Class<?>, Relay<Object>> subjectList = new HashMap<>();
private final Map<Object, CompositeDisposable> subscriptionsMap = new HashMap<>();
@Inject
private OpenOSRSConfig openOSRSConfig;
@NonNull
private <T extends Event> Relay<Object> getSubject(Class<T> eventClass)
@FunctionalInterface
public interface SubscriberMethod
{
return subjectList.computeIfAbsent(eventClass, k -> PublishRelay.create().toSerialized());
void invoke(Object event);
}
@NonNull
private CompositeDisposable getCompositeDisposable(@NonNull Object object)
@Value
private static class Subscriber
{
CompositeDisposable compositeDisposable = subscriptionsMap.get(object);
if (compositeDisposable == null)
private final Object object;
private final Method method;
private final float priority;
@EqualsAndHashCode.Exclude
private final SubscriberMethod lamda;
void invoke(final Object arg) throws Exception
{
compositeDisposable = new CompositeDisposable();
subscriptionsMap.put(object, compositeDisposable);
if (lamda != null)
{
lamda.invoke(arg);
}
else
{
method.invoke(object, arg);
}
}
}
private final Consumer<Throwable> exceptionHandler;
private ImmutableMultimap<Class, Subscriber> subscribers = ImmutableMultimap.of();
/**
* Instantiates EventBus with default exception handler
*/
public EventBus()
{
this((e) -> log.warn("Uncaught exception in event subscriber", e));
}
/**
* Registers subscriber to EventBus. All methods in subscriber and it's parent classes are checked for
* {@link Subscribe} annotation and then added to map of subscriptions.
*
* @param object subscriber to register
* @throws IllegalArgumentException in case subscriber method name is wrong (correct format is 'on' + EventName
*/
public synchronized void register(@Nonnull final Object object)
{
final ImmutableMultimap.Builder<Class, Subscriber> builder = ImmutableMultimap.builder();
if (subscribers != null)
{
builder.putAll(subscribers);
}
return compositeDisposable;
builder.orderValuesBy(Comparator.comparing(Subscriber::getPriority).reversed()
.thenComparing(s -> s.object.getClass().getName()));
for (Class<?> clazz = object.getClass(); clazz != null; clazz = clazz.getSuperclass())
{
for (final Method method : clazz.getDeclaredMethods())
{
final Subscribe sub = method.getAnnotation(Subscribe.class);
if (sub == null)
{
continue;
}
Preconditions.checkArgument(method.getReturnType() == Void.TYPE, "@Subscribed method \"" + method + "\" cannot return a value");
Preconditions.checkArgument(method.getParameterCount() == 1, "@Subscribed method \"" + method + "\" must take exactly 1 argument");
Preconditions.checkArgument(!Modifier.isStatic(method.getModifiers()), "@Subscribed method \"" + method + "\" cannot be static");
final Class<?> parameterClazz = method.getParameterTypes()[0];
Preconditions.checkArgument(!parameterClazz.isPrimitive(), "@Subscribed method \"" + method + "\" cannot subscribe to primitives");
Preconditions.checkArgument((parameterClazz.getModifiers() & (Modifier.ABSTRACT | Modifier.INTERFACE)) == 0, "@Subscribed method \"" + method + "\" cannot subscribe to polymorphic classes");
for (Class<?> psc = parameterClazz.getSuperclass(); psc != null; psc = psc.getSuperclass())
{
if (subscribers.containsKey(psc))
{
throw new IllegalArgumentException("@Subscribed method \"" + method + "\" cannot subscribe to class which inherits from subscribed class \"" + psc + "\"");
}
}
final String preferredName = "on" + parameterClazz.getSimpleName();
Preconditions.checkArgument(method.getName().equals(preferredName), "Subscribed method " + method + " should be named " + preferredName);
method.setAccessible(true);
SubscriberMethod lambda = null;
try
{
final MethodHandles.Lookup caller = ReflectUtil.privateLookupIn(clazz);
final MethodType subscription = MethodType.methodType(void.class, parameterClazz);
final MethodHandle target = caller.findVirtual(clazz, method.getName(), subscription);
final CallSite site = LambdaMetafactory.metafactory(
caller,
"invoke",
MethodType.methodType(SubscriberMethod.class, clazz),
subscription.changeParameterType(0, Object.class),
target,
subscription);
final MethodHandle factory = site.getTarget();
lambda = (SubscriberMethod) factory.bindTo(object).invokeExact();
}
catch (Throwable e)
{
log.warn("Unable to create lambda for method {}", method, e);
}
final Subscriber subscriber = new Subscriber(object, method, sub.priority(), lambda);
builder.put(parameterClazz, subscriber);
log.debug("Registering {} - {}", parameterClazz, subscriber);
}
}
subscribers = builder.build();
}
private <T> ObservableTransformer<T, T> applyTake(int until)
/**
* Unregisters all subscribed methods from provided subscriber object.
*
* @param object object to unsubscribe from
*/
public synchronized void unregister(@Nonnull final Object object)
{
return observable -> until > 0 ? observable.take(until) : observable;
}
private <T> ObservableTransformer<T, T> applyScheduler(EventScheduler eventScheduler, boolean subscribe)
{
Scheduler scheduler = eventScheduler.get();
return observable -> scheduler == null ? observable : subscribe ? observable.subscribeOn(scheduler) : observable.observeOn(scheduler);
}
@Override
public <T extends Event> void subscribe(Class<T> eventClass, @NonNull Object lifecycle, @NonNull Consumer<T> action)
{
subscribe(eventClass, lifecycle, action, -1, EventScheduler.DEFAULT, EventScheduler.DEFAULT);
}
@Override
public <T extends Event> void subscribe(Class<T> eventClass, @NonNull Object lifecycle, @NonNull Consumer<T> action, int takeUtil)
{
subscribe(eventClass, lifecycle, action, takeUtil, EventScheduler.DEFAULT, EventScheduler.DEFAULT);
}
@Override
// Subscribe on lifecycle (for example from plugin startUp -> shutdown)
public <T extends Event> void subscribe(Class<T> eventClass, @NonNull Object lifecycle, @NonNull Consumer<T> action, int takeUntil, @Nullable EventScheduler subscribe, @Nullable EventScheduler observe)
{
assert Event.class.isAssignableFrom(eventClass) : "Parameters of methods annotated with @Subscribe should implement net.runelite.api.events.Event";
if (subscriptionList.containsKey(lifecycle) && eventClass.equals(subscriptionList.get(lifecycle)))
if (subscribers == null)
{
return;
}
Disposable disposable = getSubject(eventClass)
.compose(applyTake(takeUntil))
.filter(Objects::nonNull) // Filter out null objects, better safe than sorry
.cast(eventClass) // Cast it for easier usage
.doFinally(() -> unregister(lifecycle))
.compose(applyScheduler(subscribe, true))
.compose(applyScheduler(observe, false))
.subscribe(action, error ->
log.error("Exception in eventbus", error));
final Multimap<Class, Subscriber> map = HashMultimap.create();
map.putAll(subscribers);
getCompositeDisposable(lifecycle).add(disposable);
subscriptionList.put(lifecycle, eventClass);
for (Class<?> clazz = object.getClass(); clazz != null; clazz = clazz.getSuperclass())
{
for (final Method method : clazz.getDeclaredMethods())
{
final Subscribe sub = method.getAnnotation(Subscribe.class);
if (sub == null)
{
continue;
}
final Class<?> parameterClazz = method.getParameterTypes()[0];
map.remove(parameterClazz, new Subscriber(object, method, sub.priority(), null));
}
}
subscribers = ImmutableMultimap.copyOf(map);
}
@Override
public void unregister(@NonNull Object lifecycle)
/**
* Posts provided event to all registered subscribers. Subscriber calls are invoked immediately,
* ordered by priority then their declaring class' name.
*
* @param event event to post
*/
public void post(@Nonnull final Object event)
{
//We have to remove the composition from the map, because once you dispose it can't be used anymore
CompositeDisposable compositeDisposable = subscriptionsMap.remove(lifecycle);
subscriptionList.remove(lifecycle);
if (compositeDisposable != null)
for (final Subscriber subscriber : subscribers.get(event.getClass()))
{
compositeDisposable.dispose();
try
{
subscriber.invoke(event);
}
catch (Exception e)
{
exceptionHandler.accept(e);
}
}
}
@Override
public <T extends Event> void post(Class<? extends T> eventClass, @NonNull T event)
{
getSubject(eventClass).accept(event);
}
}

View File

@@ -1,18 +0,0 @@
package net.runelite.client.eventbus;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.functions.Consumer;
import net.runelite.api.events.Event;
public interface EventBusInterface
{
<T extends Event> void subscribe(Class<T> eventClass, @NonNull Object lifecycle, @NonNull Consumer<T> action);
<T extends Event> void subscribe(Class<T> eventClass, @NonNull Object lifecycle, @NonNull Consumer<T> action, int takeUntil);
<T extends Event> void subscribe(Class<T> eventClass, @NonNull Object lifecycle, @NonNull Consumer<T> action, int takeUntil, EventScheduler subscribe, EventScheduler observe);
void unregister(@NonNull Object lifecycle);
<T extends Event> void post(Class<? extends T> eventClass, @NonNull T event);
}

View File

@@ -1,35 +0,0 @@
package net.runelite.client.eventbus;
import io.reactivex.rxjava3.core.Scheduler;
import io.reactivex.rxjava3.functions.Supplier;
import io.reactivex.rxjava3.schedulers.Schedulers;
import javax.annotation.Nullable;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public enum EventScheduler
{
DEFAULT(() -> null),
COMPUTATION(Schedulers::computation),
IO(Schedulers::io),
NEWTHREAD(Schedulers::newThread),
SINGLE(Schedulers::single),
TRAMPOLINE(Schedulers::trampoline),
CLIENT(Schedulers::single);
private Supplier<Scheduler> scheduler;
@Nullable
public Scheduler get()
{
try
{
return scheduler.get();
}
catch (Throwable ignored)
{
}
return null;
}
}

View File

@@ -38,7 +38,5 @@ import java.lang.annotation.Target;
@Documented
public @interface Subscribe
{
int takeUntil() default -1;
EventScheduler subscribe() default EventScheduler.DEFAULT;
EventScheduler observe() default EventScheduler.DEFAULT;
float priority() default 0;
}

View File

@@ -1,20 +0,0 @@
package net.runelite.client.eventbus;
import io.reactivex.rxjava3.functions.Consumer;
import lombok.Value;
@Value
public class Subscription
{
private final Class type;
private final Consumer method;
private final int takeUntil;
private final EventScheduler subscribe;
private final EventScheduler observe;
@SuppressWarnings("unchecked")
public void subscribe(EventBus eventBus, Object lifecycle)
{
eventBus.subscribe(type, lifecycle, method, takeUntil, subscribe, observe);
}
}

View File

@@ -1,34 +0,0 @@
package net.runelite.client.events;
import lombok.Value;
import net.runelite.api.Player;
import net.runelite.api.events.Event;
import net.runelite.client.game.AttackStyle;
/**
* This will fire when {@link net.runelite.client.game.PlayerManager} detects
* a change in the player appearance that resulted in the shifting of an attack style.
* For example, ranged str went to 0, but melee str went to 108.
*/
@Value
public class AttackStyleChanged implements Event
{
/**
* The player that changed styles.
*/
Player player;
/**
* Can be Unknown(nullable)
*
* @see net.runelite.client.game.AttackStyle
*/
AttackStyle oldStyle;
/**
* Can be Unknown(nullable)
*
* @see net.runelite.client.game.AttackStyle
*/
AttackStyle newStyle;
}

View File

@@ -24,18 +24,7 @@
*/
package net.runelite.client.events;
import lombok.Getter;
import net.runelite.api.events.Event;
public abstract class ChatInput implements Event
public abstract class ChatInput
{
@Getter
private boolean stop = false;
public void setStop()
{
this.stop = true;
}
public abstract void resume();
}

View File

@@ -31,13 +31,12 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.events.Event;
@Value
@Slf4j
public class ClientShutdown implements Event
public class ClientShutdown
{
Queue<Future<?>> tasks = new ConcurrentLinkedQueue<>();
private Queue<Future<?>> tasks = new ConcurrentLinkedQueue<>();
public void waitFor(Future<?> future)
{

View File

@@ -24,15 +24,15 @@
*/
package net.runelite.client.events;
import java.io.Serializable;
import javax.annotation.Nullable;
import lombok.Data;
import net.runelite.api.events.Event;
import net.runelite.client.config.RuneScapeProfile;
/**
* An event where a configuration entry has been modified.
*/
@Data
public class ConfigChanged implements Event, Serializable
public class ConfigChanged
{
/**
* The parent group for the key.
@@ -41,6 +41,14 @@ public class ConfigChanged implements Event, Serializable
* between other key values that may have the same name.
*/
private String group;
/**
* The profile that has changed, if any
*
* @see RuneScapeProfile#getKey()
*/
@Nullable
private String profile;
/**
* The configuration key that has been modified.
*/
@@ -53,12 +61,4 @@ public class ConfigChanged implements Event, Serializable
* The new value of the entry, null if the entry has been unset.
*/
private String newValue;
/**
* The client where the config value was changed from
*/
private String origin;
/**
* Path of the current config file
*/
private String path;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 Owain van Brakel <https://github.com/Owain94>
* Copyright (c) 2019 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,14 +24,15 @@
*/
package net.runelite.client.events;
import lombok.Data;
import net.runelite.api.events.Event;
import net.runelite.client.plugins.Plugin;
import java.util.List;
import lombok.Value;
import net.runelite.client.externalplugins.ExternalPluginManifest;
@Data
public class ExternalPluginChanged implements Event
/**
* Posted when an external plugin has been added, removed, or updated
*/
@Value
public class ExternalPluginsChanged
{
private final String pluginId;
private final Plugin plugin;
private final boolean added;
private final List<ExternalPluginManifest> loadedManifest;
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (c) 2019 Owain van Brakel <https://github.com/Owain94>
* 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.events;
import lombok.Data;
import net.runelite.api.events.Event;
@Data
public class ExternalPluginsLoaded implements Event
{}

View File

@@ -25,13 +25,12 @@
package net.runelite.client.events;
import lombok.Value;
import net.runelite.api.events.Event;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.infobox.InfoBox;
@Value
public class InfoBoxMenuClicked implements Event
public class InfoBoxMenuClicked
{
OverlayMenuEntry entry;
InfoBox infoBox;
private OverlayMenuEntry entry;
private InfoBox infoBox;
}

View File

@@ -25,11 +25,10 @@
package net.runelite.client.events;
import lombok.Value;
import net.runelite.api.events.Event;
import net.runelite.client.ui.NavigationButton;
@Value
public class NavigationButtonAdded implements Event
public class NavigationButtonAdded
{
NavigationButton button;
private NavigationButton button;
}

View File

@@ -25,11 +25,10 @@
package net.runelite.client.events;
import lombok.Value;
import net.runelite.api.events.Event;
import net.runelite.client.ui.NavigationButton;
@Value
public class NavigationButtonRemoved implements Event
public class NavigationButtonRemoved
{
NavigationButton button;
private NavigationButton button;
}

View File

@@ -26,11 +26,10 @@ package net.runelite.client.events;
import java.awt.TrayIcon;
import lombok.Value;
import net.runelite.api.events.Event;
@Value
public class NotificationFired implements Event
public class NotificationFired
{
String message;
TrayIcon.MessageType type;
final String message;
final TrayIcon.MessageType type;
}

View File

@@ -27,12 +27,11 @@ package net.runelite.client.events;
import java.util.Collection;
import lombok.Value;
import net.runelite.api.NPC;
import net.runelite.api.events.Event;
import net.runelite.client.game.ItemStack;
@Value
public class NpcLootReceived implements Event
public class NpcLootReceived
{
NPC npc;
Collection<ItemStack> items;
private final NPC npc;
private final Collection<ItemStack> items;
}

View File

@@ -24,19 +24,16 @@
*/
package net.runelite.client.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import net.runelite.api.events.Event;
import lombok.Value;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
/**
* Event fired when an overlay menu entry is clicked.
*/
@Data
@AllArgsConstructor
public class OverlayMenuClicked implements Event
@Value
public class OverlayMenuClicked
{
private OverlayMenuEntry entry;
private Overlay overlay;
}
}

View File

@@ -26,10 +26,9 @@ package net.runelite.client.events;
import java.util.UUID;
import lombok.Value;
import net.runelite.api.events.Event;
@Value
public class PartyChanged implements Event
public class PartyChanged
{
UUID partyId;
private final UUID partyId;
}

View File

@@ -27,12 +27,11 @@ package net.runelite.client.events;
import java.util.Collection;
import lombok.Value;
import net.runelite.api.Player;
import net.runelite.api.events.Event;
import net.runelite.client.game.ItemStack;
@Value
public class PlayerLootReceived implements Event
public class PlayerLootReceived
{
Player player;
Collection<ItemStack> items;
private final Player player;
private final Collection<ItemStack> items;
}

View File

@@ -25,11 +25,10 @@
package net.runelite.client.events;
import lombok.Data;
import net.runelite.api.events.Event;
import net.runelite.client.plugins.Plugin;
@Data
public class PluginChanged implements Event
public class PluginChanged
{
private final Plugin plugin;
private final boolean loaded;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 Owain van Brakel <https://github.com/Owain94>
* Copyright (c) 2020 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,12 +24,11 @@
*/
package net.runelite.client.events;
import lombok.Data;
import net.runelite.api.events.Event;
@Data
public class ExternalRepositoryChanged implements Event
/**
* Posted when the user switches to a different RuneScape save profile
* This might be because they logged into a different account, or hopped
* to/from a Beta/Tournament/DMM/Leagues world
*/
public class RuneScapeProfileChanged
{
private final String owner;
private final boolean added;
}

View File

@@ -25,7 +25,6 @@
package net.runelite.client.events;
import lombok.Data;
import net.runelite.api.events.Event;
/**
* An event where a new RuneLite account session has been closed,
@@ -35,4 +34,7 @@ import net.runelite.api.events.Event;
* it has nothing to do with whether an account is being logged out.
*/
@Data
public class SessionClose implements Event {}
public class SessionClose
{
}

View File

@@ -25,7 +25,6 @@
package net.runelite.client.events;
import lombok.Data;
import net.runelite.api.events.Event;
/**
* An event where a new RuneLite account session has been opened
@@ -35,4 +34,7 @@ import net.runelite.api.events.Event;
* it has nothing to do with whether an account is being logged in.
*/
@Data
public class SessionOpen implements Event {}
public class SessionOpen
{
}

View File

@@ -25,14 +25,13 @@
package net.runelite.client.events;
import lombok.Value;
import net.runelite.api.events.Event;
import net.runelite.http.api.worlds.WorldResult;
/**
* Fired when the @{link net.runelite.client.game.WorldService} refreshes the world list
*/
@Value
public class WorldsFetch implements Event
public class WorldsFetch
{
WorldResult worldResult;
}
private final WorldResult worldResult;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2019 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,17 +22,20 @@
* (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.ui.components;
package net.runelite.client.externalplugins;
import java.awt.Dimension;
import javax.swing.JPanel;
import net.runelite.client.ui.PluginPanel;
import java.net.URL;
import java.net.URLClassLoader;
import lombok.Getter;
class FixedWidthPanel extends JPanel
class ExternalPluginClassLoader extends URLClassLoader
{
@Override
public Dimension getPreferredSize()
@Getter
private final ExternalPluginManifest manifest;
ExternalPluginClassLoader(ExternalPluginManifest manifest, URL[] urls)
{
return new Dimension(PluginPanel.PANEL_WIDTH, super.getPreferredSize().height);
super(urls, ExternalPluginClassLoader.class.getClassLoader());
this.manifest = manifest;
}
}
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 2019 Abex
* 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.externalplugins;
import com.google.common.reflect.TypeToken;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.List;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLiteProperties;
import net.runelite.client.util.VerificationException;
import net.runelite.http.api.RuneLiteAPI;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.BufferedSource;
@Slf4j
public class ExternalPluginClient
{
private final OkHttpClient okHttpClient;
@Inject
private ExternalPluginClient(OkHttpClient okHttpClient)
{
this.okHttpClient = okHttpClient;
}
public List<ExternalPluginManifest> downloadManifest() throws IOException, VerificationException
{
HttpUrl manifest = RuneLiteProperties.getPluginHubBase()
.newBuilder()
.addPathSegments("manifest.js")
.build();
try (Response res = okHttpClient.newCall(new Request.Builder().url(manifest).build()).execute())
{
if (res.code() != 200)
{
throw new IOException("Non-OK response code: " + res.code());
}
BufferedSource src = res.body().source();
byte[] signature = new byte[src.readInt()];
src.readFully(signature);
byte[] data = src.readByteArray();
Signature s = Signature.getInstance("SHA256withRSA");
s.initVerify(loadCertificate());
s.update(data);
if (!s.verify(signature))
{
throw new VerificationException("Unable to verify external plugin manifest");
}
return RuneLiteAPI.GSON.fromJson(new String(data, StandardCharsets.UTF_8),
new TypeToken<List<ExternalPluginManifest>>()
{
}.getType());
}
catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e)
{
throw new RuntimeException(e);
}
}
public BufferedImage downloadIcon(ExternalPluginManifest plugin) throws IOException
{
if (!plugin.hasIcon())
{
return null;
}
HttpUrl url = RuneLiteProperties.getPluginHubBase()
.newBuilder()
.addPathSegment(plugin.getInternalName())
.addPathSegment(plugin.getCommit() + ".png")
.build();
try (Response res = okHttpClient.newCall(new Request.Builder().url(url).build()).execute())
{
byte[] bytes = res.body().bytes();
// We don't stream so the lock doesn't block the edt trying to load something at the same time
synchronized (ImageIO.class)
{
return ImageIO.read(new ByteArrayInputStream(bytes));
}
}
}
private static Certificate loadCertificate()
{
try
{
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
Certificate certificate = certFactory.generateCertificate(ExternalPluginClient.class.getResourceAsStream("externalplugins.crt"));
return certificate;
}
catch (CertificateException e)
{
throw new RuntimeException(e);
}
}
void submitPlugins(List<String> plugins)
{
if (plugins.isEmpty())
{
return;
}
HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
.addPathSegment("pluginhub")
.build();
Request request = new Request.Builder()
.url(url)
.post(RequestBody.create(RuneLiteAPI.JSON, RuneLiteAPI.GSON.toJson(plugins)))
.build();
okHttpClient.newCall(request).enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
log.debug("Error submitting plugins", e);
}
@Override
public void onResponse(Call call, Response response)
{
log.debug("Submitted plugin list");
response.close();
}
});
}
}

View File

@@ -0,0 +1,429 @@
/*
* Copyright (c) 2019 Abex
* 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.externalplugins;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.hash.Hashing;
import com.google.common.hash.HashingInputStream;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.swing.SwingUtilities;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite;
import net.runelite.client.RuneLiteProperties;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ExternalPluginsChanged;
import net.runelite.client.events.SessionClose;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginInstantiationException;
import net.runelite.client.plugins.PluginManager;
import net.runelite.client.ui.SplashScreen;
import net.runelite.client.util.CountingInputStream;
import net.runelite.client.util.Text;
import net.runelite.client.util.VerificationException;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
@Singleton
@Slf4j
public class ExternalPluginManager
{
private static final String PLUGIN_LIST_KEY = "externalPlugins";
private static Class<? extends Plugin>[] builtinExternals = null;
@Inject
@Named("safeMode")
private boolean safeMode;
private final ConfigManager configManager;
private final ExternalPluginClient externalPluginClient;
private final ScheduledExecutorService executor;
private final PluginManager pluginManager;
private final EventBus eventBus;
private final OkHttpClient okHttpClient;
@Inject
private ExternalPluginManager(
ConfigManager configManager,
ExternalPluginClient externalPluginClient,
ScheduledExecutorService executor,
PluginManager pluginManager,
EventBus eventBus,
OkHttpClient okHttpClient
)
{
this.configManager = configManager;
this.externalPluginClient = externalPluginClient;
this.executor = executor;
this.pluginManager = pluginManager;
this.eventBus = eventBus;
this.okHttpClient = okHttpClient;
executor.scheduleWithFixedDelay(() -> externalPluginClient.submitPlugins(getInstalledExternalPlugins()),
new Random().nextInt(60), 180, TimeUnit.MINUTES);
}
public void loadExternalPlugins() throws PluginInstantiationException
{
refreshPlugins();
if (builtinExternals != null)
{
// builtin external's don't actually have a manifest or a separate classloader...
pluginManager.loadPlugins(Lists.newArrayList(builtinExternals), null);
}
}
@Subscribe
public void onSessionOpen(SessionOpen event)
{
executor.submit(this::refreshPlugins);
}
@Subscribe
public void onSessionClose(SessionClose event)
{
executor.submit(this::refreshPlugins);
}
private void refreshPlugins()
{
if (safeMode)
{
log.debug("External plugins are disabled in safe mode!");
return;
}
Multimap<ExternalPluginManifest, Plugin> loadedExternalPlugins = HashMultimap.create();
for (Plugin p : pluginManager.getPlugins())
{
ExternalPluginManifest m = getExternalPluginManifest(p.getClass());
if (m != null)
{
loadedExternalPlugins.put(m, p);
}
}
List<String> installedIDs = getInstalledExternalPlugins();
if (installedIDs.isEmpty() && loadedExternalPlugins.isEmpty())
{
return;
}
boolean startup = SplashScreen.isOpen();
try
{
double splashStart = startup ? .60 : 0;
double splashLength = startup ? .10 : 1;
if (!startup)
{
SplashScreen.init();
}
SplashScreen.stage(splashStart, null, "Downloading external plugins");
Set<ExternalPluginManifest> externalPlugins = new HashSet<>();
RuneLite.PLUGINS_DIR.mkdirs();
List<ExternalPluginManifest> manifestList;
try
{
manifestList = externalPluginClient.downloadManifest();
Map<String, ExternalPluginManifest> manifests = manifestList
.stream().collect(ImmutableMap.toImmutableMap(ExternalPluginManifest::getInternalName, Function.identity()));
Set<ExternalPluginManifest> needsDownload = new HashSet<>();
Set<File> keep = new HashSet<>();
for (String name : installedIDs)
{
ExternalPluginManifest manifest = manifests.get(name);
if (manifest != null)
{
externalPlugins.add(manifest);
if (!manifest.isValid())
{
needsDownload.add(manifest);
}
else
{
keep.add(manifest.getJarFile());
}
}
}
// delete old plugins
File[] files = RuneLite.PLUGINS_DIR.listFiles();
if (files != null)
{
for (File fi : files)
{
if (!keep.contains(fi))
{
fi.delete();
}
}
}
int toDownload = needsDownload.stream().mapToInt(ExternalPluginManifest::getSize).sum();
int downloaded = 0;
for (ExternalPluginManifest manifest : needsDownload)
{
HttpUrl url = RuneLiteProperties.getPluginHubBase().newBuilder()
.addPathSegment(manifest.getInternalName())
.addPathSegment(manifest.getCommit() + ".jar")
.build();
try (Response res = okHttpClient.newCall(new Request.Builder().url(url).build()).execute())
{
int fdownloaded = downloaded;
downloaded += manifest.getSize();
HashingInputStream his = new HashingInputStream(Hashing.sha256(),
new CountingInputStream(res.body().byteStream(), i ->
SplashScreen.stage(splashStart + (splashLength * .2), splashStart + (splashLength * .8),
null, "Downloading " + manifest.getDisplayName(),
i + fdownloaded, toDownload, true)));
Files.asByteSink(manifest.getJarFile()).writeFrom(his);
if (!his.hash().toString().equals(manifest.getHash()))
{
throw new VerificationException("Plugin " + manifest.getInternalName() + " didn't match its hash");
}
}
catch (IOException | VerificationException e)
{
externalPlugins.remove(manifest);
log.error("Unable to download external plugin \"{}\"", manifest.getInternalName(), e);
}
}
}
catch (IOException | VerificationException e)
{
log.error("Unable to download external plugins", e);
return;
}
SplashScreen.stage(splashStart + (splashLength * .8), null, "Starting external plugins");
// TODO(abex): make sure the plugins get fully removed from the scheduler/eventbus/other managers (iterate and check classloader)
Set<ExternalPluginManifest> add = new HashSet<>();
for (ExternalPluginManifest ex : externalPlugins)
{
if (loadedExternalPlugins.removeAll(ex).size() <= 0)
{
add.add(ex);
}
}
// list of loaded external plugins that aren't in the manifest
Collection<Plugin> remove = loadedExternalPlugins.values();
for (Plugin p : remove)
{
log.info("Stopping external plugin \"{}\"", p.getClass());
try
{
SwingUtilities.invokeAndWait(() ->
{
try
{
pluginManager.stopPlugin(p);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
});
}
catch (InterruptedException | InvocationTargetException e)
{
log.warn("Unable to stop external plugin \"{}\"", p.getClass().getName(), e);
}
pluginManager.remove(p);
}
for (ExternalPluginManifest manifest : add)
{
// I think this can't happen, but just in case
if (!manifest.isValid())
{
log.warn("Invalid plugin for validated manifest: {}", manifest);
continue;
}
log.info("Loading external plugin \"{}\" version \"{}\" commit \"{}\"", manifest.getInternalName(), manifest.getVersion(), manifest.getCommit());
List<Plugin> newPlugins = null;
try
{
ClassLoader cl = new ExternalPluginClassLoader(manifest, new URL[]{manifest.getJarFile().toURI().toURL()});
List<Class<?>> clazzes = new ArrayList<>();
for (String className : manifest.getPlugins())
{
clazzes.add(cl.loadClass(className));
}
List<Plugin> newPlugins2 = newPlugins = pluginManager.loadPlugins(clazzes, null);
if (!startup)
{
pluginManager.loadDefaultPluginConfiguration(newPlugins);
SwingUtilities.invokeAndWait(() ->
{
try
{
for (Plugin p : newPlugins2)
{
pluginManager.startPlugin(p);
}
}
catch (PluginInstantiationException e)
{
throw new RuntimeException(e);
}
});
}
}
catch (ThreadDeath e)
{
throw e;
}
catch (Throwable e)
{
log.warn("Unable to start or load external plugin \"{}\"", manifest.getInternalName(), e);
if (newPlugins != null)
{
for (Plugin p : newPlugins)
{
try
{
SwingUtilities.invokeAndWait(() ->
{
try
{
pluginManager.stopPlugin(p);
}
catch (Exception e2)
{
throw new RuntimeException(e2);
}
});
}
catch (InterruptedException | InvocationTargetException e2)
{
log.info("Unable to fully stop plugin \"{}\"", manifest.getInternalName(), e2);
}
pluginManager.remove(p);
}
}
}
}
if (!startup)
{
eventBus.post(new ExternalPluginsChanged(manifestList));
}
}
finally
{
if (!startup)
{
SplashScreen.stop();
}
}
}
public List<String> getInstalledExternalPlugins()
{
String externalPluginsStr = configManager.getConfiguration(RuneLiteConfig.GROUP_NAME, PLUGIN_LIST_KEY);
return Text.fromCSV(externalPluginsStr == null ? "" : externalPluginsStr);
}
public void install(String key)
{
Set<String> plugins = new HashSet<>(getInstalledExternalPlugins());
if (plugins.add(key))
{
configManager.setConfiguration(RuneLiteConfig.GROUP_NAME, PLUGIN_LIST_KEY, Text.toCSV(plugins));
executor.submit(this::refreshPlugins);
}
}
public void remove(String key)
{
Set<String> plugins = new HashSet<>(getInstalledExternalPlugins());
if (plugins.remove(key))
{
configManager.setConfiguration(RuneLiteConfig.GROUP_NAME, PLUGIN_LIST_KEY, Text.toCSV(plugins));
executor.submit(this::refreshPlugins);
}
}
public void update()
{
executor.submit(this::refreshPlugins);
}
public static ExternalPluginManifest getExternalPluginManifest(Class<? extends Plugin> plugin)
{
ClassLoader cl = plugin.getClassLoader();
if (cl instanceof ExternalPluginClassLoader)
{
ExternalPluginClassLoader ecl = (ExternalPluginClassLoader) cl;
return ecl.getManifest();
}
return null;
}
public static void loadBuiltin(Class<? extends Plugin>... plugins)
{
builtinExternals = plugins;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, TheStonedTurtle <http://www.github.com/TheStonedTurtle>
* Copyright (c) 2019 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,23 +22,68 @@
* (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.ui.components;
package net.runelite.client.externalplugins;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.annotation.Nullable;
import javax.swing.Icon;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.runelite.client.RuneLite;
/**
* Used with ComboBoxListRenderer to render an icon next to the text of the list entry.
* Also supports adding a data object to be used for more complex selection logic
*/
@AllArgsConstructor
@Getter
public class ComboBoxIconEntry
@Data
public class ExternalPluginManifest
{
private Icon icon;
private String text;
private String internalName;
private String commit;
private String hash;
private int size;
private String[] plugins;
private String displayName;
private String version;
private String author;
@Nullable
private Object data;
}
private String description;
@Nullable
private String warning;
@Nullable
private String[] tags;
@EqualsAndHashCode.Exclude
private URL support;
private boolean hasIcon;
public boolean hasIcon()
{
return hasIcon;
}
File getJarFile()
{
return new File(RuneLite.PLUGINS_DIR, internalName + commit + ".jar");
}
boolean isValid()
{
File file = getJarFile();
try
{
if (file.exists())
{
String hash = Files.asByteSource(file).hash(Hashing.sha256()).toString();
if (this.hash.equals(hash))
{
return true;
}
}
}
catch (IOException e)
{
}
return false;
}
}

View File

@@ -28,56 +28,57 @@ package net.runelite.client.game;
import lombok.Getter;
import static net.runelite.api.NullObjectID.*;
import static net.runelite.api.ObjectID.*;
import net.runelite.api.TileObject;
import net.runelite.api.coords.WorldPoint;
@Getter
public enum AgilityShortcut
{
GENERIC_SHORTCUT(1, "Shortcut", null,
// Trollheim
ROCKS_3790, ROCKS_3791,
// Fremennik Slayer Cave
STEPS_29993,
// Fossil Island
LADDER_30938, LADDER_30939, LADDER_30940, LADDER_30941, RUBBER_CAP_MUSHROOM,
// Brimhaven dungeon
CREVICE_30198,
// Lumbridge
STILE_12982,
// Gu'Tanoth Bridge
GAP, GAP_2831,
// Lumbridge Swamp Caves
STEPPING_STONE_5948, STEPPING_STONE_5949, ROCKS_6673,
// Morytania Pirate Ship
ROCK_16115,
// Lumber Yard
BROKEN_FENCE_2618,
// McGrubor's Wood
LOOSE_RAILING,
// Underwater Area Fossil Island
TUNNEL_30959, HOLE_30966, OBSTACLE, OBSTACLE_30767, OBSTACLE_30964, OBSTACLE_30962, PLANT_DOOR_30961,
// Tree Gnome Village
LOOSE_RAILING_2186,
// Burgh de Rott
LOW_FENCE,
// Taverley
STILE,
// Asgarnian Ice Dungeon
STEPS,
// Fossil Island Wyvern Cave
STAIRS_31485,
// Trollweiss Mountain Cave
ROCKY_HANDHOLDS, ROCKY_HANDHOLDS_19847,
// Witchaven Dungeon
SHORTCUT),
// Trollheim
ROCKS_3790, ROCKS_3791,
// Fremennik Slayer Cave
STEPS_29993,
// Fossil Island
LADDER_30938, LADDER_30939, LADDER_30940, LADDER_30941, RUBBER_CAP_MUSHROOM,
// Brimhaven dungeon
CREVICE_30198,
// Lumbridge
STILE_12982,
// Gu'Tanoth Bridge
GAP, GAP_2831,
// Lumbridge Swamp Caves
STEPPING_STONE_5948, STEPPING_STONE_5949, ROCKS_6673,
// Morytania Pirate Ship
ROCK_16115,
// Lumber Yard
BROKEN_FENCE_2618,
// McGrubor's Wood
LOOSE_RAILING,
// Underwater Area Fossil Island
TUNNEL_30959, HOLE_30966, OBSTACLE, OBSTACLE_30767, OBSTACLE_30964, OBSTACLE_30962, PLANT_DOOR_30961,
// Tree Gnome Village
LOOSE_RAILING_2186,
// Burgh de Rott
LOW_FENCE,
// Taverley
STILE,
// Asgarnian Ice Dungeon
STEPS,
// Fossil Island Wyvern Cave
STAIRS_31485,
// Trollweiss Mountain Cave
ROCKY_HANDHOLDS, ROCKY_HANDHOLDS_19847,
// Witchaven Dungeon
SHORTCUT),
BRIMHAVEN_DUNGEON_MEDIUM_PIPE_RETURN(1, "Pipe Squeeze", null, new WorldPoint(2698, 9491, 0), PIPE_21727),
BRIMHAVEN_DUNGEON_PIPE_RETURN(1, "Pipe Squeeze", null, new WorldPoint(2655, 9573, 0), PIPE_21728),
BRIMHAVEN_DUNGEON_STEPPING_STONES_RETURN(1, "Pipe Squeeze", null, STEPPING_STONE_21739),
BRIMHAVEN_DUNGEON_LOG_BALANCE_RETURN(1, "Log Balance", null, LOG_BALANCE_20884),
AGILITY_PYRAMID_ROCKS_WEST(1, "Rocks", null, CLIMBING_ROCKS_11948),
CAIRN_ISLE_CLIMBING_ROCKS(1, "Rocks", null, CLIMBING_ROCKS),
KARAMJA_GLIDER_LOG(1, "Log Balance", new WorldPoint(2906, 3050, 0), A_WOODEN_LOG),
FALADOR_CRUMBLING_WALL(5, "Crumbling Wall", new WorldPoint(2936, 3357, 0), CRUMBLING_WALL_24222),
KARAMJA_GLIDER_LOG(1, "Log Balance", new WorldPoint(2906, 3050, 0), A_WOODEN_LOG ),
FALADOR_CRUMBLING_WALL(5, "Crumbling Wall", new WorldPoint(2936, 3357, 0), CRUMBLING_WALL_24222 ),
RIVER_LUM_GRAPPLE_WEST(8, "Grapple Broken Raft", new WorldPoint(3245, 3179, 0), BROKEN_RAFT),
RIVER_LUM_GRAPPLE_EAST(8, "Grapple Broken Raft", new WorldPoint(3258, 3179, 0), BROKEN_RAFT),
CORSAIR_COVE_ROCKS(10, "Rocks", new WorldPoint(2545, 2871, 0), ROCKS_31757),
@@ -88,7 +89,7 @@ public enum AgilityShortcut
GOBLIN_VILLAGE_WALL(14, "Wall", new WorldPoint(2925, 3523, 0), TIGHTGAP),
CORSAIR_COVE_DUNGEON_PILLAR(15, "Pillar Jump", new WorldPoint(1980, 8996, 0), PILLAR_31809),
EDGEVILLE_DUNGEON_MONKEYBARS(15, "Monkey Bars", null, MONKEYBARS_23566),
TROLLHEIM_ROCKS(15, "Rocks", null, new WorldPoint(2838, 3614, 0), ROCKS_3748), // No fixed world map location, but rocks near death plateau have a requirement of 15
TROLLHEIM_ROCKS(15, "Rocks", null, new WorldPoint(2838, 3614, 0), ROCKS_3748), // No fixed world map location, but rocks near death plateau have a requirement of 15
YANILLE_UNDERWALL_TUNNEL(16, "Underwall Tunnel", new WorldPoint(2574, 3109, 0), HOLE_16520, CASTLE_WALL),
KOUREND_CATACOMBS_SOUTH_WEST_CREVICE_NORTH(17, "Crevice", new WorldPoint(1647, 10008, 0), CRACK_28892),
KOUREND_CATACOMBS_SOUTH_WEST_CREVICE_SOUTH(17, "Crevice", new WorldPoint(1645, 10001, 0), CRACK_28892),
@@ -151,7 +152,7 @@ public enum AgilityShortcut
ISAFDAR_FOREST_OBSTACLES(56, "Trap", null, DENSE_FOREST_3938, DENSE_FOREST_3939, DENSE_FOREST_3998, DENSE_FOREST_3999, DENSE_FOREST, LEAVES, LEAVES_3924, LEAVES_3925, STICKS, TRIPWIRE, TRIPWIRE_3921),
RELEKKA_EAST_FENCE(57, "Fence", new WorldPoint(2688, 3697, 0), BROKEN_FENCE),
YANILLE_DUNGEON_MONKEY_BARS(57, "Monkey Bars", null, MONKEYBARS_23567),
PHASMATYS_ECTOPOOL_SHORTCUT(58, "Weathered Wall", null, WEATHERED_WALL, WEATHERED_WALL_16526),
PHASMATYS_ECTOPOOL_SHORTCUT(58, "Weathered Wall", null , WEATHERED_WALL, WEATHERED_WALL_16526),
ELVEN_OVERPASS_CLIFF_SCRAMBLE(59, "Rocks", new WorldPoint(2345, 3300, 0), ROCKS_16514, ROCKS_16515),
ELVEN_OVERPASS_CLIFF_SCRAMBLE_PRIFDDINAS(59, "Rocks", new WorldPoint(3369, 6052, 0), ROCKS_16514, ROCKS_16515),
WILDERNESS_GWD_CLIMB_EAST(60, "Rocks", new WorldPoint(2943, 3770, 0), ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406),
@@ -182,9 +183,17 @@ public enum AgilityShortcut
TAVERLEY_DUNGEON_PIPE_BLUE_DRAGON(70, "Pipe Squeeze", new WorldPoint(2886, 9798, 0), OBSTACLE_PIPE_16509),
TAVERLEY_DUNGEON_ROCKS_NORTH(70, "Rocks", new WorldPoint(2887, 9823, 0), ROCKS, ROCKS_14106),
TAVERLEY_DUNGEON_ROCKS_SOUTH(70, "Rocks", new WorldPoint(2887, 9631, 0), ROCKS, ROCKS_14106),
FOSSIL_ISLAND_HARDWOOD_NORTH(70, "Hole", new WorldPoint(3712, 3828, 0), HOLE_31481, HOLE_31482),
FOSSIL_ISLAND_HARDWOOD_SOUTH(70, "Hole", new WorldPoint(3714, 3816, 0), HOLE_31481, HOLE_31482),
AL_KHARID_WINDOW(70, "Window", new WorldPoint(3293, 3158, 0), BROKEN_WALL_33344, BIG_WINDOW),
FOSSIL_ISLAND_HARDWOOD_NORTH(70, "Hole" , new WorldPoint(3712, 3828, 0), HOLE_31481, HOLE_31482),
FOSSIL_ISLAND_HARDWOOD_SOUTH(70, "Hole" , new WorldPoint(3714, 3816, 0), HOLE_31481, HOLE_31482),
AL_KHARID_WINDOW(70, "Window", new WorldPoint(3295, 3158, 0), BROKEN_WALL_33344, BIG_WINDOW)
{
@Override
public boolean matches(TileObject object)
{
// there are two BIG_WINDOW objects right next to each other here, but only this one is valid
return object.getId() != BIG_WINDOW || object.getWorldLocation().equals(getWorldLocation());
}
},
GWD_SARADOMIN_ROPE_NORTH(70, "Rope Descent", new WorldPoint(2912, 5300, 0), NULL_26371, NULL_26561),
GWD_SARADOMIN_ROPE_SOUTH(70, "Rope Descent", new WorldPoint(2951, 5267, 0), NULL_26375, NULL_26562),
GU_TANOTH_CRUMBLING_WALL(71, "Rocks", new WorldPoint(2545, 3032, 0), CRUMBLING_WALL_40355, ROCKS_40356),
@@ -192,14 +201,14 @@ public enum AgilityShortcut
SLAYER_TOWER_ADVANCED_CHAIN_SECOND(71, "Spiked Chain (Floor 3)", new WorldPoint(3446, 3576, 0), SPIKEY_CHAIN_16538),
STRONGHOLD_SLAYER_CAVE_TUNNEL(72, "Tunnel", new WorldPoint(2431, 9806, 0), TUNNEL_30174, TUNNEL_30175),
TROLL_STRONGHOLD_WALL_CLIMB(73, "Rocks", new WorldPoint(2841, 3694, 0), ROCKS_16464),
ARCEUUS_ESSENSE_MINE_WEST(73, "Rock Climb", new WorldPoint(1742, 3853, 0), ROCKS_27984, ROCKS_27985),
ARCEUUS_ESSENSE_MINE_WEST(73, "Rock Climb", new WorldPoint(1742, 3853, 0), ROCKS_27984, ROCKS_27985 ),
LAVA_DRAGON_ISLE_JUMP(74, "Stepping Stone", new WorldPoint(3200, 3807, 0), STEPPING_STONE_14918),
FORTHOS_DUNGEON_SPIKED_BLADES(75, "Spiked Blades", new WorldPoint(1819, 9946, 0), STRANGE_FLOOR_34834),
REVENANT_CAVES_DEMONS_JUMP(75, "Jump", new WorldPoint(3199, 10135, 0), PILLAR_31561),
REVENANT_CAVES_ANKOU_EAST(75, "Jump", new WorldPoint(3201, 10195, 0), PILLAR_31561),
REVENANT_CAVES_ANKOU_NORTH(75, "Jump", new WorldPoint(3180, 10209, 0), PILLAR_31561),
ZUL_ANDRA_ISLAND_CROSSING(76, "Stepping Stone", new WorldPoint(2156, 3073, 0), STEPPING_STONE_10663),
SHILO_VILLAGE_STEPPING_STONES(77, "Stepping Stones", new WorldPoint(2863, 2974, 0), STEPPING_STONE_16466),
SHILO_VILLAGE_STEPPING_STONES( 77, "Stepping Stones", new WorldPoint(2863, 2974, 0), STEPPING_STONE_16466),
IORWERTHS_DUNGEON_NORTHERN_SHORTCUT_EAST(78, "Tight Gap", new WorldPoint(3221, 12441, 0), TIGHT_GAP),
IORWERTHS_DUNGEON_NORTHERN_SHORTCUT_WEST(78, "Tight Gap", new WorldPoint(3215, 12441, 0), TIGHT_GAP_36693),
KHARAZI_JUNGLE_VINE_CLIMB(79, "Vine", new WorldPoint(2897, 2939, 0), NULL_26884, NULL_26886),
@@ -265,4 +274,9 @@ public enum AgilityShortcut
{
return description + " - Level " + level;
}
public boolean matches(TileObject object)
{
return true;
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (c) 2019, ganom <https://github.com/Ganom>
* 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.game;
import java.awt.Color;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.Prayer;
@AllArgsConstructor
@Getter
public enum AttackStyle
{
MAGE("Mage", Color.CYAN, Prayer.PROTECT_FROM_MAGIC),
RANGE("Range", Color.GREEN, Prayer.PROTECT_FROM_MISSILES),
MELEE("Melee", Color.RED, Prayer.PROTECT_FROM_MELEE),
UNKNOWN("Unknown", Color.WHITE, null);
private String name;
private Color color;
private Prayer prayer;
}

View File

@@ -1,24 +0,0 @@
package net.runelite.client.game;
import lombok.Value;
@Value
public class CombatStats
{
private int magicAttack;
private int magicDefence;
private int magicStr;
private int meleeAtkCrush;
private int meleeAtkSlash;
private int meleeAtkStab;
private int meleeAttack;
private int meleeDefCrush;
private int meleeDefence;
private int meleeDefSlash;
private int meleeDefStab;
private int meleeStr;
private int rangeAttack;
private int rangeDefence;
private int rangeStr;
private int speed;
}

View File

@@ -36,18 +36,18 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.FriendsChatManager;
import net.runelite.api.FriendsChatMember;
import net.runelite.api.FriendsChatManager;
import net.runelite.api.FriendsChatRank;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.IndexedSprite;
import net.runelite.api.SpriteID;
import net.runelite.api.events.FriendsChatChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.util.Text;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.Text;
@Singleton
public class FriendChatManager
@@ -74,7 +74,7 @@ public class FriendChatManager
private final LoadingCache<String, FriendsChatRank> ranksCache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(new CacheLoader<>()
.build(new CacheLoader<String, FriendsChatRank>()
{
@Override
public FriendsChatRank load(@Nonnull String key)
@@ -93,15 +93,10 @@ public class FriendChatManager
private int offset;
@Inject
private FriendChatManager(final Client client,
final SpriteManager spriteManager,
final EventBus eventbus)
private FriendChatManager(Client client, SpriteManager spriteManager)
{
this.client = client;
this.spriteManager = spriteManager;
eventbus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventbus.subscribe(FriendsChatChanged.class, this, this::onFriendsChatChanged);
}
public boolean isMember(String name)
@@ -131,14 +126,16 @@ public class FriendChatManager
return offset + friendsChatRank.ordinal() - 1;
}
private void onGameStateChanged(GameStateChanged gameStateChanged)
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
if (gameStateChanged.getGameState() == GameState.LOGGED_IN && offset == 0)
if (gameStateChanged.getGameState() == GameState.LOGIN_SCREEN && offset == 0)
{
loadRankIcons();
}
}
@Subscribe
public void onFriendsChatChanged(FriendsChatChanged friendsChatChanged)
{
ranksCache.invalidateAll();

View File

@@ -36,7 +36,6 @@ import static net.runelite.client.game.HiscoreManager.NONE;
import net.runelite.http.api.hiscore.HiscoreClient;
import net.runelite.http.api.hiscore.HiscoreEndpoint;
import net.runelite.http.api.hiscore.HiscoreResult;
import org.jetbrains.annotations.NotNull;
@Slf4j
class HiscoreLoader extends CacheLoader<HiscoreManager.HiscoreKey, HiscoreResult>
@@ -51,7 +50,7 @@ class HiscoreLoader extends CacheLoader<HiscoreManager.HiscoreKey, HiscoreResult
}
@Override
public HiscoreResult load(@NotNull HiscoreManager.HiscoreKey hiscoreKey)
public HiscoreResult load(HiscoreManager.HiscoreKey hiscoreKey) throws Exception
{
return EMPTY;
}

View File

@@ -28,9 +28,9 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -49,19 +49,17 @@ import net.runelite.api.Client;
import net.runelite.api.Constants;
import static net.runelite.api.Constants.CLIENT_DEFAULT_ZOOM;
import net.runelite.api.GameState;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.api.ItemComposition;
import static net.runelite.api.ItemID.*;
import net.runelite.api.Sprite;
import net.runelite.api.SpritePixels;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.PostItemDefinition;
import net.runelite.api.events.PostItemComposition;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.util.AsyncBufferedImage;
import net.runelite.http.api.item.ItemClient;
import net.runelite.http.api.item.ItemPrice;
import net.runelite.http.api.item.ItemStats;
import org.jetbrains.annotations.NotNull;
import okhttp3.OkHttpClient;
@Singleton
@@ -91,7 +89,7 @@ public class ItemManager
private Map<Integer, ItemPrice> itemPrices = Collections.emptyMap();
private Map<Integer, ItemStats> itemStats = Collections.emptyMap();
private final LoadingCache<ImageKey, AsyncBufferedImage> itemImages;
private final LoadingCache<Integer, ItemDefinition> itemDefinitions;
private final LoadingCache<Integer, ItemComposition> itemCompositions;
private final LoadingCache<OutlineKey, BufferedImage> itemOutlines;
// Worn items with weight reducing property have a different worn and inventory ItemID
@@ -164,19 +162,15 @@ public class ItemManager
build();
@Inject
public ItemManager(
Client client,
ScheduledExecutorService executor,
ClientThread clientThread,
EventBus eventbus,
public ItemManager(Client client, ScheduledExecutorService scheduledExecutorService, ClientThread clientThread,
OkHttpClient okHttpClient)
{
this.client = client;
this.clientThread = clientThread;
this.itemClient = new ItemClient(okHttpClient);
executor.scheduleWithFixedDelay(this::loadPrices, 0, 30, TimeUnit.MINUTES);
executor.submit(this::loadStats);
scheduledExecutorService.scheduleWithFixedDelay(this::loadPrices, 0, 30, TimeUnit.MINUTES);
scheduledExecutorService.submit(this::loadStats);
itemImages = CacheBuilder.newBuilder()
.maximumSize(128L)
@@ -184,19 +178,19 @@ public class ItemManager
.build(new CacheLoader<ImageKey, AsyncBufferedImage>()
{
@Override
public AsyncBufferedImage load(@NotNull ImageKey key)
public AsyncBufferedImage load(ImageKey key) throws Exception
{
return loadImage(key.itemId, key.itemQuantity, key.stackable);
}
});
itemDefinitions = CacheBuilder.newBuilder()
itemCompositions = CacheBuilder.newBuilder()
.maximumSize(1024L)
.expireAfterAccess(1, TimeUnit.HOURS)
.build(new CacheLoader<Integer, ItemDefinition>()
.build(new CacheLoader<Integer, ItemComposition>()
{
@Override
public ItemDefinition load(@NotNull Integer key)
public ItemComposition load(Integer key) throws Exception
{
return client.getItemDefinition(key);
}
@@ -208,59 +202,77 @@ public class ItemManager
.build(new CacheLoader<OutlineKey, BufferedImage>()
{
@Override
public BufferedImage load(@NotNull OutlineKey key)
public BufferedImage load(OutlineKey key) throws Exception
{
return loadItemOutline(key.itemId, key.itemQuantity, key.outlineColor);
}
});
eventbus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventbus.subscribe(PostItemDefinition.class, this, this::onPostItemDefinition);
}
private void loadPrices()
{
itemClient.getPrices()
.subscribeOn(Schedulers.io())
.subscribe(
m -> itemPrices = m,
e -> log.warn("Error loading prices", e),
() -> log.debug("Loaded {} prices", itemPrices.size())
);
try
{
ItemPrice[] prices = itemClient.getPrices();
if (prices != null)
{
ImmutableMap.Builder<Integer, ItemPrice> map = ImmutableMap.builderWithExpectedSize(prices.length);
for (ItemPrice price : prices)
{
map.put(price.getId(), price);
}
itemPrices = map.build();
}
log.debug("Loaded {} prices", itemPrices.size());
}
catch (IOException e)
{
log.warn("error loading prices!", e);
}
}
private void loadStats()
{
itemClient.getStats()
.subscribeOn(Schedulers.io())
.subscribe(
m -> itemStats = m,
e -> log.warn("Error fetching stats", e),
() -> log.debug("Loaded {} stats", itemStats.size())
);
}
private void onGameStateChanged(final GameStateChanged event)
{
if (event.getGameState() == GameState.HOPPING || event.getGameState() == GameState.LOGIN_SCREEN)
try
{
itemDefinitions.invalidateAll();
final Map<Integer, ItemStats> stats = itemClient.getStats();
if (stats != null)
{
itemStats = ImmutableMap.copyOf(stats);
}
log.debug("Loaded {} stats", itemStats.size());
}
catch (IOException e)
{
log.warn("error loading stats!", e);
}
}
private void onPostItemDefinition(PostItemDefinition event)
@Subscribe
public void onGameStateChanged(final GameStateChanged event)
{
itemDefinitions.put(event.getItemDefinition().getId(), event.getItemDefinition());
if (event.getGameState() == GameState.HOPPING || event.getGameState() == GameState.LOGIN_SCREEN)
{
itemCompositions.invalidateAll();
}
}
@Subscribe
public void onPostItemComposition(PostItemComposition event)
{
itemCompositions.put(event.getItemComposition().getId(), event.getItemComposition());
}
/**
* Invalidates internal item manager item composition cache (but not client item composition cache)
*
* @see Client#getItemDefinitionCache()
* @see Client#getItemCompositionCache()
*/
public void invalidateItemDefinitionCache()
public void invalidateItemCompositionCache()
{
itemDefinitions.invalidateAll();
itemCompositions.invalidateAll();
}
/**
@@ -280,7 +292,7 @@ public class ItemManager
* @param itemID item id
* @param ignoreUntradeableMap should the price returned ignore items that are not tradeable for coins in regular way
* @return item price
* */
*/
public int getItemPrice(int itemID, boolean ignoreUntradeableMap)
{
if (itemID == COINS_995)
@@ -292,10 +304,10 @@ public class ItemManager
return 1000;
}
ItemDefinition itemDefinition = getItemDefinition(itemID);
if (itemDefinition.getNote() != -1)
ItemComposition itemComposition = getItemComposition(itemID);
if (itemComposition.getNote() != -1)
{
itemID = itemDefinition.getLinkedNoteId();
itemID = itemComposition.getLinkedNoteId();
}
itemID = WORN_ITEMS.getOrDefault(itemID, itemID);
@@ -328,67 +340,17 @@ public class ItemManager
return price;
}
public int getAlchValue(ItemDefinition composition)
{
if (composition.getId() == ItemID.COINS_995)
{
return 1;
}
if (composition.getId() == ItemID.PLATINUM_TOKEN)
{
return 1000;
}
return Math.max(1, composition.getHaPrice());
}
public int getAlchValue(int itemID)
{
if (itemID == ItemID.COINS_995)
{
return 1;
}
if (itemID == ItemID.PLATINUM_TOKEN)
{
return 1000;
}
return Math.max(1, getItemDefinition(itemID).getHaPrice());
}
public int getRepairValue(int itemId)
{
return getRepairValue(itemId, false);
}
private int getRepairValue(int itemId, boolean fullValue)
{
final ItemReclaimCost b = ItemReclaimCost.of(itemId);
if (b != null)
{
if (fullValue || b.getItemID() == GRANITE_MAUL_24225 || b.getItemID() == GRANITE_MAUL_24227)
{
return b.getValue();
}
return (int) (b.getValue() * (75.0f / 100.0f));
}
return 0;
}
/**
* Look up an item's stats
*
* @param itemId item id
* @return item stats
*/
@Nullable
public ItemStats getItemStats(int itemId, boolean allowNote)
{
ItemDefinition itemDefinition = getItemDefinition(itemId);
ItemComposition itemComposition = getItemComposition(itemId);
if (!allowNote && itemDefinition.getNote() != -1)
if (itemComposition == null || itemComposition.getName() == null || (!allowNote && itemComposition.getNote() != -1))
{
return null;
}
@@ -425,10 +387,10 @@ public class ItemManager
* @return item composition
*/
@Nonnull
public ItemDefinition getItemDefinition(int itemId)
public ItemComposition getItemComposition(int itemId)
{
assert client.isClientThread() : "getItemDefinition must be called on client thread";
return itemDefinitions.getUnchecked(itemId);
assert client.isClientThread() : "getItemComposition must be called on client thread";
return itemCompositions.getUnchecked(itemId);
}
/**
@@ -436,16 +398,16 @@ public class ItemManager
*/
public int canonicalize(int itemID)
{
ItemDefinition itemDefinition = getItemDefinition(itemID);
ItemComposition itemComposition = getItemComposition(itemID);
if (itemDefinition.getNote() != -1)
if (itemComposition.getNote() != -1)
{
return itemDefinition.getLinkedNoteId();
return itemComposition.getLinkedNoteId();
}
if (itemDefinition.getPlaceholderTemplateId() != -1)
if (itemComposition.getPlaceholderTemplateId() != -1)
{
return itemDefinition.getPlaceholderId();
return itemComposition.getPlaceholderId();
}
return WORN_ITEMS.getOrDefault(itemID, itemID);
@@ -466,7 +428,7 @@ public class ItemManager
{
return false;
}
Sprite sprite = client.createItemSprite(itemId, quantity, 1, Sprite.DEFAULT_SHADOW_COLOR,
SpritePixels sprite = client.createItemSprite(itemId, quantity, 1, SpritePixels.DEFAULT_SHADOW_COLOR,
stackable ? 1 : 0, false, CLIENT_DEFAULT_ZOOM);
if (sprite == null)
{
@@ -520,21 +482,21 @@ public class ItemManager
/**
* Create item sprite and applies an outline.
*
* @param itemId item id
* @param itemId item id
* @param itemQuantity item quantity
* @param outlineColor outline color
* @return image
*/
private BufferedImage loadItemOutline(final int itemId, final int itemQuantity, final Color outlineColor)
{
final Sprite itemSprite = client.createItemSprite(itemId, itemQuantity, 1, 0, 0, false, CLIENT_DEFAULT_ZOOM);
final SpritePixels itemSprite = client.createItemSprite(itemId, itemQuantity, 1, 0, 0, false, CLIENT_DEFAULT_ZOOM);
return itemSprite.toBufferedOutline(outlineColor);
}
/**
* Get item outline with a specific color.
*
* @param itemId item id
* @param itemId item id
* @param itemQuantity item quantity
* @param outlineColor outline color
* @return image

View File

@@ -352,9 +352,4 @@ public enum ItemMapping
return mapping;
}
public static boolean isMapped(int itemId)
{
return MAPPINGS.containsValue(itemId);
}
}
}

View File

@@ -1,132 +0,0 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.game;
import com.google.common.collect.ImmutableMap;
import javax.annotation.Nullable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.ItemID;
/**
* Some non tradeable items are kept on death inside low level wilderness (1-20) but are turned into a broken variant.
* <p>
* The non-broken variant will be shown inside the interface.
*/
@AllArgsConstructor
@Getter
public enum ItemReclaimCost
{
// Capes
FIRE_CAPE(ItemID.FIRE_CAPE, 50000),
FIRE_MAX_CAPE(ItemID.FIRE_MAX_CAPE, 99000),
INFERNAL_CAPE(ItemID.INFERNAL_CAPE, 50000),
INFERNAL_MAX_CAPE(ItemID.INFERNAL_MAX_CAPE, 99000),
AVAS_ASSEMBLER(ItemID.AVAS_ASSEMBLER, 75000),
ASSEMBLER_MAX_CAPE(ItemID.ASSEMBLER_MAX_CAPE, 99000),
IMBUED_GUTHIX_CAPE(ItemID.IMBUED_GUTHIX_CAPE, 75000),
IMBUED_GUTHIX_MAX_CAPE(ItemID.GUTHIX_MAX_CAPE, 99000),
IMBUED_SARADOMIN_CAPE(ItemID.IMBUED_SARADOMIN_CAPE, 75000),
IMBUED_SARADOMIN_MAX_CAPE(ItemID.SARADOMIN_MAX_CAPE, 99000),
IMBUED_ZAMORAK_CAPE(ItemID.IMBUED_ZAMORAK_CAPE, 75000),
IMBUED_ZAMORAK_MAX_CAPE(ItemID.ZAMORAK_MAX_CAPE, 99000),
// Defenders
BRONZE_DEFENDER(ItemID.BRONZE_DEFENDER, 1000),
IRON_DEFENDER(ItemID.IRON_DEFENDER, 2000),
STEEL_DEFENDER(ItemID.STEEL_DEFENDER, 2500),
BLACK_DEFENDER(ItemID.BLACK_DEFENDER, 5000),
MITHRIL_DEFENDER(ItemID.MITHRIL_DEFENDER, 15000),
ADAMANT_DEFENDER(ItemID.ADAMANT_DEFENDER, 25000),
RUNE_DEFENDER(ItemID.RUNE_DEFENDER, 35000),
DRAGON_DEFENDER(ItemID.DRAGON_DEFENDER, 40000),
AVERNIC_DEFENDER(ItemID.AVERNIC_DEFENDER, 1000000),
// Void
VOID_MAGE_HELM(ItemID.VOID_MAGE_HELM, 40000),
VOID_RANGER_HELM(ItemID.VOID_RANGER_HELM, 40000),
VOID_MELEE_HELM(ItemID.VOID_MELEE_HELM, 40000),
VOID_KNIGHT_TOP(ItemID.VOID_KNIGHT_TOP, 45000),
VOID_KNIGHT_ROBE(ItemID.VOID_KNIGHT_ROBE, 45000),
VOID_KNIGHT_GLOVES(ItemID.VOID_KNIGHT_GLOVES, 30000),
ELITE_VOID_TOP(ItemID.ELITE_VOID_TOP, 50000),
ELITE_VOID_ROBE(ItemID.ELITE_VOID_ROBE, 50000),
// Barb Assault
FIGHTER_HAT(ItemID.FIGHTER_HAT, 45000),
RANGER_HAT(ItemID.RANGER_HAT, 45000),
HEALER_HAT(ItemID.HEALER_HAT, 45000),
FIGHTER_TORSO(ItemID.FIGHTER_TORSO, 50000),
PENANCE_SKIRT(ItemID.PENANCE_SKIRT, 20000),
// Castle Wars
SARADOMIN_HALO(ItemID.SARADOMIN_HALO, 25000),
ZAMORAK_HALO(ItemID.ZAMORAK_HALO, 25000),
GUTHIX_HALO(ItemID.GUTHIX_HALO, 25000),
DECORATIVE_MAGIC_HAT(ItemID.DECORATIVE_ARMOUR_11898, 5000),
DECORATIVE_MAGIC_ROBE_TOP(ItemID.DECORATIVE_ARMOUR_11896, 5000),
DECORATIVE_MAGIC_ROBE_LEGS(ItemID.DECORATIVE_ARMOUR_11897, 5000),
DECORATIVE_RANGE_TOP(ItemID.DECORATIVE_ARMOUR_11899, 5000),
DECORATIVE_RANGE_BOTTOM(ItemID.DECORATIVE_ARMOUR_11900, 5000),
DECORATIVE_RANGE_QUIVER(ItemID.DECORATIVE_ARMOUR_11901, 5000),
GOLD_DECORATIVE_HELM(ItemID.DECORATIVE_HELM_4511, 5000),
GOLD_DECORATIVE_BODY(ItemID.DECORATIVE_ARMOUR_4509, 5000),
GOLD_DECORATIVE_LEGS(ItemID.DECORATIVE_ARMOUR_4510, 5000),
GOLD_DECORATIVE_SKIRT(ItemID.DECORATIVE_ARMOUR_11895, 5000),
GOLD_DECORATIVE_SHIELD(ItemID.DECORATIVE_SHIELD_4512, 5000),
GOLD_DECORATIVE_SWORD(ItemID.DECORATIVE_SWORD_4508, 5000),
// Granite Maul
GRANITE_MAUL(ItemID.GRANITE_MAUL_24225, 375000),
GRANITE_MAUL_OR(ItemID.GRANITE_MAUL_24227, 375000);
private static final ImmutableMap<Integer, ItemReclaimCost> idMap;
static
{
ImmutableMap.Builder<Integer, ItemReclaimCost> builder = ImmutableMap.builder();
for (ItemReclaimCost items : values())
{
builder.put(items.itemID, items);
}
idMap = builder.build();
}
private final int itemID;
private final int value;
@Nullable
public static ItemReclaimCost of(int itemId)
{
return idMap.get(itemId);
}
public static boolean breaksOnDeath(int itemId)
{
return idMap.containsKey(itemId);
}
}

View File

@@ -98,9 +98,4 @@ public class ItemVariationMapping
{
return INVERTED_MAPPINGS.asMap().getOrDefault(itemId, Collections.singletonList(itemId));
}
static int getSize()
{
return MAPPINGS.size();
}
}

View File

@@ -1,449 +1,428 @@
/*
* Copyright (c) 2018, 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.game;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ListMultimap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.AnimationID;
import net.runelite.api.Client;
import net.runelite.api.ItemID;
import net.runelite.api.NPC;
import net.runelite.api.NPCDefinition;
import net.runelite.api.NpcID;
import net.runelite.api.Player;
import net.runelite.api.Tile;
import net.runelite.api.TileItem;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ItemDespawned;
import net.runelite.api.events.ItemQuantityChanged;
import net.runelite.api.events.ItemSpawned;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.PlayerDespawned;
import net.runelite.api.events.NpcDefinitionChanged;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.NpcLootReceived;
import net.runelite.client.events.PlayerLootReceived;
@Singleton
@Slf4j
public class LootManager
{
private static final Map<Integer, Integer> NPC_DEATH_ANIMATIONS = ImmutableMap.<Integer, Integer>builder()
.put(NpcID.CAVE_KRAKEN, AnimationID.CAVE_KRAKEN_DEATH)
.put(NpcID.CRYSTALLINE_BAT, AnimationID.CRYSTALLINE_BAT_DEATH)
.put(NpcID.CRYSTALLINE_RAT, AnimationID.CRYSTALLINE_RAT_DEATH)
.put(NpcID.CRYSTALLINE_SPIDER, AnimationID.CRYSTALLINE_SPIDER_DEATH)
.put(NpcID.CRYSTALLINE_WOLF, AnimationID.CRYSTALLINE_WOLF_DEATH)
.put(NpcID.CRYSTALLINE_UNICORN, AnimationID.CRYSTALLINE_UNICORN_DEATH)
.put(NpcID.CRYSTALLINE_SCORPION, AnimationID.CORRUPTED_SCORPION_DEATH)
.put(NpcID.CRYSTALLINE_DRAGON, AnimationID.CRYSTALLINE_DRAGON_DEATH)
.put(NpcID.CRYSTALLINE_DARK_BEAST, AnimationID.CRYSTALLINE_DARK_BEAST_DEATH)
.put(NpcID.CRYSTALLINE_BEAR, AnimationID.CRYSTALLINE_BEAR_DEATH)
.put(NpcID.CORRUPTED_BAT, AnimationID.CRYSTALLINE_BAT_DEATH)
.put(NpcID.CORRUPTED_RAT, AnimationID.CRYSTALLINE_RAT_DEATH)
.put(NpcID.CORRUPTED_SPIDER, AnimationID.CRYSTALLINE_SPIDER_DEATH)
.put(NpcID.CORRUPTED_WOLF, AnimationID.CRYSTALLINE_WOLF_DEATH)
.put(NpcID.CORRUPTED_UNICORN, AnimationID.CRYSTALLINE_UNICORN_DEATH)
.put(NpcID.CORRUPTED_SCORPION, AnimationID.CORRUPTED_SCORPION_DEATH)
.put(NpcID.CORRUPTED_DRAGON, AnimationID.CRYSTALLINE_DRAGON_DEATH)
.put(NpcID.CORRUPTED_DARK_BEAST, AnimationID.CRYSTALLINE_DARK_BEAST_DEATH)
.put(NpcID.CORRUPTED_BEAR, AnimationID.CRYSTALLINE_BEAR_DEATH)
.put(NpcID.THE_NIGHTMARE_9433, AnimationID.NIGHTMARE_DEATH)
.build();
private final EventBus eventBus;
private final Client client;
private final ListMultimap<Integer, ItemStack> itemSpawns = ArrayListMultimap.create();
private final Set<LocalPoint> killPoints = new HashSet<>();
private WorldPoint playerLocationLastTick;
private WorldPoint krakenPlayerLocation;
private NPC delayedLootNpc;
private int delayedLootTickLimit;
@Inject
private LootManager(
final EventBus eventBus,
final Client client
)
{
this.eventBus = eventBus;
this.client = client;
eventBus.subscribe(GameTick.class, this, this::onGameTick);
eventBus.subscribe(NpcDespawned.class, this, this::onNpcDespawned);
eventBus.subscribe(PlayerDespawned.class, this, this::onPlayerDespawned);
eventBus.subscribe(ItemSpawned.class, this, this::onItemSpawned);
eventBus.subscribe(ItemDespawned.class, this, this::onItemDespawned);
eventBus.subscribe(ItemQuantityChanged.class, this, this::onItemQuantityChanged);
eventBus.subscribe(AnimationChanged.class, this, this::onAnimationChanged);
eventBus.subscribe(NpcDefinitionChanged.class, this, this::onNpcDefinitionChanged);
}
private void onNpcDespawned(NpcDespawned npcDespawned)
{
final NPC npc = npcDespawned.getNpc();
if (npc == delayedLootNpc)
{
delayedLootNpc = null;
delayedLootTickLimit = 0;
}
if (!npc.isDead())
{
int id = npc.getId();
switch (id)
{
case NpcID.GARGOYLE:
case NpcID.GARGOYLE_413:
case NpcID.GARGOYLE_1543:
case NpcID.MARBLE_GARGOYLE:
case NpcID.MARBLE_GARGOYLE_7408:
case NpcID.DUSK_7888:
case NpcID.DUSK_7889:
case NpcID.ROCKSLUG:
case NpcID.ROCKSLUG_422:
case NpcID.GIANT_ROCKSLUG:
case NpcID.SMALL_LIZARD:
case NpcID.SMALL_LIZARD_463:
case NpcID.DESERT_LIZARD:
case NpcID.DESERT_LIZARD_460:
case NpcID.DESERT_LIZARD_461:
case NpcID.LIZARD:
case NpcID.ZYGOMITE:
case NpcID.ZYGOMITE_1024:
case NpcID.ANCIENT_ZYGOMITE:
// these monsters die with >0 hp, so we just look for coincident
// item spawn with despawn
break;
default:
return;
}
}
processNpcLoot(npc);
}
private void onPlayerDespawned(PlayerDespawned playerDespawned)
{
final Player player = playerDespawned.getPlayer();
// Only care about dead Players
if (player.getHealthRatio() != 0)
{
return;
}
final LocalPoint location = LocalPoint.fromWorld(client, player.getWorldLocation());
if (location == null || killPoints.contains(location))
{
return;
}
final int x = location.getSceneX();
final int y = location.getSceneY();
final int packed = x << 8 | y;
final Collection<ItemStack> items = itemSpawns.get(packed);
if (items.isEmpty())
{
return;
}
killPoints.add(location);
eventBus.post(PlayerLootReceived.class, new PlayerLootReceived(player, items));
}
private void onItemSpawned(ItemSpawned itemSpawned)
{
final TileItem item = itemSpawned.getItem();
final Tile tile = itemSpawned.getTile();
final LocalPoint location = tile.getLocalLocation();
final int packed = location.getSceneX() << 8 | location.getSceneY();
itemSpawns.put(packed, new ItemStack(item.getId(), item.getQuantity(), location));
log.debug("Item spawn {} ({}) location {}", item.getId(), item.getQuantity(), location);
}
private void onItemDespawned(ItemDespawned itemDespawned)
{
final TileItem item = itemDespawned.getItem();
final LocalPoint location = itemDespawned.getTile().getLocalLocation();
log.debug("Item despawn {} ({}) location {}", item.getId(), item.getQuantity(), location);
}
private void onItemQuantityChanged(ItemQuantityChanged itemQuantityChanged)
{
final TileItem item = itemQuantityChanged.getItem();
final Tile tile = itemQuantityChanged.getTile();
final LocalPoint location = tile.getLocalLocation();
final int packed = location.getSceneX() << 8 | location.getSceneY();
final int diff = itemQuantityChanged.getNewQuantity() - itemQuantityChanged.getOldQuantity();
if (diff <= 0)
{
return;
}
itemSpawns.put(packed, new ItemStack(item.getId(), diff, location));
}
private void onAnimationChanged(AnimationChanged e)
{
if (!(e.getActor() instanceof NPC))
{
return;
}
final NPC npc = (NPC) e.getActor();
int id = npc.getId();
// We only care about certain NPCs
final Integer deathAnim = NPC_DEATH_ANIMATIONS.get(id);
// Current animation is death animation?
if (deathAnim != null && deathAnim == npc.getAnimation())
{
if (id == NpcID.CAVE_KRAKEN)
{
// Big Kraken drops loot wherever player is standing when animation starts.
krakenPlayerLocation = client.getLocalPlayer().getWorldLocation();
}
else
{
// These NPCs drop loot on death animation, which is right now.
processNpcLoot(npc);
}
}
}
public void onNpcDefinitionChanged(NpcDefinitionChanged npcChanged)
{
final NPC npc = npcChanged.getNpc();
if (npc.getId() == NpcID.THE_NIGHTMARE_9433)
{
delayedLootNpc = npc;
delayedLootTickLimit = 15;
}
}
private void onGameTick(GameTick gameTick)
{
if (delayedLootNpc != null && delayedLootTickLimit-- > 0)
{
processDelayedLoot();
}
playerLocationLastTick = client.getLocalPlayer().getWorldLocation();
itemSpawns.clear();
killPoints.clear();
}
private void processDelayedLoot()
{
final WorldPoint adjacentLootTile = getAdjacentSquareLootTile(delayedLootNpc);
final LocalPoint localPoint = LocalPoint.fromWorld(client, adjacentLootTile);
if (localPoint == null)
{
log.debug("Scene changed away from delayed loot location");
delayedLootNpc = null;
delayedLootTickLimit = 0;
return;
}
final int sceneX = localPoint.getSceneX();
final int sceneY = localPoint.getSceneY();
final int packed = sceneX << 8 | sceneY;
final List<ItemStack> itemStacks = itemSpawns.get(packed);
if (itemStacks.isEmpty())
{
// no loot yet
return;
}
log.debug("Got delayed loot stack from {}: {}", delayedLootNpc.getName(), itemStacks);
eventBus.post(NpcLootReceived.class, new NpcLootReceived(delayedLootNpc, itemStacks));
delayedLootNpc = null;
delayedLootTickLimit = 0;
}
private void processNpcLoot(NPC npc)
{
final LocalPoint location = LocalPoint.fromWorld(client, getDropLocation(npc, npc.getWorldLocation()));
if (location == null || killPoints.contains(location))
{
return;
}
final int x = location.getSceneX();
final int y = location.getSceneY();
final int size = npc.getDefinition().getSize();
// Some NPCs drop items onto multiple tiles
final List<ItemStack> allItems = new ArrayList<>();
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j)
{
final int packed = (x + i) << 8 | (y + j);
final Collection<ItemStack> items = itemSpawns.get(packed);
allItems.addAll(items);
}
}
if (allItems.isEmpty())
{
return;
}
killPoints.add(location);
eventBus.post(NpcLootReceived.class, new NpcLootReceived(npc, allItems));
}
private WorldPoint getDropLocation(NPC npc, WorldPoint worldLocation)
{
switch (npc.getId())
{
case NpcID.KRAKEN:
case NpcID.KRAKEN_6640:
case NpcID.KRAKEN_6656:
worldLocation = playerLocationLastTick;
break;
case NpcID.CAVE_KRAKEN:
worldLocation = krakenPlayerLocation;
break;
case NpcID.ZULRAH: // Green
case NpcID.ZULRAH_2043: // Red
case NpcID.ZULRAH_2044: // Blue
for (Map.Entry<Integer, ItemStack> entry : itemSpawns.entries())
{
if (entry.getValue().getId() == ItemID.ZULRAHS_SCALES)
{
int packed = entry.getKey();
int unpackedX = packed >> 8;
int unpackedY = packed & 0xFF;
worldLocation = WorldPoint.fromScene(client, unpackedX, unpackedY, worldLocation.getPlane());
break;
}
}
break;
case NpcID.VORKATH:
case NpcID.VORKATH_8058:
case NpcID.VORKATH_8059:
case NpcID.VORKATH_8060:
case NpcID.VORKATH_8061:
int x = worldLocation.getX() + 3;
int y = worldLocation.getY() + 3;
if (playerLocationLastTick.getX() < x)
{
x -= 4;
}
else if (playerLocationLastTick.getX() > x)
{
x += 4;
}
if (playerLocationLastTick.getY() < y)
{
y -= 4;
}
else if (playerLocationLastTick.getY() > y)
{
y += 4;
}
worldLocation = new WorldPoint(x, y, worldLocation.getPlane());
break;
}
return worldLocation;
}
private WorldPoint getAdjacentSquareLootTile(NPC npc)
{
final NPCDefinition composition = npc.getDefinition();
final WorldPoint worldLocation = npc.getWorldLocation();
int x = worldLocation.getX();
int y = worldLocation.getY();
if (playerLocationLastTick.getX() < x)
{
x -= 1;
}
else
{
x += Math.min(playerLocationLastTick.getX() - x, composition.getSize());
}
if (playerLocationLastTick.getY() < y)
{
y -= 1;
}
else
{
y += Math.min(playerLocationLastTick.getY() - y, composition.getSize());
}
return new WorldPoint(x, y, worldLocation.getPlane());
}
/**
* Get the list of items present at the provided WorldPoint that spawned this tick.
*
* @param worldPoint the location in question
* @return the list of item stacks
*/
public Collection<ItemStack> getItemSpawns(WorldPoint worldPoint)
{
LocalPoint localPoint = LocalPoint.fromWorld(client, worldPoint);
if (localPoint == null)
{
return Collections.emptyList();
}
final int sceneX = localPoint.getSceneX();
final int sceneY = localPoint.getSceneY();
final int packed = sceneX << 8 | sceneY;
final List<ItemStack> itemStacks = itemSpawns.get(packed);
return Collections.unmodifiableList(itemStacks);
}
}
/*
* Copyright (c) 2018, 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.game;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ListMultimap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.AnimationID;
import net.runelite.api.Client;
import net.runelite.api.ItemID;
import net.runelite.api.NPC;
import net.runelite.api.NPCComposition;
import net.runelite.api.NpcID;
import net.runelite.api.Player;
import net.runelite.api.Tile;
import net.runelite.api.TileItem;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ItemDespawned;
import net.runelite.api.events.ItemQuantityChanged;
import net.runelite.api.events.ItemSpawned;
import net.runelite.api.events.NpcChanged;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.PlayerDespawned;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.NpcLootReceived;
import net.runelite.client.events.PlayerLootReceived;
@Singleton
@Slf4j
public class LootManager
{
private static final Map<Integer, Integer> NPC_DEATH_ANIMATIONS = ImmutableMap.of(
NpcID.CAVE_KRAKEN, AnimationID.CAVE_KRAKEN_DEATH
);
private final EventBus eventBus;
private final Client client;
private final ListMultimap<Integer, ItemStack> itemSpawns = ArrayListMultimap.create();
private final Set<LocalPoint> killPoints = new HashSet<>();
private WorldPoint playerLocationLastTick;
private WorldPoint krakenPlayerLocation;
private NPC delayedLootNpc;
private int delayedLootTickLimit;
@Inject
private LootManager(EventBus eventBus, Client client)
{
this.eventBus = eventBus;
this.client = client;
}
@Subscribe
public void onNpcDespawned(NpcDespawned npcDespawned)
{
final NPC npc = npcDespawned.getNpc();
if (npc == delayedLootNpc)
{
delayedLootNpc = null;
delayedLootTickLimit = 0;
}
if (!npc.isDead())
{
int id = npc.getId();
switch (id)
{
case NpcID.GARGOYLE:
case NpcID.GARGOYLE_413:
case NpcID.GARGOYLE_1543:
case NpcID.MARBLE_GARGOYLE:
case NpcID.MARBLE_GARGOYLE_7408:
case NpcID.DUSK_7888:
case NpcID.DUSK_7889:
case NpcID.ROCKSLUG:
case NpcID.ROCKSLUG_422:
case NpcID.GIANT_ROCKSLUG:
case NpcID.SMALL_LIZARD:
case NpcID.SMALL_LIZARD_463:
case NpcID.DESERT_LIZARD:
case NpcID.DESERT_LIZARD_460:
case NpcID.DESERT_LIZARD_461:
case NpcID.LIZARD:
case NpcID.ZYGOMITE:
case NpcID.ZYGOMITE_1024:
case NpcID.ANCIENT_ZYGOMITE:
// these monsters die with >0 hp, so we just look for coincident
// item spawn with despawn
break;
default:
return;
}
}
processNpcLoot(npc);
}
@Subscribe
public void onPlayerDespawned(PlayerDespawned playerDespawned)
{
final Player player = playerDespawned.getPlayer();
// Only care about dead Players
if (player.getHealthRatio() != 0)
{
return;
}
final LocalPoint location = LocalPoint.fromWorld(client, player.getWorldLocation());
if (location == null || killPoints.contains(location))
{
return;
}
final int x = location.getSceneX();
final int y = location.getSceneY();
final int packed = x << 8 | y;
final Collection<ItemStack> items = itemSpawns.get(packed);
if (items.isEmpty())
{
return;
}
killPoints.add(location);
eventBus.post(new PlayerLootReceived(player, items));
}
@Subscribe
public void onItemSpawned(ItemSpawned itemSpawned)
{
final TileItem item = itemSpawned.getItem();
final Tile tile = itemSpawned.getTile();
final LocalPoint location = tile.getLocalLocation();
final int packed = location.getSceneX() << 8 | location.getSceneY();
itemSpawns.put(packed, new ItemStack(item.getId(), item.getQuantity(), location));
log.debug("Item spawn {} ({}) location {}", item.getId(), item.getQuantity(), location);
}
@Subscribe
public void onItemDespawned(ItemDespawned itemDespawned)
{
final TileItem item = itemDespawned.getItem();
final LocalPoint location = itemDespawned.getTile().getLocalLocation();
log.debug("Item despawn {} ({}) location {}", item.getId(), item.getQuantity(), location);
}
@Subscribe
public void onItemQuantityChanged(ItemQuantityChanged itemQuantityChanged)
{
final TileItem item = itemQuantityChanged.getItem();
final Tile tile = itemQuantityChanged.getTile();
final LocalPoint location = tile.getLocalLocation();
final int packed = location.getSceneX() << 8 | location.getSceneY();
final int diff = itemQuantityChanged.getNewQuantity() - itemQuantityChanged.getOldQuantity();
if (diff <= 0)
{
return;
}
itemSpawns.put(packed, new ItemStack(item.getId(), diff, location));
}
@Subscribe
public void onAnimationChanged(AnimationChanged e)
{
if (!(e.getActor() instanceof NPC))
{
return;
}
final NPC npc = (NPC) e.getActor();
int id = npc.getId();
// We only care about certain NPCs
final Integer deathAnim = NPC_DEATH_ANIMATIONS.get(id);
// Current animation is death animation?
if (deathAnim != null && deathAnim == npc.getAnimation())
{
if (id == NpcID.CAVE_KRAKEN)
{
// Big Kraken drops loot wherever player is standing when animation starts.
krakenPlayerLocation = client.getLocalPlayer().getWorldLocation();
}
else
{
// These NPCs drop loot on death animation, which is right now.
processNpcLoot(npc);
}
}
}
@Subscribe
public void onNpcChanged(NpcChanged npcChanged)
{
final NPC npc = npcChanged.getNpc();
if (npc.getId() == NpcID.THE_NIGHTMARE_9433)
{
delayedLootNpc = npc;
delayedLootTickLimit = 15;
}
}
@Subscribe
public void onGameTick(GameTick gameTick)
{
if (delayedLootNpc != null && delayedLootTickLimit-- > 0)
{
processDelayedLoot();
}
playerLocationLastTick = client.getLocalPlayer().getWorldLocation();
itemSpawns.clear();
killPoints.clear();
}
private void processDelayedLoot()
{
final WorldPoint adjacentLootTile = getAdjacentSquareLootTile(delayedLootNpc);
final LocalPoint localPoint = LocalPoint.fromWorld(client, adjacentLootTile);
if (localPoint == null)
{
log.debug("Scene changed away from delayed loot location");
delayedLootNpc = null;
delayedLootTickLimit = 0;
return;
}
final int sceneX = localPoint.getSceneX();
final int sceneY = localPoint.getSceneY();
final int packed = sceneX << 8 | sceneY;
final List<ItemStack> itemStacks = itemSpawns.get(packed);
if (itemStacks.isEmpty())
{
// no loot yet
return;
}
log.debug("Got delayed loot stack from {}: {}", delayedLootNpc.getName(), itemStacks);
eventBus.post(new NpcLootReceived(delayedLootNpc, itemStacks));
delayedLootNpc = null;
delayedLootTickLimit = 0;
}
private void processNpcLoot(NPC npc)
{
final LocalPoint location = LocalPoint.fromWorld(client, getDropLocation(npc, npc.getWorldLocation()));
if (location == null || killPoints.contains(location))
{
return;
}
final int x = location.getSceneX();
final int y = location.getSceneY();
final int size = npc.getComposition().getSize();
// Some NPCs drop items onto multiple tiles
final List<ItemStack> allItems = new ArrayList<>();
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j)
{
final int packed = (x + i) << 8 | (y + j);
final Collection<ItemStack> items = itemSpawns.get(packed);
allItems.addAll(items);
}
}
if (allItems.isEmpty())
{
return;
}
killPoints.add(location);
eventBus.post(new NpcLootReceived(npc, allItems));
}
private WorldPoint getDropLocation(NPC npc, WorldPoint worldLocation)
{
switch (npc.getId())
{
case NpcID.KRAKEN:
case NpcID.KRAKEN_6640:
case NpcID.KRAKEN_6656:
worldLocation = playerLocationLastTick;
break;
case NpcID.CAVE_KRAKEN:
worldLocation = krakenPlayerLocation;
break;
case NpcID.ZULRAH: // Green
case NpcID.ZULRAH_2043: // Red
case NpcID.ZULRAH_2044: // Blue
for (Map.Entry<Integer, ItemStack> entry : itemSpawns.entries())
{
if (entry.getValue().getId() == ItemID.ZULRAHS_SCALES)
{
int packed = entry.getKey();
int unpackedX = packed >> 8;
int unpackedY = packed & 0xFF;
worldLocation = WorldPoint.fromScene(client, unpackedX, unpackedY, worldLocation.getPlane());
break;
}
}
break;
case NpcID.VORKATH:
case NpcID.VORKATH_8058:
case NpcID.VORKATH_8059:
case NpcID.VORKATH_8060:
case NpcID.VORKATH_8061:
int x = worldLocation.getX() + 3;
int y = worldLocation.getY() + 3;
if (playerLocationLastTick.getX() < x)
{
x -= 4;
}
else if (playerLocationLastTick.getX() > x)
{
x += 4;
}
if (playerLocationLastTick.getY() < y)
{
y -= 4;
}
else if (playerLocationLastTick.getY() > y)
{
y += 4;
}
worldLocation = new WorldPoint(x, y, worldLocation.getPlane());
break;
}
return worldLocation;
}
private WorldPoint getAdjacentSquareLootTile(NPC npc)
{
final NPCComposition composition = npc.getComposition();
final WorldPoint worldLocation = npc.getWorldLocation();
int x = worldLocation.getX();
int y = worldLocation.getY();
if (playerLocationLastTick.getX() < x)
{
x -= 1;
}
else
{
x += Math.min(playerLocationLastTick.getX() - x, composition.getSize());
}
if (playerLocationLastTick.getY() < y)
{
y -= 1;
}
else
{
y += Math.min(playerLocationLastTick.getY() - y, composition.getSize());
}
return new WorldPoint(x, y, worldLocation.getPlane());
}
/**
* Get the list of items present at the provided WorldPoint that spawned this tick.
*
* @param worldPoint the location in question
* @return the list of item stacks
*/
public Collection<ItemStack> getItemSpawns(WorldPoint worldPoint)
{
LocalPoint localPoint = LocalPoint.fromWorld(client, worldPoint);
if (localPoint == null)
{
return Collections.emptyList();
}
final int sceneX = localPoint.getSceneX();
final int sceneY = localPoint.getSceneY();
final int packed = sceneX << 8 | sceneY;
final List<ItemStack> itemStacks = itemSpawns.get(packed);
return Collections.unmodifiableList(itemStacks);
}
}

View File

@@ -1,6 +1,5 @@
/*
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,136 +24,54 @@
*/
package net.runelite.client.game;
import com.google.common.collect.ImmutableMap;
import com.google.gson.stream.JsonReader;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.NpcID;
import net.runelite.http.api.npc.NpcInfo;
import net.runelite.http.api.npc.NpcInfoClient;
import okhttp3.OkHttpClient;
@Slf4j
@Singleton
@Slf4j
public class NPCManager
{
private static final Set<Integer> blacklistXpMultiplier = Set.of(
// Vorkath
NpcID.VORKATH, NpcID.VORKATH_8058, NpcID.VORKATH_8059, NpcID.VORKATH_8060, NpcID.VORKATH_8061,
// Grotesque Guardians
NpcID.DAWN, NpcID.DAWN_7852, NpcID.DAWN_7853, NpcID.DAWN_7884, NpcID.DAWN_7885,
NpcID.DUSK, NpcID.DUSK_7851, NpcID.DUSK_7854, NpcID.DUSK_7855, NpcID.DUSK_7882, NpcID.DUSK_7883, NpcID.DUSK_7886, NpcID.DUSK_7887, NpcID.DUSK_7888, NpcID.DUSK_7889,
// Kraken
NpcID.KRAKEN, NpcID.KRAKEN_6640, NpcID.KRAKEN_6656,
// Zulrah
NpcID.ZULRAH, NpcID.ZULRAH_2043, NpcID.ZULRAH_2044
);
private ImmutableMap<Integer, NPCStats> statsMap;
private final OkHttpClient okHttpClient;
private Map<Integer, NpcInfo> npcMap = Collections.emptyMap();
@Inject
private NPCManager()
private NPCManager(OkHttpClient okHttpClient, ScheduledExecutorService scheduledExecutorService)
{
Completable.fromAction(this::loadStats)
.subscribeOn(Schedulers.computation())
.subscribe(
() -> log.debug("Loaded {} NPC stats", statsMap.size()),
ex -> log.warn("Error loading NPC stats", ex)
);
this.okHttpClient = okHttpClient;
scheduledExecutorService.execute(this::loadNpcs);
}
private void loadStats() throws IOException
{
try (JsonReader reader = new JsonReader(new InputStreamReader(NPCManager.class.getResourceAsStream("/npc_stats.json"), StandardCharsets.UTF_8)))
{
ImmutableMap.Builder<Integer, NPCStats> builder = ImmutableMap.builderWithExpectedSize(2821);
reader.beginObject();
while (reader.hasNext())
{
builder.put(
Integer.parseInt(reader.nextName()),
NPCStats.NPC_STATS_TYPE_ADAPTER.read(reader)
);
}
reader.endObject();
statsMap = builder.build();
}
}
/**
* Returns the {@link NPCStats} for target NPC id
*
* @param npcId NPC id
* @return the {@link NPCStats} or null if unknown
*/
@Nullable
public NPCStats getStats(final int npcId)
public NpcInfo getNpcInfo(int npcId)
{
return statsMap.get(npcId);
return npcMap.get(npcId);
}
/**
* Returns health for target NPC ID
*
* @param npcId NPC id
* @return health or null if unknown
*/
public int getHealth(final int npcId)
@Nullable
public Integer getHealth(int npcId)
{
final NPCStats s = statsMap.get(npcId);
if (s == null || s.getHitpoints() == -1)
{
return -1;
}
return s.getHitpoints();
NpcInfo npcInfo = npcMap.get(npcId);
return npcInfo == null ? null : npcInfo.getHitpoints();
}
/**
* Returns the attack speed for target NPC ID.
*
* @param npcId NPC id
* @return attack speed in game ticks for NPC ID.
*/
public int getAttackSpeed(final int npcId)
private void loadNpcs()
{
final NPCStats s = statsMap.get(npcId);
if (s == null || s.getAttackSpeed() == -1)
try
{
return -1;
npcMap = new NpcInfoClient(okHttpClient).getNpcs();
}
return s.getAttackSpeed();
}
/**
* Returns the exp modifier for target NPC ID based on its stats.
*
* @param npcId NPC id
* @return npcs exp modifier. Assumes default xp rate if npc stats are unknown (returns 1)
*/
public double getXpModifier(final int npcId)
{
if (blacklistXpMultiplier.contains(npcId))
catch (IOException e)
{
return 1;
log.warn("error loading npc stats", e);
}
final NPCStats s = statsMap.get(npcId);
if (s == null)
{
return 1;
}
return s.calculateXpModifier();
}
}

Some files were not shown because too many files have changed in this diff Show More