Merges Injector
Welcome to the new world boys.
This commit is contained in:
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class ClientSessionManager
|
||||
{
|
||||
private final SessionClient sessionClient = new SessionClient();
|
||||
private final ScheduledExecutorService executorService;
|
||||
|
||||
private ScheduledFuture<?> scheduledFuture;
|
||||
private UUID sessionId;
|
||||
|
||||
|
||||
@Inject
|
||||
ClientSessionManager(ScheduledExecutorService executorService)
|
||||
{
|
||||
this.executorService = executorService;
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
try
|
||||
{
|
||||
sessionId = sessionClient.open();
|
||||
log.debug("Opened session {}", sessionId);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("error opening session", ex);
|
||||
}
|
||||
|
||||
scheduledFuture = executorService.scheduleWithFixedDelay(this::ping, 1, 10, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
if (sessionId != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
sessionClient.delete(sessionId);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn(null, ex);
|
||||
}
|
||||
sessionId = null;
|
||||
}
|
||||
|
||||
scheduledFuture.cancel(true);
|
||||
}
|
||||
|
||||
private void ping()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (sessionId == null)
|
||||
{
|
||||
sessionId = sessionClient.open();
|
||||
log.debug("Opened session {}", sessionId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn(null, ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
sessionClient.ping(sessionId);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("Resetting session", ex);
|
||||
sessionId = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,344 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.escape.Escaper;
|
||||
import com.google.common.escape.Escapers;
|
||||
import com.google.inject.Inject;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.TrayIcon;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.client.chat.ChatColorType;
|
||||
import net.runelite.client.chat.ChatMessageBuilder;
|
||||
import net.runelite.client.chat.ChatMessageManager;
|
||||
import net.runelite.client.chat.QueuedMessage;
|
||||
import net.runelite.client.config.RuneLiteConfig;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.util.OSType;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class Notifier
|
||||
{
|
||||
// Default timeout of notification in milliseconds
|
||||
private static final int DEFAULT_TIMEOUT = 10000;
|
||||
private static final String DOUBLE_QUOTE = "\"";
|
||||
private static final Escaper SHELL_ESCAPE = Escapers.builder()
|
||||
.addEscape('"', "'")
|
||||
.build();
|
||||
|
||||
// Notifier properties
|
||||
private static final Color FLASH_COLOR = new Color(255, 0, 0, 70);
|
||||
private static final int FLASH_DURATION = 2000;
|
||||
|
||||
private final Client client;
|
||||
private final String appName;
|
||||
private final RuneLiteConfig runeLiteConfig;
|
||||
private final ClientUI clientUI;
|
||||
private final ScheduledExecutorService executorService;
|
||||
private final ChatMessageManager chatMessageManager;
|
||||
private final Path notifyIconPath;
|
||||
private final boolean terminalNotifierAvailable;
|
||||
private Instant flashStart;
|
||||
|
||||
@Inject
|
||||
private Notifier(
|
||||
final ClientUI clientUI,
|
||||
final Client client,
|
||||
final RuneLiteConfig runeliteConfig,
|
||||
final RuneLiteProperties runeLiteProperties,
|
||||
final ScheduledExecutorService executorService,
|
||||
final ChatMessageManager chatMessageManager)
|
||||
{
|
||||
this.client = client;
|
||||
this.appName = runeLiteProperties.getTitle();
|
||||
this.clientUI = clientUI;
|
||||
this.runeLiteConfig = runeliteConfig;
|
||||
this.executorService = executorService;
|
||||
this.chatMessageManager = chatMessageManager;
|
||||
this.notifyIconPath = RuneLite.RUNELITE_DIR.toPath().resolve("icon.png");
|
||||
|
||||
// First check if we are running in launcher
|
||||
this.terminalNotifierAvailable =
|
||||
!Strings.isNullOrEmpty(RuneLiteProperties.getLauncherVersion())
|
||||
&& isTerminalNotifierAvailable();
|
||||
|
||||
storeIcon();
|
||||
}
|
||||
|
||||
public void notify(String message)
|
||||
{
|
||||
notify(message, TrayIcon.MessageType.NONE);
|
||||
}
|
||||
|
||||
public void notify(String message, TrayIcon.MessageType type)
|
||||
{
|
||||
if (!runeLiteConfig.sendNotificationsWhenFocused() && clientUI.isFocused())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (runeLiteConfig.requestFocusOnNotification())
|
||||
{
|
||||
clientUI.requestFocus();
|
||||
}
|
||||
|
||||
if (runeLiteConfig.enableTrayNotifications())
|
||||
{
|
||||
sendNotification(appName, message, type);
|
||||
}
|
||||
|
||||
if (runeLiteConfig.enableNotificationSound())
|
||||
{
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
}
|
||||
|
||||
if (runeLiteConfig.enableGameMessageNotification() && client.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
final String formattedMessage = new ChatMessageBuilder()
|
||||
.append(ChatColorType.HIGHLIGHT)
|
||||
.append(message)
|
||||
.build();
|
||||
|
||||
chatMessageManager.queue(QueuedMessage.builder()
|
||||
.type(ChatMessageType.CONSOLE)
|
||||
.name(appName)
|
||||
.runeLiteFormattedMessage(formattedMessage)
|
||||
.build());
|
||||
}
|
||||
|
||||
if (runeLiteConfig.enableFlashNotification())
|
||||
{
|
||||
flashStart = Instant.now();
|
||||
}
|
||||
|
||||
log.debug(message);
|
||||
}
|
||||
|
||||
public void processFlash(final Graphics2D graphics)
|
||||
{
|
||||
if (flashStart == null || client.getGameCycle() % 40 >= 20)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
flashStart = null;
|
||||
return;
|
||||
}
|
||||
|
||||
final Color color = graphics.getColor();
|
||||
graphics.setColor(FLASH_COLOR);
|
||||
graphics.fill(new Rectangle(client.getCanvas().getSize()));
|
||||
graphics.setColor(color);
|
||||
|
||||
if (Instant.now().minusMillis(FLASH_DURATION).isAfter(flashStart))
|
||||
{
|
||||
flashStart = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendNotification(
|
||||
final String title,
|
||||
final String message,
|
||||
final TrayIcon.MessageType type)
|
||||
{
|
||||
final String escapedTitle = SHELL_ESCAPE.escape(title);
|
||||
final String escapedMessage = SHELL_ESCAPE.escape(message);
|
||||
|
||||
switch (OSType.getOSType())
|
||||
{
|
||||
case Linux:
|
||||
sendLinuxNotification(escapedTitle, escapedMessage, type);
|
||||
break;
|
||||
case MacOS:
|
||||
sendMacNotification(escapedTitle, escapedMessage);
|
||||
break;
|
||||
default:
|
||||
sendTrayNotification(title, message, type);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendTrayNotification(
|
||||
final String title,
|
||||
final String message,
|
||||
final TrayIcon.MessageType type)
|
||||
{
|
||||
if (clientUI.getTrayIcon() != null)
|
||||
{
|
||||
clientUI.getTrayIcon().displayMessage(title, message, type);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendLinuxNotification(
|
||||
final String title,
|
||||
final String message,
|
||||
final TrayIcon.MessageType type)
|
||||
{
|
||||
final List<String> commands = new ArrayList<>();
|
||||
commands.add("notify-send");
|
||||
commands.add(title);
|
||||
commands.add(message);
|
||||
commands.add("-i");
|
||||
commands.add(SHELL_ESCAPE.escape(notifyIconPath.toAbsolutePath().toString()));
|
||||
commands.add("-u");
|
||||
commands.add(toUrgency(type));
|
||||
commands.add("-t");
|
||||
commands.add(String.valueOf(DEFAULT_TIMEOUT));
|
||||
|
||||
executorService.submit(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
Process notificationProcess = sendCommand(commands);
|
||||
|
||||
boolean exited = notificationProcess.waitFor(500, TimeUnit.MILLISECONDS);
|
||||
if (exited && notificationProcess.exitValue() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (IOException | InterruptedException ex)
|
||||
{
|
||||
log.debug("error sending notification", ex);
|
||||
}
|
||||
|
||||
// fall back to tray notification
|
||||
sendTrayNotification(title, message, type);
|
||||
});
|
||||
}
|
||||
|
||||
private void sendMacNotification(final String title, final String message)
|
||||
{
|
||||
final List<String> commands = new ArrayList<>();
|
||||
|
||||
if (terminalNotifierAvailable)
|
||||
{
|
||||
commands.add("terminal-notifier");
|
||||
commands.add("-group");
|
||||
commands.add("net.runelite.launcher");
|
||||
commands.add("-sender");
|
||||
commands.add("net.runelite.launcher");
|
||||
commands.add("-message");
|
||||
commands.add(DOUBLE_QUOTE + message + DOUBLE_QUOTE);
|
||||
commands.add("-title");
|
||||
commands.add(DOUBLE_QUOTE + title + DOUBLE_QUOTE);
|
||||
}
|
||||
else
|
||||
{
|
||||
commands.add("osascript");
|
||||
commands.add("-e");
|
||||
|
||||
final String script = "display notification " + DOUBLE_QUOTE +
|
||||
message +
|
||||
DOUBLE_QUOTE +
|
||||
" with title " +
|
||||
DOUBLE_QUOTE +
|
||||
title +
|
||||
DOUBLE_QUOTE;
|
||||
|
||||
commands.add(script);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
sendCommand(commands);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("error sending notification", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static Process sendCommand(final List<String> commands) throws IOException
|
||||
{
|
||||
return new ProcessBuilder(commands.toArray(new String[commands.size()]))
|
||||
.redirectErrorStream(true)
|
||||
.start();
|
||||
}
|
||||
|
||||
private void storeIcon()
|
||||
{
|
||||
if (OSType.getOSType() == OSType.Linux && !Files.exists(notifyIconPath))
|
||||
{
|
||||
try (InputStream stream = Notifier.class.getResourceAsStream("/runelite.png"))
|
||||
{
|
||||
Files.copy(stream, notifyIconPath);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn(null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTerminalNotifierAvailable()
|
||||
{
|
||||
if (OSType.getOSType() == OSType.MacOS)
|
||||
{
|
||||
try
|
||||
{
|
||||
final Process exec = Runtime.getRuntime().exec(new String[]{"terminal-notifier", "-help"});
|
||||
exec.waitFor();
|
||||
return exec.exitValue() == 0;
|
||||
}
|
||||
catch (IOException | InterruptedException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String toUrgency(TrayIcon.MessageType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case WARNING:
|
||||
case ERROR:
|
||||
return "critical";
|
||||
default:
|
||||
return "normal";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,412 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import java.io.File;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
import java.net.Authenticator;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.util.Locale;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
import joptsimple.ArgumentAcceptingOptionSpec;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.util.EnumConverter;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.client.account.SessionManager;
|
||||
import net.runelite.client.chat.ChatMessageManager;
|
||||
import net.runelite.client.chat.CommandManager;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.discord.DiscordService;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.game.ClanManager;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.LootManager;
|
||||
import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
||||
import net.runelite.client.graphics.ModelOutlineRenderer;
|
||||
import net.runelite.client.menus.MenuManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginInstantiationException;
|
||||
import net.runelite.client.plugins.PluginManager;
|
||||
import net.runelite.client.rs.ClientUpdateCheckMode;
|
||||
import net.runelite.client.task.Scheduler;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.ui.DrawManager;
|
||||
import net.runelite.client.ui.RuneLiteSplashScreen;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import net.runelite.client.ui.overlay.OverlayRenderer;
|
||||
import net.runelite.client.ui.overlay.WidgetOverlay;
|
||||
import net.runelite.client.ui.overlay.arrow.ArrowMinimapOverlay;
|
||||
import net.runelite.client.ui.overlay.arrow.ArrowWorldOverlay;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxOverlay;
|
||||
import net.runelite.client.ui.overlay.tooltip.TooltipOverlay;
|
||||
import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay;
|
||||
import net.runelite.client.ws.PartyService;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class RuneLite
|
||||
{
|
||||
public static final String RUNELIT_VERSION = "0.1.2";
|
||||
public static final File RUNELITE_DIR = new File(System.getProperty("user.home"), ".runelite");
|
||||
public static final File PROFILES_DIR = new File(RUNELITE_DIR, "profiles");
|
||||
public static final File PLUGIN_DIR = new File(RUNELITE_DIR, "plugins");
|
||||
public static final File SCREENSHOT_DIR = new File(RUNELITE_DIR, "screenshots");
|
||||
static final RuneLiteSplashScreen splashScreen = new RuneLiteSplashScreen();
|
||||
|
||||
|
||||
@Getter
|
||||
private static Injector injector;
|
||||
|
||||
@Inject
|
||||
private PluginManager pluginManager;
|
||||
|
||||
@Inject
|
||||
private EventBus eventBus;
|
||||
|
||||
@Inject
|
||||
private ConfigManager configManager;
|
||||
|
||||
@Inject
|
||||
private DrawManager drawManager;
|
||||
|
||||
@Inject
|
||||
private SessionManager sessionManager;
|
||||
|
||||
@Inject
|
||||
public DiscordService discordService;
|
||||
|
||||
@Inject
|
||||
private ClientSessionManager clientSessionManager;
|
||||
|
||||
@Inject
|
||||
private ClientUI clientUI;
|
||||
|
||||
@Inject
|
||||
private InfoBoxManager infoBoxManager;
|
||||
|
||||
@Inject
|
||||
private OverlayManager overlayManager;
|
||||
|
||||
@Inject
|
||||
private PartyService partyService;
|
||||
|
||||
@Inject
|
||||
private Provider<ItemManager> itemManager;
|
||||
|
||||
@Inject
|
||||
private Provider<OverlayRenderer> overlayRenderer;
|
||||
|
||||
@Inject
|
||||
private Provider<ClanManager> clanManager;
|
||||
|
||||
@Inject
|
||||
private Provider<ChatMessageManager> chatMessageManager;
|
||||
|
||||
@Inject
|
||||
private Provider<MenuManager> menuManager;
|
||||
|
||||
@Inject
|
||||
private Provider<CommandManager> commandManager;
|
||||
|
||||
@Inject
|
||||
private Provider<InfoBoxOverlay> infoBoxOverlay;
|
||||
|
||||
@Inject
|
||||
private Provider<TooltipOverlay> tooltipOverlay;
|
||||
|
||||
@Inject
|
||||
private Provider<WorldMapOverlay> worldMapOverlay;
|
||||
|
||||
@Inject
|
||||
private Provider<ArrowWorldOverlay> arrowWorldOverlay;
|
||||
|
||||
@Inject
|
||||
private Provider<ArrowMinimapOverlay> arrowMinimapOverlay;
|
||||
|
||||
@Inject
|
||||
private Provider<LootManager> lootManager;
|
||||
|
||||
@Inject
|
||||
private Provider<ChatboxPanelManager> chatboxPanelManager;
|
||||
|
||||
@Inject
|
||||
@Nullable
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private Provider<ModelOutlineRenderer> modelOutlineRenderer;
|
||||
|
||||
@Inject
|
||||
private Scheduler scheduler;
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Locale.setDefault(Locale.ENGLISH);
|
||||
|
||||
final OptionParser parser = new OptionParser();
|
||||
parser.accepts("developer-mode", "Enable developer tools");
|
||||
parser.accepts("debug", "Show extra debugging output");
|
||||
parser.accepts("no-splash", "Do not show the splash screen");
|
||||
|
||||
final ArgumentAcceptingOptionSpec<String> proxyInfo = parser
|
||||
.accepts("proxy")
|
||||
.withRequiredArg().ofType(String.class);
|
||||
|
||||
final ArgumentAcceptingOptionSpec<ClientUpdateCheckMode> updateMode = parser
|
||||
.accepts("rs", "Select client type")
|
||||
.withRequiredArg()
|
||||
.ofType(ClientUpdateCheckMode.class)
|
||||
.defaultsTo(ClientUpdateCheckMode.AUTO)
|
||||
.withValuesConvertedBy(new EnumConverter<ClientUpdateCheckMode>(ClientUpdateCheckMode.class)
|
||||
{
|
||||
@Override
|
||||
public ClientUpdateCheckMode convert(String v)
|
||||
{
|
||||
return super.convert(v.toUpperCase());
|
||||
}
|
||||
});
|
||||
|
||||
parser.accepts("help", "Show this text").forHelp();
|
||||
OptionSet options = parser.parse(args);
|
||||
|
||||
if (options.has("proxy"))
|
||||
{
|
||||
String[] proxy = options.valueOf(proxyInfo).split(":");
|
||||
|
||||
if (proxy.length >= 2)
|
||||
{
|
||||
System.setProperty("socksProxyHost", proxy[0]);
|
||||
System.setProperty("socksProxyPort", proxy[1]);
|
||||
}
|
||||
|
||||
if (proxy.length >= 4)
|
||||
{
|
||||
System.setProperty("java.net.socks.username", proxy[2]);
|
||||
System.setProperty("java.net.socks.password", proxy[3]);
|
||||
|
||||
final String user = proxy[2];
|
||||
final char[] pass = proxy[3].toCharArray();
|
||||
|
||||
Authenticator.setDefault(new Authenticator()
|
||||
{
|
||||
private PasswordAuthentication auth = new PasswordAuthentication(user, pass);
|
||||
|
||||
protected PasswordAuthentication getPasswordAuthentication()
|
||||
{
|
||||
return auth;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (options.has("help"))
|
||||
{
|
||||
parser.printHelpOn(System.out);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
final boolean developerMode = true;
|
||||
|
||||
if (developerMode)
|
||||
{
|
||||
boolean assertions = false;
|
||||
assert assertions = true;
|
||||
if (!assertions)
|
||||
{
|
||||
java.util.logging.Logger.getAnonymousLogger().warning("Developers should enable assertions; Add `-ea` to your JVM arguments`");
|
||||
}
|
||||
}
|
||||
|
||||
PROFILES_DIR.mkdirs();
|
||||
|
||||
if (options.has("debug"))
|
||||
{
|
||||
final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
logger.setLevel(Level.DEBUG);
|
||||
}
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) ->
|
||||
{
|
||||
log.error("Uncaught exception:", throwable);
|
||||
if (throwable instanceof AbstractMethodError)
|
||||
{
|
||||
log.error("Classes are out of date; Build with maven again.");
|
||||
}
|
||||
});
|
||||
|
||||
if (!options.has("no-splash"))
|
||||
{
|
||||
splashScreen.open(4);
|
||||
}
|
||||
|
||||
// The submessage is shown in case the connection is slow
|
||||
splashScreen.setMessage("Starting RuneLite Injector");
|
||||
splashScreen.setSubMessage(" ");
|
||||
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
injector = Guice.createInjector(new RuneLiteModule(
|
||||
options.valueOf(updateMode),
|
||||
developerMode));
|
||||
|
||||
injector.getInstance(RuneLite.class).start();
|
||||
splashScreen.setProgress(1, 5);
|
||||
final long end = System.currentTimeMillis();
|
||||
final RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
|
||||
final long uptime = rb.getUptime();
|
||||
log.info("Client initialization took {}ms. Uptime: {}ms", end - start, uptime);
|
||||
}
|
||||
|
||||
public void start() throws Exception
|
||||
{
|
||||
// Load RuneLite or Vanilla client
|
||||
final boolean isOutdated = client == null;
|
||||
|
||||
if (!isOutdated)
|
||||
{
|
||||
// Inject members into client
|
||||
injector.injectMembers(client);
|
||||
}
|
||||
|
||||
// Load user configuration
|
||||
splashScreen.setMessage("Loading configuration");
|
||||
configManager.load();
|
||||
|
||||
// Load the session, including saved configuration
|
||||
sessionManager.loadSession();
|
||||
splashScreen.setProgress(2, 5);
|
||||
|
||||
splashScreen.setMessage("Loading plugins");
|
||||
|
||||
// Begin watching for new plugins
|
||||
pluginManager.watch();
|
||||
|
||||
// Tell the plugin manager if client is outdated or not
|
||||
pluginManager.setOutdated(isOutdated);
|
||||
|
||||
// Load the plugins, but does not start them yet.
|
||||
// This will initialize configuration
|
||||
pluginManager.loadCorePlugins();
|
||||
|
||||
// Plugins have provided their config, so set default config
|
||||
// to main settings
|
||||
pluginManager.loadDefaultPluginConfiguration();
|
||||
splashScreen.setProgress(3, 5);
|
||||
|
||||
splashScreen.setMessage("Starting Session");
|
||||
// Start client session
|
||||
clientSessionManager.start();
|
||||
splashScreen.setProgress(4, 5);
|
||||
|
||||
// Load the session, including saved configuration
|
||||
splashScreen.setMessage("Loading interface");
|
||||
splashScreen.setProgress(5, 5);
|
||||
|
||||
// Initialize UI
|
||||
clientUI.open(this);
|
||||
|
||||
// Close the splash screen
|
||||
splashScreen.close();
|
||||
|
||||
// Register event listeners
|
||||
eventBus.register(clientUI);
|
||||
eventBus.register(pluginManager);
|
||||
eventBus.register(overlayManager);
|
||||
eventBus.register(drawManager);
|
||||
eventBus.register(infoBoxManager);
|
||||
eventBus.register(partyService);
|
||||
|
||||
if (!isOutdated)
|
||||
{
|
||||
// Initialize chat colors
|
||||
chatMessageManager.get().loadColors();
|
||||
|
||||
eventBus.register(overlayRenderer.get());
|
||||
eventBus.register(clanManager.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());
|
||||
|
||||
// Add core overlays
|
||||
WidgetOverlay.createOverlays(client).forEach(overlayManager::add);
|
||||
overlayManager.add(infoBoxOverlay.get());
|
||||
overlayManager.add(worldMapOverlay.get());
|
||||
overlayManager.add(tooltipOverlay.get());
|
||||
overlayManager.add(arrowWorldOverlay.get());
|
||||
overlayManager.add(arrowMinimapOverlay.get());
|
||||
}
|
||||
|
||||
// Start plugins
|
||||
pluginManager.startCorePlugins();
|
||||
|
||||
// Register additional schedulers
|
||||
if (this.client != null)
|
||||
{
|
||||
scheduler.registerObject(modelOutlineRenderer.get());
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
configManager.sendConfig();
|
||||
clientSessionManager.shutdown();
|
||||
discordService.close();
|
||||
|
||||
for (final Plugin plugin : pluginManager.getPlugins())
|
||||
{
|
||||
try
|
||||
{
|
||||
pluginManager.stopPlugin(plugin);
|
||||
}
|
||||
catch (PluginInstantiationException e)
|
||||
{
|
||||
log.warn("Failed to gracefully close plugin", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void setInjector(Injector injector)
|
||||
{
|
||||
RuneLite.injector = injector;
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.name.Names;
|
||||
import java.applet.Applet;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.hooks.Callbacks;
|
||||
import net.runelite.client.account.SessionManager;
|
||||
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.RuneLiteConfig;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.menus.MenuManager;
|
||||
import net.runelite.client.plugins.PluginManager;
|
||||
import net.runelite.client.rs.ClientLoader;
|
||||
import net.runelite.client.rs.ClientUpdateCheckMode;
|
||||
import net.runelite.client.task.Scheduler;
|
||||
import net.runelite.client.util.DeferredEventBus;
|
||||
import net.runelite.client.util.ExecutorServiceExceptionLogger;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Slf4j
|
||||
public class RuneLiteModule extends AbstractModule
|
||||
{
|
||||
private final ClientUpdateCheckMode updateCheckMode;
|
||||
private final boolean developerMode;
|
||||
|
||||
public RuneLiteModule(final ClientUpdateCheckMode updateCheckMode, final boolean developerMode)
|
||||
{
|
||||
this.updateCheckMode = updateCheckMode;
|
||||
this.developerMode = developerMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure()
|
||||
{
|
||||
bindConstant().annotatedWith(Names.named("updateCheckMode")).to(updateCheckMode);
|
||||
bindConstant().annotatedWith(Names.named("developerMode")).to(developerMode);
|
||||
bind(ScheduledExecutorService.class).toInstance(new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor()));
|
||||
bind(OkHttpClient.class).toInstance(RuneLiteAPI.CLIENT);
|
||||
bind(MenuManager.class);
|
||||
bind(ChatMessageManager.class);
|
||||
bind(ItemManager.class);
|
||||
bind(Scheduler.class);
|
||||
bind(PluginManager.class);
|
||||
bind(RuneLiteProperties.class);
|
||||
bind(SessionManager.class);
|
||||
|
||||
bind(Callbacks.class).to(Hooks.class);
|
||||
|
||||
bind(EventBus.class)
|
||||
.toInstance(new EventBus());
|
||||
|
||||
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
|
||||
@Singleton
|
||||
Applet provideApplet(ClientLoader clientLoader)
|
||||
{
|
||||
return clientLoader.load();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Client provideClient(@Nullable Applet applet)
|
||||
{
|
||||
return applet instanceof Client ? (Client) applet : null;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
RuneLiteConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
return configManager.getConfig(RuneLiteConfig.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ChatColorConfig provideChatColorConfig(ConfigManager configManager)
|
||||
{
|
||||
return configManager.getConfig(ChatColorConfig.class);
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.plugins.runeliteplus.RuneLitePlusPlugin;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class RuneLiteProperties
|
||||
{
|
||||
public static String discordAppID = "409416265891971072";
|
||||
private static final String RUNELITE_TITLE = "runelite.title";
|
||||
private static final String RUNELITE_VERSION = "runelite.version";
|
||||
private static final String RUNESCAPE_VERSION = "runescape.version";
|
||||
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 = "runelite.launcher.version";
|
||||
|
||||
private final Properties properties = new Properties();
|
||||
|
||||
@Inject
|
||||
public RuneLiteProperties()
|
||||
{
|
||||
try (InputStream in = getClass().getResourceAsStream("runelite.properties"))
|
||||
{
|
||||
properties.load(in);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("unable to load propertries", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public 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();
|
||||
}
|
||||
|
||||
public String getVersion()
|
||||
{
|
||||
return properties.getProperty(RUNELITE_VERSION);
|
||||
}
|
||||
|
||||
public String getRunescapeVersion()
|
||||
{
|
||||
return properties.getProperty(RUNESCAPE_VERSION);
|
||||
}
|
||||
|
||||
public String getDiscordAppId()
|
||||
{
|
||||
if (RuneLitePlusPlugin.customPresenceEnabled)
|
||||
{
|
||||
return properties.getProperty(RuneLitePlusPlugin.rlPlusDiscordApp);
|
||||
}
|
||||
else
|
||||
{
|
||||
return properties.getProperty(DISCORD_APP_ID);
|
||||
}
|
||||
}
|
||||
|
||||
public String getDiscordInvite()
|
||||
{
|
||||
return properties.getProperty(DISCORD_INVITE);
|
||||
}
|
||||
|
||||
public String getGithubLink()
|
||||
{
|
||||
return properties.getProperty(GITHUB_LINK);
|
||||
}
|
||||
|
||||
public String getWikiLink()
|
||||
{
|
||||
return properties.getProperty(WIKI_LINK);
|
||||
}
|
||||
|
||||
public String getPatreonLink()
|
||||
{
|
||||
return properties.getProperty(PATREON_LINK);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getLauncherVersion()
|
||||
{
|
||||
return System.getProperty(LAUNCHER_VERSION_PROPERTY);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.UUID;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
class SessionClient
|
||||
{
|
||||
UUID open() throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getRuneLitePlusSessionBase().newBuilder()
|
||||
.build();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
ResponseBody body = response.body();
|
||||
|
||||
InputStream in = body.byteStream();
|
||||
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), UUID.class);
|
||||
}
|
||||
catch (JsonParseException | IllegalArgumentException ex) // UUID.fromString can throw IllegalArgumentException
|
||||
{
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
void ping(UUID uuid) throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getRuneLitePlusSessionBase().newBuilder()
|
||||
.addPathSegment("ping")
|
||||
.addQueryParameter("session", uuid.toString())
|
||||
.build();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
{
|
||||
throw new IOException("Unsuccessful ping");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void delete(UUID uuid) throws IOException
|
||||
{
|
||||
HttpUrl url = RuneLiteAPI.getRuneLitePlusSessionBase().newBuilder()
|
||||
.addQueryParameter("session", uuid.toString())
|
||||
.build();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.delete()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
RuneLiteAPI.CLIENT.newCall(request).execute().close();
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.account;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(of = "uuid")
|
||||
public class AccountSession
|
||||
{
|
||||
private final UUID uuid;
|
||||
private final Instant created;
|
||||
private String username;
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.account;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
import javax.inject.Inject;
|
||||
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;
|
||||
import net.runelite.client.ws.WSClient;
|
||||
import net.runelite.http.api.account.AccountClient;
|
||||
import net.runelite.http.api.account.OAuthResponse;
|
||||
import net.runelite.http.api.ws.messages.LoginResponse;
|
||||
|
||||
@Singleton
|
||||
@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;
|
||||
|
||||
@Inject
|
||||
private SessionManager(ConfigManager configManager, EventBus eventBus, WSClient wsClient)
|
||||
{
|
||||
this.configManager = configManager;
|
||||
this.eventBus = eventBus;
|
||||
this.wsClient = wsClient;
|
||||
eventBus.register(this);
|
||||
}
|
||||
|
||||
public void loadSession()
|
||||
{
|
||||
if (!SESSION_FILE.exists())
|
||||
{
|
||||
log.info("No session file exists");
|
||||
return;
|
||||
}
|
||||
|
||||
AccountSession session;
|
||||
|
||||
try (FileInputStream in = new FileInputStream(SESSION_FILE))
|
||||
{
|
||||
session = new Gson().fromJson(new InputStreamReader(in), AccountSession.class);
|
||||
|
||||
log.debug("Loaded session for {}", session.getUsername());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("Unable to load session file", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if session is still valid
|
||||
AccountClient accountClient = new AccountClient(session.getUuid());
|
||||
if (!accountClient.sesssionCheck())
|
||||
{
|
||||
log.debug("Loaded session {} is invalid", session.getUuid());
|
||||
return;
|
||||
}
|
||||
|
||||
openSession(session, false);
|
||||
}
|
||||
|
||||
private void saveSession()
|
||||
{
|
||||
if (accountSession == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileWriter fw = new FileWriter(SESSION_FILE))
|
||||
{
|
||||
new Gson().toJson(accountSession, fw);
|
||||
|
||||
log.debug("Saved session to {}", SESSION_FILE);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("Unable to save session file", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteSession()
|
||||
{
|
||||
SESSION_FILE.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given session as the active session and open a socket to the
|
||||
* server with the given session
|
||||
*
|
||||
* @param session session
|
||||
*/
|
||||
private void openSession(AccountSession session, boolean openSocket)
|
||||
{
|
||||
// Change session on the websocket
|
||||
if (openSocket)
|
||||
{
|
||||
wsClient.changeSession(session.getUuid());
|
||||
}
|
||||
|
||||
accountSession = session;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
eventBus.post(new SessionOpen());
|
||||
}
|
||||
|
||||
private void closeSession()
|
||||
{
|
||||
wsClient.changeSession(null);
|
||||
|
||||
if (accountSession == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Logging out of account {}", accountSession.getUsername());
|
||||
|
||||
AccountClient client = new AccountClient(accountSession.getUuid());
|
||||
try
|
||||
{
|
||||
client.logout();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("Unable to logout of session", ex);
|
||||
}
|
||||
|
||||
accountSession = null; // No more account
|
||||
|
||||
// Restore config
|
||||
configManager.switchSession();
|
||||
|
||||
eventBus.post(new SessionClose());
|
||||
}
|
||||
|
||||
public void login()
|
||||
{
|
||||
// If a session is already open, use that id. Otherwise generate a new id.
|
||||
UUID uuid = wsClient.getSessionId() != null ? wsClient.getSessionId() : UUID.randomUUID();
|
||||
AccountClient loginClient = new AccountClient(uuid);
|
||||
|
||||
final OAuthResponse login;
|
||||
|
||||
try
|
||||
{
|
||||
login = loginClient.login();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("Unable to get oauth url", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new session
|
||||
openSession(new AccountSession(login.getUid(), Instant.now()), true);
|
||||
|
||||
// Navigate to login link
|
||||
LinkBrowser.browse(login.getOauthUrl());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onLoginResponse(LoginResponse loginResponse)
|
||||
{
|
||||
log.debug("Now logged in as {}", loginResponse.getUsername());
|
||||
|
||||
AccountSession session = getAccountSession();
|
||||
session.setUsername(loginResponse.getUsername());
|
||||
|
||||
// Open session, again, now that we have a username
|
||||
// This triggers onSessionOpen
|
||||
// The socket is already opened here anyway so we pass true for openSocket
|
||||
openSession(session, true);
|
||||
|
||||
// Save session to disk
|
||||
saveSession();
|
||||
}
|
||||
|
||||
public void logout()
|
||||
{
|
||||
closeSession();
|
||||
deleteSession();
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* 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.callback;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class ClientThread
|
||||
{
|
||||
private ConcurrentLinkedQueue<BooleanSupplier> invokes = new ConcurrentLinkedQueue<>();
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
public void invoke(Runnable r)
|
||||
{
|
||||
invoke(() ->
|
||||
{
|
||||
r.run();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Will run r on the game thread, at a unspecified point in the future.
|
||||
* If r returns false, r will be ran again, at a later point
|
||||
*/
|
||||
public void invoke(BooleanSupplier r)
|
||||
{
|
||||
if (client.isClientThread())
|
||||
{
|
||||
if (r.getAsBoolean())
|
||||
{
|
||||
invokes.add(r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
invokeLater(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will run r on the game thread after this method returns
|
||||
* If r returns false, r will be ran again, at a later point
|
||||
*/
|
||||
public void invokeLater(Runnable r)
|
||||
{
|
||||
invokeLater(() ->
|
||||
{
|
||||
r.run();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public void invokeLater(BooleanSupplier r)
|
||||
{
|
||||
invokes.add(r);
|
||||
}
|
||||
|
||||
void invoke()
|
||||
{
|
||||
assert client.isClientThread();
|
||||
Iterator<BooleanSupplier> ir = invokes.iterator();
|
||||
for (; ir.hasNext(); )
|
||||
{
|
||||
BooleanSupplier r = ir.next();
|
||||
boolean remove = true;
|
||||
try
|
||||
{
|
||||
remove = r.getAsBoolean();
|
||||
}
|
||||
catch (ThreadDeath d)
|
||||
{
|
||||
throw d;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
log.warn("Exception in invoke", e);
|
||||
}
|
||||
if (remove)
|
||||
{
|
||||
ir.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,534 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.callback;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
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.Constants;
|
||||
import net.runelite.api.MainBufferProvider;
|
||||
import net.runelite.api.NullItemID;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.RenderOverview;
|
||||
import net.runelite.api.Renderable;
|
||||
import net.runelite.api.WorldMapManager;
|
||||
import net.runelite.api.events.BeforeMenuRender;
|
||||
import net.runelite.api.events.BeforeRender;
|
||||
import net.runelite.api.events.GameTick;
|
||||
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.input.KeyManager;
|
||||
import net.runelite.client.input.MouseManager;
|
||||
import net.runelite.client.task.Scheduler;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.ui.DrawManager;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
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;
|
||||
|
||||
/**
|
||||
* This class contains field required for mixins and runelite hooks to work.
|
||||
* All remaining method hooks in this class are performance-critical or contain client-specific logic and so they
|
||||
* can't just be placed in mixins or sent through event bus.
|
||||
*/
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class Hooks implements Callbacks
|
||||
{
|
||||
private static final long CHECK = Constants.GAME_TICK_LENGTH; // ms - how often to run checks
|
||||
|
||||
private static final Injector injector = RuneLite.getInjector();
|
||||
private static final Client client = injector.getInstance(Client.class);
|
||||
private 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();
|
||||
|
||||
@Inject
|
||||
private EventBus eventBus;
|
||||
|
||||
@Inject
|
||||
private DeferredEventBus deferredEventBus;
|
||||
|
||||
@Inject
|
||||
private Scheduler scheduler;
|
||||
|
||||
@Inject
|
||||
private InfoBoxManager infoBoxManager;
|
||||
|
||||
@Inject
|
||||
private ChatMessageManager chatMessageManager;
|
||||
|
||||
@Inject
|
||||
private MouseManager mouseManager;
|
||||
|
||||
@Inject
|
||||
private KeyManager keyManager;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Inject
|
||||
private DrawManager drawManager;
|
||||
|
||||
@Inject
|
||||
private Notifier notifier;
|
||||
|
||||
@Inject
|
||||
private ClientUI clientUi;
|
||||
|
||||
private Dimension lastStretchedDimensions;
|
||||
private VolatileImage stretchedImage;
|
||||
private Graphics2D stretchedGraphics;
|
||||
|
||||
private long lastCheck;
|
||||
private boolean shouldProcessGameTick;
|
||||
|
||||
@Override
|
||||
public void post(Object event)
|
||||
{
|
||||
eventBus.post(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDeferred(Object event)
|
||||
{
|
||||
deferredEventBus.post(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientMainLoop()
|
||||
{
|
||||
if (shouldProcessGameTick)
|
||||
{
|
||||
shouldProcessGameTick = false;
|
||||
|
||||
deferredEventBus.replay();
|
||||
|
||||
eventBus.post(GAME_TICK);
|
||||
|
||||
int tick = client.getTickCount();
|
||||
client.setTickCount(tick + 1);
|
||||
}
|
||||
|
||||
eventBus.post(BEFORE_RENDER);
|
||||
|
||||
clientThread.invoke();
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (now - lastCheck < CHECK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lastCheck = now;
|
||||
|
||||
try
|
||||
{
|
||||
// tick pending scheduled tasks
|
||||
scheduler.tick();
|
||||
|
||||
// cull infoboxes
|
||||
infoBoxManager.cull();
|
||||
|
||||
chatMessageManager.process();
|
||||
|
||||
checkWorldMap();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("error during main loop tasks", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the world map opens it loads about ~100mb of data into memory, which
|
||||
* represents about half of the total memory allocated by the client.
|
||||
* This gets cached and never released, which causes GC pressure which can affect
|
||||
* performance. This method reinitializes the world map cache, which allows the
|
||||
* data to be garbage collected, and causes the map data from disk each time
|
||||
* is it opened.
|
||||
*/
|
||||
private void checkWorldMap()
|
||||
{
|
||||
Widget widget = client.getWidget(WORLD_MAP_VIEW);
|
||||
|
||||
if (widget != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RenderOverview renderOverview = client.getRenderOverview();
|
||||
|
||||
if (renderOverview == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WorldMapManager manager = renderOverview.getWorldMapManager();
|
||||
|
||||
if (manager != null && manager.isLoaded())
|
||||
{
|
||||
log.debug("World map was closed, reinitializing");
|
||||
renderOverview.initializeWorldMap(renderOverview.getWorldMapData());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseManager.processMousePressed(mouseEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseReleased(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseManager.processMouseReleased(mouseEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseClicked(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseManager.processMouseClicked(mouseEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseManager.processMouseEntered(mouseEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseManager.processMouseExited(mouseEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseDragged(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseManager.processMouseDragged(mouseEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseMoved(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseManager.processMouseMoved(mouseEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseWheelEvent mouseWheelMoved(MouseWheelEvent event)
|
||||
{
|
||||
return mouseManager.processMouseWheelMoved(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent keyEvent)
|
||||
{
|
||||
keyManager.processKeyPressed(keyEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent keyEvent)
|
||||
{
|
||||
keyManager.processKeyReleased(keyEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent keyEvent)
|
||||
{
|
||||
keyManager.processKeyTyped(keyEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(MainBufferProvider mainBufferProvider, Graphics graphics, int x, int y)
|
||||
{
|
||||
if (graphics == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Image image = mainBufferProvider.getImage();
|
||||
final Image finalImage;
|
||||
final Graphics2D graphics2d = (Graphics2D) image.getGraphics();
|
||||
|
||||
try
|
||||
{
|
||||
renderer.render(graphics2d, OverlayLayer.ALWAYS_ON_TOP);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("Error during overlay rendering", ex);
|
||||
}
|
||||
|
||||
notifier.processFlash(graphics2d);
|
||||
|
||||
// Draw clientUI overlays
|
||||
clientUi.paintOverlays(graphics2d);
|
||||
|
||||
graphics2d.dispose();
|
||||
|
||||
if (client.isGpu())
|
||||
{
|
||||
// processDrawComplete gets called on GPU by the gpu plugin at the end of its
|
||||
// drawing cycle, which is later on.
|
||||
return;
|
||||
}
|
||||
|
||||
// Stretch the game image if the user has that enabled
|
||||
if (client.isStretchedEnabled())
|
||||
{
|
||||
GraphicsConfiguration gc = clientUi.getGraphicsConfiguration();
|
||||
Dimension stretchedDimensions = client.getStretchedDimensions();
|
||||
|
||||
if (lastStretchedDimensions == null || !lastStretchedDimensions.equals(stretchedDimensions)
|
||||
|| (stretchedImage != null && stretchedImage.validate(gc) == VolatileImage.IMAGE_INCOMPATIBLE))
|
||||
{
|
||||
/*
|
||||
Reuse the resulting image instance to avoid creating an extreme amount of objects
|
||||
*/
|
||||
stretchedImage = gc.createCompatibleVolatileImage(stretchedDimensions.width, stretchedDimensions.height);
|
||||
|
||||
if (stretchedGraphics != null)
|
||||
{
|
||||
stretchedGraphics.dispose();
|
||||
}
|
||||
stretchedGraphics = (Graphics2D) stretchedImage.getGraphics();
|
||||
|
||||
lastStretchedDimensions = stretchedDimensions;
|
||||
|
||||
/*
|
||||
Fill Canvas before drawing stretched image to prevent artifacts.
|
||||
*/
|
||||
graphics.setColor(Color.BLACK);
|
||||
graphics.fillRect(0, 0, client.getCanvas().getWidth(), client.getCanvas().getHeight());
|
||||
}
|
||||
|
||||
stretchedGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
client.isStretchedFast()
|
||||
? RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR
|
||||
: RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
stretchedGraphics.drawImage(image, 0, 0, stretchedDimensions.width, stretchedDimensions.height, null);
|
||||
|
||||
finalImage = stretchedImage;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalImage = image;
|
||||
}
|
||||
|
||||
// Draw the image onto the game canvas
|
||||
graphics.drawImage(finalImage, 0, 0, client.getCanvas());
|
||||
|
||||
// finalImage is backed by the client buffer which will change soon. make a copy
|
||||
// so that callbacks can safely use it later from threads.
|
||||
drawManager.processDrawComplete(() -> copy(finalImage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an image
|
||||
*
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
private static Image copy(Image src)
|
||||
{
|
||||
final int width = src.getWidth(null);
|
||||
final int height = src.getHeight(null);
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics graphics = image.getGraphics();
|
||||
graphics.drawImage(src, 0, 0, width, height, null);
|
||||
graphics.dispose();
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScene()
|
||||
{
|
||||
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
|
||||
BufferedImage image = (BufferedImage) bufferProvider.getImage();
|
||||
Graphics2D graphics2d = image.createGraphics();
|
||||
|
||||
// Update selected scene tile
|
||||
if (!client.isMenuOpen())
|
||||
{
|
||||
Point p = client.getMouseCanvasPosition();
|
||||
p = new Point(
|
||||
p.getX() - client.getViewportXOffset(),
|
||||
p.getY() - client.getViewportYOffset());
|
||||
|
||||
client.setCheckClick(true);
|
||||
client.setMouseCanvasHoverPosition(p);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
renderer.render(graphics2d, OverlayLayer.ABOVE_SCENE);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("Error during overlay rendering", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
graphics2d.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawAboveOverheads()
|
||||
{
|
||||
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
|
||||
BufferedImage image = (BufferedImage) bufferProvider.getImage();
|
||||
Graphics2D graphics2d = image.createGraphics();
|
||||
|
||||
try
|
||||
{
|
||||
renderer.render(graphics2d, OverlayLayer.UNDER_WIDGETS);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("Error during overlay rendering", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
graphics2d.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawAfterWidgets()
|
||||
{
|
||||
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
|
||||
BufferedImage image = (BufferedImage) bufferProvider.getImage();
|
||||
Graphics2D graphics2d = image.createGraphics();
|
||||
|
||||
try
|
||||
{
|
||||
renderer.render(graphics2d, OverlayLayer.ABOVE_WIDGETS);
|
||||
renderer.render(graphics2d, OverlayLayer.ABOVE_MAP);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("Error during overlay rendering", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
graphics2d.dispose();
|
||||
}
|
||||
|
||||
// WidgetItemOverlays render at ABOVE_WIDGETS, reset widget item
|
||||
// list for next frame.
|
||||
overlayManager.getItemWidgets().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNpcs()
|
||||
{
|
||||
// The NPC update event seem to run every server tick,
|
||||
// but having the game tick event after all packets
|
||||
// have been processed is typically more useful.
|
||||
shouldProcessGameTick = true;
|
||||
// Replay deferred events, otherwise if two npc
|
||||
// update packets get processed in one frame, a
|
||||
// despawn event could be published prior to the
|
||||
// spawn event, which is deferred
|
||||
deferredEventBus.replay();
|
||||
}
|
||||
|
||||
public static void renderDraw(Renderable renderable, 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(renderable, orientation, pitchSin, pitchCos, yawSin, yawCos, x, y, z, hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderable.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)
|
||||
{
|
||||
// Empty bank item
|
||||
if (widgetItem.getId() != NullItemID.NULL_6512)
|
||||
{
|
||||
overlayManager.getItemWidgets().add(widgetItem);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean drawMenu()
|
||||
{
|
||||
BeforeMenuRender event = new BeforeMenuRender();
|
||||
client.getCallbacks().post(event);
|
||||
return event.isConsumed();
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Tomas Slusny <slusnucky@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.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(exclude = {"color", "isDefault"})
|
||||
public class ChatColor
|
||||
{
|
||||
private ChatColorType type;
|
||||
private Color color;
|
||||
private boolean transparent;
|
||||
private boolean isDefault;
|
||||
|
||||
public ChatColor(ChatColorType type, Color color, boolean transparent)
|
||||
{
|
||||
this(type, color, transparent, false);
|
||||
}
|
||||
|
||||
public ChatColor(ChatColorType type, Color color, boolean transparent, boolean isDefault)
|
||||
{
|
||||
this.type = type;
|
||||
this.color = color;
|
||||
this.transparent = transparent;
|
||||
this.isDefault = isDefault;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Tomas Slusny <slusnucky@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.chat;
|
||||
|
||||
public enum ChatColorType
|
||||
{
|
||||
NORMAL,
|
||||
HIGHLIGHT
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.chat;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiPredicate;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.client.events.ChatInput;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
class ChatCommand
|
||||
{
|
||||
private final String name;
|
||||
private boolean async;
|
||||
private final BiConsumer<ChatMessage, String> execute;
|
||||
private final BiPredicate<ChatInput, String> input;
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.chat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiPredicate;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.events.ChatInput;
|
||||
import net.runelite.client.events.ChatboxInput;
|
||||
import net.runelite.client.events.PrivateMessageInput;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class ChatCommandManager implements ChatboxInputListener
|
||||
{
|
||||
private final Map<String, ChatCommand> commands = new HashMap<>();
|
||||
|
||||
private final Client client;
|
||||
private final ScheduledExecutorService scheduledExecutorService;
|
||||
|
||||
@Inject
|
||||
private ChatCommandManager(EventBus eventBus, CommandManager commandManager, Client client, ScheduledExecutorService scheduledExecutorService)
|
||||
{
|
||||
this.client = client;
|
||||
this.scheduledExecutorService = scheduledExecutorService;
|
||||
eventBus.register(this);
|
||||
commandManager.register(this);
|
||||
}
|
||||
|
||||
public void registerCommand(String command, BiConsumer<ChatMessage, String> execute)
|
||||
{
|
||||
registerCommand(command, execute, null);
|
||||
}
|
||||
|
||||
public void registerCommand(String command, BiConsumer<ChatMessage, String> execute, BiPredicate<ChatInput, String> input)
|
||||
{
|
||||
commands.put(command.toLowerCase(), new ChatCommand(command, false, execute, input));
|
||||
}
|
||||
|
||||
public void registerCommandAsync(String command, BiConsumer<ChatMessage, String> execute)
|
||||
{
|
||||
registerCommandAsync(command, execute, null);
|
||||
}
|
||||
|
||||
public void registerCommandAsync(String command, BiConsumer<ChatMessage, String> execute, BiPredicate<ChatInput, String> input)
|
||||
{
|
||||
commands.put(command.toLowerCase(), new ChatCommand(command, true, execute, input));
|
||||
}
|
||||
|
||||
public void unregisterCommand(String command)
|
||||
{
|
||||
commands.remove(command.toLowerCase());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onChatMessage(ChatMessage chatMessage)
|
||||
{
|
||||
if (client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (chatMessage.getType())
|
||||
{
|
||||
case PUBLICCHAT:
|
||||
case MODCHAT:
|
||||
case FRIENDSCHAT:
|
||||
case PRIVATECHAT:
|
||||
case MODPRIVATECHAT:
|
||||
case PRIVATECHATOUT:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
String message = chatMessage.getMessage();
|
||||
|
||||
String command = extractCommand(message);
|
||||
if (command == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChatCommand chatCommand = commands.get(command.toLowerCase());
|
||||
if (chatCommand == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (chatCommand.isAsync())
|
||||
{
|
||||
scheduledExecutorService.execute(() -> chatCommand.getExecute().accept(chatMessage, message));
|
||||
}
|
||||
else
|
||||
{
|
||||
chatCommand.getExecute().accept(chatMessage, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChatboxInput(ChatboxInput chatboxInput)
|
||||
{
|
||||
String message = chatboxInput.getValue();
|
||||
if (message.startsWith("/"))
|
||||
{
|
||||
message = message.substring(1); // clan chat input
|
||||
}
|
||||
|
||||
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(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)
|
||||
{
|
||||
int idx = message.indexOf(' ');
|
||||
if (idx == -1)
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
return message.substring(0, idx);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Tomas Slusny <slusnucky@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.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import net.runelite.client.util.ColorUtil;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
public class ChatMessageBuilder
|
||||
{
|
||||
private final StringBuilder builder = new StringBuilder();
|
||||
|
||||
public ChatMessageBuilder append(final ChatColorType type)
|
||||
{
|
||||
builder.append("<col").append(type.name()).append(">");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatMessageBuilder append(final Color color, final String message)
|
||||
{
|
||||
builder.append(ColorUtil.wrapWithColorTag(message, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatMessageBuilder append(final String message)
|
||||
{
|
||||
builder.append(Text.escapeJagex(message));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatMessageBuilder img(int imageId)
|
||||
{
|
||||
builder.append("<img=").append(imageId).append('>');
|
||||
return this;
|
||||
}
|
||||
|
||||
public String build()
|
||||
{
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,636 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Tomas Slusny <slusnucky@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.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;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import net.runelite.api.ChatLineBuffer;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.MessageNode;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.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.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 = ImmutableSet.of(12336, 12335, 12592, 12080, 12079, 12436);
|
||||
|
||||
private final Multimap<ChatMessageType, ChatColor> colorCache = HashMultimap.create();
|
||||
private final Client client;
|
||||
private final ChatColorConfig chatColorConfig;
|
||||
private final ClientThread clientThread;
|
||||
private int transparencyVarbit = -1;
|
||||
private final Queue<QueuedMessage> queuedMessages = new ConcurrentLinkedQueue<>();
|
||||
|
||||
@Inject
|
||||
private ChatMessageManager(
|
||||
Client client,
|
||||
ChatColorConfig chatColorConfig,
|
||||
ClientThread clientThread)
|
||||
{
|
||||
this.client = client;
|
||||
this.chatColorConfig = chatColorConfig;
|
||||
this.clientThread = clientThread;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onVarbitChanged(VarbitChanged event)
|
||||
{
|
||||
int setting = client.getVar(Varbits.TRANSPARENT_CHATBOX);
|
||||
|
||||
if (transparencyVarbit != setting)
|
||||
{
|
||||
transparencyVarbit = setting;
|
||||
refreshAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onResizeableChanged(ResizeableChanged event)
|
||||
{
|
||||
refreshAll();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onConfigChanged(ConfigChanged event)
|
||||
{
|
||||
if (event.getGroup().equals("textrecolor"))
|
||||
{
|
||||
loadColors();
|
||||
clientThread.invokeLater(this::refreshAll);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onChatMessage(ChatMessage chatMessage)
|
||||
{
|
||||
MessageNode messageNode = chatMessage.getMessageNode();
|
||||
ChatMessageType chatMessageType = chatMessage.getType();
|
||||
|
||||
boolean isChatboxTransparent = client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1;
|
||||
Color usernameColor = null;
|
||||
Color senderColor = null;
|
||||
|
||||
switch (chatMessageType)
|
||||
{
|
||||
case MODPRIVATECHAT:
|
||||
case PRIVATECHAT:
|
||||
case PRIVATECHATOUT:
|
||||
usernameColor = isChatboxTransparent ? chatColorConfig.transparentPrivateUsernames() : chatColorConfig.opaquePrivateUsernames();
|
||||
break;
|
||||
|
||||
case TRADEREQ:
|
||||
case AUTOTYPER:
|
||||
case PUBLICCHAT:
|
||||
case MODCHAT:
|
||||
{
|
||||
boolean isFriend = client.isFriended(chatMessage.getName(), true) && !client.getLocalPlayer().getName().equals(chatMessage.getName());
|
||||
|
||||
if (isFriend)
|
||||
{
|
||||
usernameColor = isChatboxTransparent ? chatColorConfig.transparentPublicFriendUsernames() : chatColorConfig.opaquePublicFriendUsernames();
|
||||
}
|
||||
if (usernameColor == null)
|
||||
{
|
||||
usernameColor = isChatboxTransparent ? chatColorConfig.transparentUsername() : chatColorConfig.opaqueUsername();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FRIENDSCHAT:
|
||||
usernameColor = isChatboxTransparent ? chatColorConfig.transparentClanUsernames() : chatColorConfig.opaqueClanUsernames();
|
||||
break;
|
||||
}
|
||||
|
||||
senderColor = isChatboxTransparent ? chatColorConfig.transparentClanChannelName() : chatColorConfig.opaqueClanChannelName();
|
||||
|
||||
if (usernameColor != null)
|
||||
{
|
||||
messageNode.setName(ColorUtil.wrapWithColorTag(messageNode.getName(), usernameColor));
|
||||
}
|
||||
|
||||
String sender = chatMessage.getSender();
|
||||
if (senderColor != null && !Strings.isNullOrEmpty(sender))
|
||||
{
|
||||
messageNode.setSender(ColorUtil.wrapWithColorTag(sender, senderColor));
|
||||
}
|
||||
|
||||
final Collection<ChatColor> chatColors = colorCache.get(chatMessageType);
|
||||
for (ChatColor chatColor : chatColors)
|
||||
{
|
||||
if (chatColor.isTransparent() != isChatboxTransparent || chatColor.getType() != ChatColorType.NORMAL || chatColor.isDefault())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
messageNode.setValue(ColorUtil.wrapWithColorTag(messageNode.getValue(), chatColor.getColor()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent)
|
||||
{
|
||||
final String eventName = scriptCallbackEvent.getEventName();
|
||||
|
||||
switch (eventName)
|
||||
{
|
||||
case "privateChatFrom":
|
||||
case "privateChatTo":
|
||||
case "privateChatSplitFrom":
|
||||
case "privateChatSplitTo":
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isChatboxTransparent = client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1;
|
||||
Color usernameColor = isChatboxTransparent ? chatColorConfig.transparentPrivateUsernames() : chatColorConfig.opaquePrivateUsernames();
|
||||
if (usernameColor == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final String[] stringStack = client.getStringStack();
|
||||
final int stringStackSize = client.getStringStackSize();
|
||||
|
||||
// Stack is: To/From playername :
|
||||
String toFrom = stringStack[stringStackSize - 3];
|
||||
stringStack[stringStackSize - 3] = ColorUtil.prependColorTag(toFrom, usernameColor);
|
||||
}
|
||||
|
||||
private static Color getDefaultColor(ChatMessageType type, boolean transparent)
|
||||
{
|
||||
if (!transparent)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PUBLICCHAT:
|
||||
case MODCHAT:
|
||||
return JagexColors.CHAT_PUBLIC_TEXT_OPAQUE_BACKGROUND;
|
||||
case PRIVATECHATOUT:
|
||||
case MODPRIVATECHAT:
|
||||
case PRIVATECHAT:
|
||||
return JagexColors.CHAT_PRIVATE_MESSAGE_TEXT_OPAQUE_BACKGROUND;
|
||||
case FRIENDSCHAT:
|
||||
return JagexColors.CHAT_CLAN_TEXT_OPAQUE_BACKGROUND;
|
||||
case ITEM_EXAMINE:
|
||||
case OBJECT_EXAMINE:
|
||||
case NPC_EXAMINE:
|
||||
case CONSOLE:
|
||||
return JagexColors.CHAT_GAME_EXAMINE_TEXT_OPAQUE_BACKGROUND;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PUBLICCHAT:
|
||||
case MODCHAT:
|
||||
return JagexColors.CHAT_PUBLIC_TEXT_TRANSPARENT_BACKGROUND;
|
||||
case PRIVATECHATOUT:
|
||||
case MODPRIVATECHAT:
|
||||
case PRIVATECHAT:
|
||||
return JagexColors.CHAT_PRIVATE_MESSAGE_TEXT_TRANSPARENT_BACKGROUND;
|
||||
case FRIENDSCHAT:
|
||||
return JagexColors.CHAT_CLAN_TEXT_TRANSPARENT_BACKGROUND;
|
||||
case ITEM_EXAMINE:
|
||||
case OBJECT_EXAMINE:
|
||||
case NPC_EXAMINE:
|
||||
case CONSOLE:
|
||||
return JagexColors.CHAT_GAME_EXAMINE_TEXT_TRANSPARENT_BACKGROUND;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all configured colors
|
||||
*/
|
||||
public void loadColors()
|
||||
{
|
||||
colorCache.clear();
|
||||
|
||||
// Apply defaults
|
||||
for (ChatMessageType chatMessageType : ChatMessageType.values())
|
||||
{
|
||||
Color defaultTransparent = getDefaultColor(chatMessageType, true);
|
||||
if (defaultTransparent != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, defaultTransparent, true, true), chatMessageType);
|
||||
}
|
||||
|
||||
Color defaultOpaque = getDefaultColor(chatMessageType, false);
|
||||
if (defaultOpaque != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, defaultOpaque, false, true), chatMessageType);
|
||||
}
|
||||
}
|
||||
|
||||
if (chatColorConfig.opaquePublicChat() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaquePublicChat(), false),
|
||||
ChatMessageType.PUBLICCHAT);
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaquePublicChat(), false),
|
||||
ChatMessageType.MODCHAT);
|
||||
}
|
||||
if (chatColorConfig.opaquePublicChatHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaquePublicChatHighlight(), false),
|
||||
ChatMessageType.PUBLICCHAT);
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaquePublicChatHighlight(), false),
|
||||
ChatMessageType.MODCHAT);
|
||||
}
|
||||
if (chatColorConfig.opaquePrivateMessageSent() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaquePrivateMessageSent(), false),
|
||||
ChatMessageType.PRIVATECHATOUT);
|
||||
}
|
||||
if (chatColorConfig.opaquePrivateMessageSentHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaquePrivateMessageSentHighlight(), false),
|
||||
ChatMessageType.PRIVATECHATOUT);
|
||||
}
|
||||
if (chatColorConfig.opaquePrivateMessageReceived() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaquePrivateMessageReceived(), false),
|
||||
ChatMessageType.PRIVATECHAT);
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaquePrivateMessageReceived(), false),
|
||||
ChatMessageType.MODPRIVATECHAT);
|
||||
}
|
||||
if (chatColorConfig.opaquePrivateMessageReceivedHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaquePrivateMessageReceivedHighlight(), false),
|
||||
ChatMessageType.PRIVATECHAT);
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaquePrivateMessageReceivedHighlight(), false),
|
||||
ChatMessageType.MODPRIVATECHAT);
|
||||
}
|
||||
if (chatColorConfig.opaqueClanChatInfo() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueClanChatInfo(), false),
|
||||
ChatMessageType.FRIENDSCHATNOTIFICATION);
|
||||
}
|
||||
if (chatColorConfig.opaqueClanChatInfoHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueClanChatInfoHighlight(), false),
|
||||
ChatMessageType.FRIENDSCHATNOTIFICATION);
|
||||
}
|
||||
if (chatColorConfig.opaqueClanChatMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueClanChatMessage(), false),
|
||||
ChatMessageType.FRIENDSCHAT);
|
||||
}
|
||||
if (chatColorConfig.opaqueClanChatMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueClanChatMessageHighlight(), false),
|
||||
ChatMessageType.FRIENDSCHAT);
|
||||
}
|
||||
if (chatColorConfig.opaqueAutochatMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueAutochatMessage(), false),
|
||||
ChatMessageType.AUTOTYPER);
|
||||
}
|
||||
if (chatColorConfig.opaqueAutochatMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueAutochatMessageHighlight(), false),
|
||||
ChatMessageType.AUTOTYPER);
|
||||
}
|
||||
if (chatColorConfig.opaqueTradeChatMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueTradeChatMessage(), false),
|
||||
ChatMessageType.TRADEREQ);
|
||||
}
|
||||
if (chatColorConfig.opaqueTradeChatMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueTradeChatMessageHighlight(), false),
|
||||
ChatMessageType.TRADEREQ);
|
||||
}
|
||||
if (chatColorConfig.opaqueServerMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueServerMessage(), false),
|
||||
ChatMessageType.GAMEMESSAGE);
|
||||
}
|
||||
if (chatColorConfig.opaqueServerMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueServerMessageHighlight(), false),
|
||||
ChatMessageType.GAMEMESSAGE);
|
||||
}
|
||||
if (chatColorConfig.opaqueGameMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueGameMessage(), false),
|
||||
ChatMessageType.CONSOLE);
|
||||
}
|
||||
if (chatColorConfig.opaqueGameMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueGameMessageHighlight(), false),
|
||||
ChatMessageType.CONSOLE);
|
||||
}
|
||||
if (chatColorConfig.opaqueExamine() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueExamine(), false),
|
||||
ChatMessageType.OBJECT_EXAMINE);
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueExamine(), false),
|
||||
ChatMessageType.NPC_EXAMINE);
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueExamine(), false),
|
||||
ChatMessageType.ITEM_EXAMINE);
|
||||
}
|
||||
if (chatColorConfig.opaqueExamineHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueExamineHighlight(), false),
|
||||
ChatMessageType.OBJECT_EXAMINE);
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueExamineHighlight(), false),
|
||||
ChatMessageType.NPC_EXAMINE);
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueExamineHighlight(), false),
|
||||
ChatMessageType.ITEM_EXAMINE);
|
||||
}
|
||||
if (chatColorConfig.opaqueFiltered() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.opaqueFiltered(), false),
|
||||
ChatMessageType.SPAM);
|
||||
}
|
||||
if (chatColorConfig.opaqueFilteredHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.opaqueFilteredHighlight(), false),
|
||||
ChatMessageType.SPAM);
|
||||
}
|
||||
|
||||
//Transparent Chat Colours
|
||||
if (chatColorConfig.transparentPublicChat() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentPublicChat(), true),
|
||||
ChatMessageType.PUBLICCHAT);
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentPublicChat(), true),
|
||||
ChatMessageType.MODCHAT);
|
||||
}
|
||||
if (chatColorConfig.transparentPublicChatHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentPublicChatHighlight(), true),
|
||||
ChatMessageType.PUBLICCHAT);
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentPublicChatHighlight(), true),
|
||||
ChatMessageType.MODCHAT);
|
||||
}
|
||||
if (chatColorConfig.transparentPrivateMessageSent() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentPrivateMessageSent(), true),
|
||||
ChatMessageType.PRIVATECHATOUT);
|
||||
}
|
||||
if (chatColorConfig.transparentPrivateMessageSentHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentPrivateMessageSentHighlight(), true),
|
||||
ChatMessageType.PRIVATECHATOUT);
|
||||
}
|
||||
if (chatColorConfig.transparentPrivateMessageReceived() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentPrivateMessageReceived(), true),
|
||||
ChatMessageType.PRIVATECHAT);
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentPrivateMessageReceived(), true),
|
||||
ChatMessageType.MODPRIVATECHAT);
|
||||
}
|
||||
if (chatColorConfig.transparentPrivateMessageReceivedHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentPrivateMessageReceivedHighlight(), true),
|
||||
ChatMessageType.PRIVATECHAT);
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentPrivateMessageReceivedHighlight(), true),
|
||||
ChatMessageType.MODPRIVATECHAT);
|
||||
}
|
||||
if (chatColorConfig.transparentClanChatInfo() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentClanChatInfo(), true),
|
||||
ChatMessageType.FRIENDSCHATNOTIFICATION);
|
||||
}
|
||||
if (chatColorConfig.transparentClanChatInfoHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentClanChatInfoHighlight(), true),
|
||||
ChatMessageType.FRIENDSCHATNOTIFICATION);
|
||||
}
|
||||
if (chatColorConfig.transparentClanChatMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentClanChatMessage(), true),
|
||||
ChatMessageType.FRIENDSCHAT);
|
||||
}
|
||||
if (chatColorConfig.transparentClanChatMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentClanChatMessageHighlight(), true),
|
||||
ChatMessageType.FRIENDSCHAT);
|
||||
}
|
||||
if (chatColorConfig.transparentAutochatMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentAutochatMessage(), true),
|
||||
ChatMessageType.AUTOTYPER);
|
||||
}
|
||||
if (chatColorConfig.transparentAutochatMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentAutochatMessageHighlight(), true),
|
||||
ChatMessageType.AUTOTYPER);
|
||||
}
|
||||
if (chatColorConfig.transparentTradeChatMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentTradeChatMessage(), true),
|
||||
ChatMessageType.TRADEREQ);
|
||||
}
|
||||
if (chatColorConfig.transparentTradeChatMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentTradeChatMessageHighlight(), true),
|
||||
ChatMessageType.TRADEREQ);
|
||||
}
|
||||
if (chatColorConfig.transparentServerMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentServerMessage(), true),
|
||||
ChatMessageType.GAMEMESSAGE);
|
||||
}
|
||||
if (chatColorConfig.transparentServerMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentServerMessageHighlight(), true),
|
||||
ChatMessageType.GAMEMESSAGE);
|
||||
}
|
||||
if (chatColorConfig.transparentGameMessage() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentGameMessage(), true),
|
||||
ChatMessageType.CONSOLE);
|
||||
}
|
||||
if (chatColorConfig.transparentGameMessageHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentGameMessageHighlight(), true),
|
||||
ChatMessageType.CONSOLE);
|
||||
}
|
||||
if (chatColorConfig.transparentExamine() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentExamine(), true),
|
||||
ChatMessageType.OBJECT_EXAMINE);
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentExamine(), true),
|
||||
ChatMessageType.NPC_EXAMINE);
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentExamine(), true),
|
||||
ChatMessageType.ITEM_EXAMINE);
|
||||
}
|
||||
if (chatColorConfig.transparentExamineHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentExamineHighlight(), true),
|
||||
ChatMessageType.OBJECT_EXAMINE);
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentExamineHighlight(), true),
|
||||
ChatMessageType.NPC_EXAMINE);
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentExamineHighlight(), true),
|
||||
ChatMessageType.ITEM_EXAMINE);
|
||||
}
|
||||
if (chatColorConfig.transparentFiltered() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.NORMAL, chatColorConfig.transparentFiltered(), true),
|
||||
ChatMessageType.SPAM);
|
||||
}
|
||||
if (chatColorConfig.transparentFilteredHighlight() != null)
|
||||
{
|
||||
cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, chatColorConfig.transparentFilteredHighlight(), true),
|
||||
ChatMessageType.SPAM);
|
||||
}
|
||||
}
|
||||
|
||||
private void cacheColor(final ChatColor chatColor, final ChatMessageType... types)
|
||||
{
|
||||
for (ChatMessageType chatMessageType : types)
|
||||
{
|
||||
// color is excluded from equals/hashCode on ChatColor
|
||||
colorCache.remove(chatMessageType, chatColor);
|
||||
colorCache.put(chatMessageType, chatColor);
|
||||
}
|
||||
}
|
||||
|
||||
public void queue(QueuedMessage message)
|
||||
{
|
||||
queuedMessages.add(message);
|
||||
}
|
||||
|
||||
public void process()
|
||||
{
|
||||
if (!queuedMessages.isEmpty())
|
||||
{
|
||||
try
|
||||
{
|
||||
queuedMessages.forEach(this::add);
|
||||
}
|
||||
finally
|
||||
{
|
||||
queuedMessages.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void add(QueuedMessage message)
|
||||
{
|
||||
// Do not send message if the player is on tutorial island
|
||||
final Player player = client.getLocalPlayer();
|
||||
if (player != null && TUTORIAL_ISLAND_REGIONS.contains(player.getWorldLocation().getRegionID()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// this updates chat cycle
|
||||
client.addChatMessage(
|
||||
message.getType(),
|
||||
MoreObjects.firstNonNull(message.getName(), ""),
|
||||
MoreObjects.firstNonNull(message.getValue(), message.getRuneLiteFormattedMessage()),
|
||||
message.getSender());
|
||||
|
||||
// Get last message from line buffer (the one we just added)
|
||||
final ChatLineBuffer chatLineBuffer = client.getChatLineMap().get(message.getType().getType());
|
||||
final MessageNode[] lines = chatLineBuffer.getLines();
|
||||
final MessageNode line = lines[0];
|
||||
|
||||
// Update the message with RuneLite additions
|
||||
line.setRuneLiteFormatMessage(message.getRuneLiteFormattedMessage());
|
||||
line.setTimestamp(message.getTimestamp());
|
||||
|
||||
update(line);
|
||||
}
|
||||
|
||||
public void update(final MessageNode target)
|
||||
{
|
||||
if (Strings.isNullOrEmpty(target.getRuneLiteFormatMessage()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean transparent = client.isResized() && transparencyVarbit != 0;
|
||||
final Collection<ChatColor> chatColors = colorCache.get(target.getType());
|
||||
|
||||
// If we do not have any colors cached, simply set clean message
|
||||
if (chatColors == null || chatColors.isEmpty())
|
||||
{
|
||||
target.setValue(target.getRuneLiteFormatMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
target.setValue(recolorMessage(transparent, target.getRuneLiteFormatMessage(), target.getType()));
|
||||
}
|
||||
|
||||
private String recolorMessage(boolean transparent, String message, ChatMessageType messageType)
|
||||
{
|
||||
final Collection<ChatColor> chatColors = colorCache.get(messageType);
|
||||
final AtomicReference<String> resultMessage = new AtomicReference<>(message);
|
||||
|
||||
// Replace custom formatting with actual colors
|
||||
chatColors.stream()
|
||||
.filter(chatColor -> chatColor.isTransparent() == transparent)
|
||||
.forEach(chatColor ->
|
||||
resultMessage.getAndUpdate(oldMessage -> oldMessage.replaceAll(
|
||||
"<col" + chatColor.getType().name() + ">",
|
||||
ColorUtil.colorTag(chatColor.getColor()))));
|
||||
|
||||
return resultMessage.get();
|
||||
}
|
||||
|
||||
private void refreshAll()
|
||||
{
|
||||
client.getChatLineMap().values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(clb -> Arrays.stream(clb.getLines()))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(this::update);
|
||||
|
||||
client.refreshChat();
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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.chat;
|
||||
|
||||
import net.runelite.client.events.ChatboxInput;
|
||||
import net.runelite.client.events.PrivateMessageInput;
|
||||
|
||||
public interface ChatboxInputListener
|
||||
{
|
||||
boolean onChatboxInput(ChatboxInput chatboxInput);
|
||||
|
||||
boolean onPrivateMessageInput(PrivateMessageInput privateMessageInput);
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Kamiel
|
||||
* 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.chat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.ScriptID;
|
||||
import net.runelite.api.VarClientStr;
|
||||
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;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class CommandManager
|
||||
{
|
||||
private static final String RUNELITE_COMMAND = "runeliteCommand";
|
||||
private static final String CHATBOX_INPUT = "chatboxInput";
|
||||
private static final String PRIVMATE_MESSAGE = "privateMessage";
|
||||
|
||||
private final Client client;
|
||||
private final EventBus eventBus;
|
||||
private final ClientThread clientThread;
|
||||
private boolean sending;
|
||||
|
||||
private final List<ChatboxInputListener> chatboxInputListenerList = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
private CommandManager(Client client, EventBus eventBus, ClientThread clientThread)
|
||||
{
|
||||
this.client = client;
|
||||
this.eventBus = eventBus;
|
||||
this.clientThread = clientThread;
|
||||
}
|
||||
|
||||
public void register(ChatboxInputListener chatboxInputListener)
|
||||
{
|
||||
chatboxInputListenerList.add(chatboxInputListener);
|
||||
}
|
||||
|
||||
public void unregister(ChatboxInputListener chatboxInputListener)
|
||||
{
|
||||
chatboxInputListenerList.remove(chatboxInputListener);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onScriptCallbackEvent(ScriptCallbackEvent event)
|
||||
{
|
||||
if (sending)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.getEventName())
|
||||
{
|
||||
case RUNELITE_COMMAND:
|
||||
runCommand();
|
||||
break;
|
||||
case CHATBOX_INPUT:
|
||||
handleInput(event);
|
||||
break;
|
||||
case PRIVMATE_MESSAGE:
|
||||
handlePrivateMessage(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void runCommand()
|
||||
{
|
||||
String typedText = client.getVar(VarClientStr.CHATBOX_TYPED_TEXT).substring(2); // strip ::
|
||||
|
||||
log.debug("Command: {}", typedText);
|
||||
|
||||
String[] split = typedText.split(" ");
|
||||
|
||||
// Fixes ArrayIndexOutOfBounds when typing ":: "
|
||||
if (split.length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
String command = split[0];
|
||||
String[] args = Arrays.copyOfRange(split, 1, split.length);
|
||||
|
||||
CommandExecuted commandExecuted = new CommandExecuted(command, args);
|
||||
eventBus.post(commandExecuted);
|
||||
}
|
||||
|
||||
private void handleInput(ScriptCallbackEvent event)
|
||||
{
|
||||
final String[] stringStack = client.getStringStack();
|
||||
final int[] intStack = client.getIntStack();
|
||||
int stringStackCount = client.getStringStackSize();
|
||||
int intStackCount = client.getIntStackSize();
|
||||
|
||||
final String typedText = stringStack[stringStackCount - 1];
|
||||
final int chatType = intStack[intStackCount - 1];
|
||||
|
||||
ChatboxInput chatboxInput = new ChatboxInput(typedText, chatType)
|
||||
{
|
||||
private boolean resumed;
|
||||
|
||||
@Override
|
||||
public void resume()
|
||||
{
|
||||
if (resumed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
resumed = true;
|
||||
|
||||
clientThread.invoke(() -> sendChatboxInput(chatType, typedText));
|
||||
}
|
||||
};
|
||||
boolean stop = false;
|
||||
for (ChatboxInputListener chatboxInputListener : chatboxInputListenerList)
|
||||
{
|
||||
stop |= chatboxInputListener.onChatboxInput(chatboxInput);
|
||||
}
|
||||
|
||||
if (stop)
|
||||
{
|
||||
// input was blocked.
|
||||
stringStack[stringStackCount - 1] = ""; // prevent script from sending
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePrivateMessage(ScriptCallbackEvent event)
|
||||
{
|
||||
final String[] stringStack = client.getStringStack();
|
||||
final int[] intStack = client.getIntStack();
|
||||
int stringStackCount = client.getStringStackSize();
|
||||
int intStackCount = client.getIntStackSize();
|
||||
|
||||
final String target = stringStack[stringStackCount - 2];
|
||||
final String message = stringStack[stringStackCount - 1];
|
||||
|
||||
PrivateMessageInput privateMessageInput = new PrivateMessageInput(target, message)
|
||||
{
|
||||
private boolean resumed;
|
||||
|
||||
@Override
|
||||
public void resume()
|
||||
{
|
||||
if (resumed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
resumed = true;
|
||||
|
||||
clientThread.invoke(() -> sendPrivmsg(target, message));
|
||||
}
|
||||
};
|
||||
|
||||
boolean stop = false;
|
||||
for (ChatboxInputListener chatboxInputListener : chatboxInputListenerList)
|
||||
{
|
||||
stop |= chatboxInputListener.onPrivateMessageInput(privateMessageInput);
|
||||
}
|
||||
|
||||
if (stop)
|
||||
{
|
||||
intStack[intStackCount - 1] = 1;
|
||||
client.setStringStackSize(stringStackCount - 2); // remove both target and message
|
||||
}
|
||||
}
|
||||
|
||||
private void sendChatboxInput(int chatType, String input)
|
||||
{
|
||||
sending = true;
|
||||
try
|
||||
{
|
||||
client.runScript(ScriptID.CHATBOX_INPUT, chatType, input);
|
||||
}
|
||||
finally
|
||||
{
|
||||
sending = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendPrivmsg(String target, String message)
|
||||
{
|
||||
client.runScript(ScriptID.PRIVMSG, target, message);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.chat;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class QueuedMessage
|
||||
{
|
||||
@NonNull
|
||||
private final ChatMessageType type;
|
||||
private final String value;
|
||||
private String name;
|
||||
private String sender;
|
||||
private String runeLiteFormattedMessage;
|
||||
private int timestamp;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Ron Young <https://github.com/raiyni>
|
||||
* 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.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used with ConfigItem, determines if to use alpha slider on colors
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface Alpha
|
||||
{
|
||||
}
|
||||
@@ -1,512 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.awt.Color;
|
||||
import net.runelite.client.ui.JagexColors;
|
||||
|
||||
@ConfigGroup("textrecolor")
|
||||
public interface ChatColorConfig extends Config
|
||||
{
|
||||
@ConfigItem(
|
||||
position = 31,
|
||||
keyName = "opaquePublicChat",
|
||||
name = "Public chat",
|
||||
description = "Color of Public chat"
|
||||
)
|
||||
Color opaquePublicChat();
|
||||
|
||||
@ConfigItem(
|
||||
position = 32,
|
||||
keyName = "opaquePublicChatHighlight",
|
||||
name = "Public chat highlight",
|
||||
description = "Color of highlights in Public chat"
|
||||
)
|
||||
default Color opaquePublicChatHighlight()
|
||||
{
|
||||
return Color.decode("#000000");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 33,
|
||||
keyName = "opaquePrivateMessageSent",
|
||||
name = "Sent private messages",
|
||||
description = "Color of Private messages you've sent"
|
||||
)
|
||||
Color opaquePrivateMessageSent();
|
||||
|
||||
@ConfigItem(
|
||||
position = 34,
|
||||
keyName = "opaquePrivateMessageSentHighlight",
|
||||
name = "Sent private messages highlight",
|
||||
description = "Color of highlights in Private messages you've sent"
|
||||
)
|
||||
default Color opaquePrivateMessageSentHighlight()
|
||||
{
|
||||
return Color.decode("#002783");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 35,
|
||||
keyName = "opaquePrivateMessageReceived",
|
||||
name = "Received private messages",
|
||||
description = "Color of Private messages you've received"
|
||||
)
|
||||
Color opaquePrivateMessageReceived();
|
||||
|
||||
@ConfigItem(
|
||||
position = 36,
|
||||
keyName = "opaquePrivateMessageReceivedHighlight",
|
||||
name = "Received private messages highlight",
|
||||
description = "Color of highlights in Private messages you've received"
|
||||
)
|
||||
default Color opaquePrivateMessageReceivedHighlight()
|
||||
{
|
||||
return Color.decode("#002783");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 37,
|
||||
keyName = "opaqueClanChatInfo",
|
||||
name = "Clan chat info",
|
||||
description = "Clan Chat Information (eg. when joining a channel)"
|
||||
)
|
||||
default Color opaqueClanChatInfo()
|
||||
{
|
||||
return JagexColors.CHAT_GAME_EXAMINE_TEXT_OPAQUE_BACKGROUND;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 38,
|
||||
keyName = "opaqueClanChatInfoHighlight",
|
||||
name = "Clan chat info highlight",
|
||||
description = "Clan Chat Information highlight (used for the Raids plugin)"
|
||||
)
|
||||
default Color opaqueClanChatInfoHighlight()
|
||||
{
|
||||
return Color.RED;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 39,
|
||||
keyName = "opaqueClanChatMessage",
|
||||
name = "Clan chat message",
|
||||
description = "Color of Clan Chat Messages"
|
||||
)
|
||||
Color opaqueClanChatMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 40,
|
||||
keyName = "opaqueClanChatMessageHighlight",
|
||||
name = "Clan chat message highlight",
|
||||
description = "Color of highlights in Clan Chat Messages"
|
||||
)
|
||||
default Color opaqueClanChatMessageHighlight()
|
||||
{
|
||||
return Color.decode("#000000");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 41,
|
||||
keyName = "opaqueAutochatMessage",
|
||||
name = "Autochat",
|
||||
description = "Color of Autochat messages"
|
||||
)
|
||||
Color opaqueAutochatMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 42,
|
||||
keyName = "opaqueAutochatMessageHighlight",
|
||||
name = "Autochat highlight",
|
||||
description = "Color of highlights in Autochat messages"
|
||||
)
|
||||
Color opaqueAutochatMessageHighlight();
|
||||
|
||||
@ConfigItem(
|
||||
position = 43,
|
||||
keyName = "opaqueTradeChatMessage",
|
||||
name = "Trade chat",
|
||||
description = "Color of Trade Chat Messages"
|
||||
)
|
||||
Color opaqueTradeChatMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 44,
|
||||
keyName = "opaqueTradeChatMessageHighlight",
|
||||
name = "Trade chat highlight",
|
||||
description = "Color of highlights in Trade Chat Messages"
|
||||
)
|
||||
Color opaqueTradeChatMessageHighlight();
|
||||
|
||||
@ConfigItem(
|
||||
position = 45,
|
||||
keyName = "opaqueServerMessage",
|
||||
name = "Server message",
|
||||
description = "Color of Server Messages (eg. 'Welcome to Runescape')"
|
||||
)
|
||||
Color opaqueServerMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 46,
|
||||
keyName = "opaqueServerMessageHighlight",
|
||||
name = "Server message highlight",
|
||||
description = "Color of highlights in Server Messages"
|
||||
)
|
||||
Color opaqueServerMessageHighlight();
|
||||
|
||||
@ConfigItem(
|
||||
position = 47,
|
||||
keyName = "opaqueGameMessage",
|
||||
name = "Game message",
|
||||
description = "Color of Game Messages"
|
||||
)
|
||||
Color opaqueGameMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 48,
|
||||
keyName = "opaqueGameMessageHighlight",
|
||||
name = "Game message highlight",
|
||||
description = "Color of highlights in Game Messages"
|
||||
)
|
||||
default Color opaqueGameMessageHighlight()
|
||||
{
|
||||
return Color.decode("#EF1020");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 49,
|
||||
keyName = "opaqueExamine",
|
||||
name = "Examine",
|
||||
description = "Color of Examine Text"
|
||||
)
|
||||
Color opaqueExamine();
|
||||
|
||||
@ConfigItem(
|
||||
position = 50,
|
||||
keyName = "opaqueExamineHighlight",
|
||||
name = "Examine highlight",
|
||||
description = "Color of highlights in Examine Text"
|
||||
)
|
||||
default Color opaqueExamineHighlight()
|
||||
{
|
||||
return Color.decode("#0000FF");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 51,
|
||||
keyName = "opaqueFiltered",
|
||||
name = "Filtered",
|
||||
description = "Color of Filtered Text (messages that aren't shown when Game messages are filtered)"
|
||||
)
|
||||
Color opaqueFiltered();
|
||||
|
||||
@ConfigItem(
|
||||
position = 52,
|
||||
keyName = "opaqueFilteredHighlight",
|
||||
name = "Filtered highlight",
|
||||
description = "Color of highlights in Filtered Text"
|
||||
)
|
||||
Color opaqueFilteredHighlight();
|
||||
|
||||
@ConfigItem(
|
||||
position = 53,
|
||||
keyName = "opaqueUsername",
|
||||
name = "Usernames",
|
||||
description = "Color of Usernames"
|
||||
)
|
||||
Color opaqueUsername();
|
||||
|
||||
@ConfigItem(
|
||||
position = 54,
|
||||
keyName = "opaquePrivateUsernames",
|
||||
name = "Private chat usernames",
|
||||
description = "Color of Usernames in Private Chat"
|
||||
)
|
||||
Color opaquePrivateUsernames();
|
||||
|
||||
@ConfigItem(
|
||||
position = 55,
|
||||
keyName = "opaqueClanChannelName",
|
||||
name = "Clan channel name",
|
||||
description = "Color of Clan Channel Name"
|
||||
)
|
||||
Color opaqueClanChannelName();
|
||||
|
||||
@ConfigItem(
|
||||
position = 56,
|
||||
keyName = "opaqueClanUsernames",
|
||||
name = "Clan usernames",
|
||||
description = "Color of Usernames in Clan Chat"
|
||||
)
|
||||
Color opaqueClanUsernames();
|
||||
|
||||
@ConfigItem(
|
||||
position = 57,
|
||||
keyName = "opaquePublicFriendUsernames",
|
||||
name = "Public friend usernames",
|
||||
description = "Color of Friend Usernames in Public Chat"
|
||||
)
|
||||
Color opaquePublicFriendUsernames();
|
||||
|
||||
@ConfigItem(
|
||||
position = 61,
|
||||
keyName = "transparentPublicChat",
|
||||
name = "Public chat (transparent)",
|
||||
description = "Color of Public chat (transparent)"
|
||||
)
|
||||
Color transparentPublicChat();
|
||||
|
||||
@ConfigItem(
|
||||
position = 62,
|
||||
keyName = "transparentPublicChatHighlight",
|
||||
name = "Public chat highlight (transparent)",
|
||||
description = "Color of highlights in Public chat (transparent)"
|
||||
)
|
||||
default Color transparentPublicChatHighlight()
|
||||
{
|
||||
return Color.decode("#FFFFFF");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 63,
|
||||
keyName = "transparentPrivateMessageSent",
|
||||
name = "Sent private messages (transparent)",
|
||||
description = "Color of Private messages you've sent (transparent)"
|
||||
)
|
||||
Color transparentPrivateMessageSent();
|
||||
|
||||
@ConfigItem(
|
||||
position = 64,
|
||||
keyName = "transparentPrivateMessageSentHighlight",
|
||||
name = "Sent private messages highlight (transparent)",
|
||||
description = "Color of highlights in Private messages you've sent (transparent)"
|
||||
)
|
||||
default Color transparentPrivateMessageSentHighlight()
|
||||
{
|
||||
return Color.decode("#FFFFFF");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 65,
|
||||
keyName = "transparentPrivateMessageReceived",
|
||||
name = "Received private messages (transparent)",
|
||||
description = "Color of Private messages you've received (transparent)"
|
||||
)
|
||||
Color transparentPrivateMessageReceived();
|
||||
|
||||
@ConfigItem(
|
||||
position = 66,
|
||||
keyName = "transparentPrivateMessageReceivedHighlight",
|
||||
name = "Received private messages highlight (transparent)",
|
||||
description = "Color of highlights in Private messages you've received (transparent)"
|
||||
)
|
||||
default Color transparentPrivateMessageReceivedHighlight()
|
||||
{
|
||||
return Color.decode("#FFFFFF");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 67,
|
||||
keyName = "transparentClanChatInfo",
|
||||
name = "Clan chat info (transparent)",
|
||||
description = "Clan Chat Information (eg. when joining a channel) (transparent)"
|
||||
)
|
||||
default Color transparentClanChatInfo()
|
||||
{
|
||||
return JagexColors.CHAT_GAME_EXAMINE_TEXT_TRANSPARENT_BACKGROUND;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 68,
|
||||
keyName = "transparentClanChatInfoHighlight",
|
||||
name = "Clan chat info highlight (transparent)",
|
||||
description = "Clan Chat Information highlight (used for the Raids plugin) (transparent)"
|
||||
)
|
||||
default Color transparentClanChatInfoHighlight()
|
||||
{
|
||||
return Color.RED;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 69,
|
||||
keyName = "transparentClanChatMessage",
|
||||
name = "Clan chat message (transparent)",
|
||||
description = "Color of Clan Chat Messages (transparent)"
|
||||
)
|
||||
Color transparentClanChatMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 70,
|
||||
keyName = "transparentClanChatMessageHighlight",
|
||||
name = "Clan chat message highlight (transparent)",
|
||||
description = "Color of highlights in Clan Chat Messages (transparent)"
|
||||
)
|
||||
default Color transparentClanChatMessageHighlight()
|
||||
{
|
||||
return Color.decode("#FFFFFF");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 71,
|
||||
keyName = "transparentAutochatMessage",
|
||||
name = "Autochat (transparent)",
|
||||
description = "Color of Autochat messages (transparent)"
|
||||
)
|
||||
Color transparentAutochatMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 72,
|
||||
keyName = "transparentAutochatMessageHighlight",
|
||||
name = "Autochat highlight (transparent)",
|
||||
description = "Color of highlights in Autochat messages (transparent)"
|
||||
)
|
||||
Color transparentAutochatMessageHighlight();
|
||||
|
||||
@ConfigItem(
|
||||
position = 73,
|
||||
keyName = "transparentTradeChatMessage",
|
||||
name = "Trade chat (transparent)",
|
||||
description = "Color of Trade Chat Messages (transparent)"
|
||||
)
|
||||
Color transparentTradeChatMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 74,
|
||||
keyName = "transparentTradeChatMessageHighlight",
|
||||
name = "Trade chat highlight (transparent)",
|
||||
description = "Color of highlights in Trade Chat Messages (transparent)"
|
||||
)
|
||||
Color transparentTradeChatMessageHighlight();
|
||||
|
||||
@ConfigItem(
|
||||
position = 75,
|
||||
keyName = "transparentServerMessage",
|
||||
name = "Server message (transparent)",
|
||||
description = "Color of Server Messages (eg. 'Welcome to Runescape') (transparent)"
|
||||
)
|
||||
Color transparentServerMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 76,
|
||||
keyName = "transparentServerMessageHighlight",
|
||||
name = "Server message highlight (transparent)",
|
||||
description = "Color of highlights in Server Messages (transparent)"
|
||||
)
|
||||
Color transparentServerMessageHighlight();
|
||||
|
||||
@ConfigItem(
|
||||
position = 77,
|
||||
keyName = "transparentGameMessage",
|
||||
name = "Game message (transparent)",
|
||||
description = "Color of Game Messages (transparent)"
|
||||
)
|
||||
Color transparentGameMessage();
|
||||
|
||||
@ConfigItem(
|
||||
position = 78,
|
||||
keyName = "transparentGameMessageHighlight",
|
||||
name = "Game message highlight (transparent)",
|
||||
description = "Color of highlights in Game Messages (transparent)"
|
||||
)
|
||||
default Color transparentGameMessageHighlight()
|
||||
{
|
||||
return Color.decode("#EF1020");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 79,
|
||||
keyName = "transparentExamine",
|
||||
name = "Examine (transparent)",
|
||||
description = "Color of Examine Text (transparent)"
|
||||
)
|
||||
Color transparentExamine();
|
||||
|
||||
@ConfigItem(
|
||||
position = 80,
|
||||
keyName = "transparentExamineHighlight",
|
||||
name = "Examine highlight (transparent)",
|
||||
description = "Color of highlights in Examine Text (transparent)"
|
||||
)
|
||||
default Color transparentExamineHighlight()
|
||||
{
|
||||
return Color.decode("#0000FF");
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 81,
|
||||
keyName = "transparentFiltered",
|
||||
name = "Filtered (transparent)",
|
||||
description = "Color of Filtered Text (messages that aren't shown when Game messages are filtered) (transparent)"
|
||||
)
|
||||
Color transparentFiltered();
|
||||
|
||||
@ConfigItem(
|
||||
position = 82,
|
||||
keyName = "transparentFilteredHighlight",
|
||||
name = "Filtered highlight (transparent)",
|
||||
description = "Color of highlights in Filtered Text (transparent)"
|
||||
)
|
||||
Color transparentFilteredHighlight();
|
||||
|
||||
@ConfigItem(
|
||||
position = 83,
|
||||
keyName = "transparentUsername",
|
||||
name = "Usernames (transparent)",
|
||||
description = "Color of Usernames (transparent)"
|
||||
)
|
||||
Color transparentUsername();
|
||||
|
||||
@ConfigItem(
|
||||
position = 84,
|
||||
keyName = "transparentPrivateUsernames",
|
||||
name = "Private chat usernames (transparent)",
|
||||
description = "Color of Usernames in Private Chat (transparent)"
|
||||
)
|
||||
Color transparentPrivateUsernames();
|
||||
|
||||
@ConfigItem(
|
||||
position = 85,
|
||||
keyName = "transparentClanChannelName",
|
||||
name = "Clan channel name (transparent)",
|
||||
description = "Color of Clan Channel Name (transparent)"
|
||||
)
|
||||
Color transparentClanChannelName();
|
||||
|
||||
@ConfigItem(
|
||||
position = 86,
|
||||
keyName = "transparentClanUsernames",
|
||||
name = "Clan usernames (transparent)",
|
||||
description = "Color of Usernames in Clan Chat (transparent)"
|
||||
)
|
||||
Color transparentClanUsernames();
|
||||
|
||||
@ConfigItem(
|
||||
position = 87,
|
||||
keyName = "transparentPublicFriendUsernames",
|
||||
name = "Public friend usernames (transparent)",
|
||||
description = "Color of Friend Usernames in Public Chat (transparent)"
|
||||
)
|
||||
Color transparentPublicFriendUsernames();
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.config;
|
||||
|
||||
public interface Config
|
||||
{
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class ConfigDescriptor
|
||||
{
|
||||
private final ConfigGroup group;
|
||||
private final Collection<ConfigItemsGroup> itemGroups;
|
||||
|
||||
public ConfigDescriptor(ConfigGroup group, Collection<ConfigItemsGroup> itemGroups)
|
||||
{
|
||||
this.group = group;
|
||||
this.itemGroups = itemGroups;
|
||||
}
|
||||
|
||||
public ConfigGroup getGroup()
|
||||
{
|
||||
return group;
|
||||
}
|
||||
|
||||
public Collection<ConfigItemsGroup> getItemGroups()
|
||||
{
|
||||
return itemGroups;
|
||||
}
|
||||
|
||||
public Collection<ConfigItemDescriptor> getItems()
|
||||
{
|
||||
Collection<ConfigItemDescriptor> allItems = new ArrayList<>();
|
||||
for (ConfigItemsGroup g : itemGroups)
|
||||
{
|
||||
for (ConfigItemDescriptor item : g.getItems())
|
||||
{
|
||||
allItems.add(item);
|
||||
}
|
||||
}
|
||||
return allItems;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.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.TYPE)
|
||||
public @interface ConfigGroup
|
||||
{
|
||||
/**
|
||||
* The key name of the config group used for storing configuration within the config group.
|
||||
* This should typically be a lowercased version of your plugin name, with all spaces removed.
|
||||
* <p>
|
||||
* For example, the {@code Grand Exchange} plugin uses the key name {@code grandexchange}.
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.config;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
class ConfigInvocationHandler implements InvocationHandler
|
||||
{
|
||||
private final ConfigManager manager;
|
||||
|
||||
public ConfigInvocationHandler(ConfigManager manager)
|
||||
{
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
|
||||
{
|
||||
Class<?> iface = proxy.getClass().getInterfaces()[0];
|
||||
|
||||
ConfigGroup group = iface.getAnnotation(ConfigGroup.class);
|
||||
ConfigItem item = method.getAnnotation(ConfigItem.class);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
log.warn("Configuration proxy class {} has no @ConfigGroup!", proxy.getClass());
|
||||
return null;
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
log.warn("Configuration method {} has no @ConfigItem!", method);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (args == null)
|
||||
{
|
||||
// Getting configuration item
|
||||
String value = manager.getConfiguration(group.value(), item.keyName());
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
if (method.isDefault())
|
||||
{
|
||||
return callDefaultMethod(proxy, method, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Convert value to return type
|
||||
Class<?> returnType = method.getReturnType();
|
||||
|
||||
try
|
||||
{
|
||||
return ConfigManager.stringToObject(value, returnType);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
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 null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Setting a configuration value
|
||||
|
||||
if (args.length != 1)
|
||||
{
|
||||
throw new RuntimeException("Invalid number of arguents to configuration method");
|
||||
}
|
||||
|
||||
Object newValue = args[0];
|
||||
|
||||
Class<?> type = method.getParameterTypes()[0];
|
||||
Object oldValue = manager.getConfiguration(group.value(), item.keyName(), type);
|
||||
|
||||
if (Objects.equals(oldValue, newValue))
|
||||
{
|
||||
// nothing to do
|
||||
return null;
|
||||
}
|
||||
|
||||
if (method.isDefault())
|
||||
{
|
||||
Object defaultValue = callDefaultMethod(proxy, method, args);
|
||||
|
||||
if (Objects.equals(newValue, defaultValue))
|
||||
{
|
||||
// Just unset if it goes back to the default
|
||||
manager.unsetConfiguration(group.value(), item.keyName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (newValue == null)
|
||||
{
|
||||
manager.unsetConfiguration(group.value(), item.keyName());
|
||||
}
|
||||
else
|
||||
{
|
||||
String newValueStr = ConfigManager.objectToString(newValue);
|
||||
manager.setConfiguration(group.value(), item.keyName(), newValueStr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Object callDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable
|
||||
{
|
||||
// Call the default method implementation - https://rmannibucau.wordpress.com/2014/03/27/java-8-default-interface-methods-and-jdk-dynamic-proxies/
|
||||
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
|
||||
constructor.setAccessible(true);
|
||||
|
||||
Class<?> declaringClass = method.getDeclaringClass();
|
||||
return constructor.newInstance(declaringClass, MethodHandles.Lookup.PUBLIC | MethodHandles.Lookup.PRIVATE)
|
||||
.unreflectSpecial(method, declaringClass)
|
||||
.bindTo(proxy)
|
||||
.invokeWithArguments(args);
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.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 ConfigItem
|
||||
{
|
||||
int position() default -1;
|
||||
|
||||
String keyName();
|
||||
|
||||
String name();
|
||||
|
||||
String description();
|
||||
|
||||
boolean hidden() default false;
|
||||
|
||||
String warning() default "";
|
||||
|
||||
boolean secret() default false;
|
||||
|
||||
String group() default "";
|
||||
|
||||
String unhide() default "";
|
||||
|
||||
String hide() default "";
|
||||
|
||||
String parent() default "";
|
||||
|
||||
String enabledBy() default "";
|
||||
|
||||
String disabledBy() default "";
|
||||
|
||||
boolean parse() default false;
|
||||
|
||||
Class<?> clazz() default void.class;
|
||||
String method() default "";
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.config;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class ConfigItemDescriptor
|
||||
{
|
||||
private final ConfigItem item;
|
||||
private final Class<?> type;
|
||||
private final Range range;
|
||||
private final Alpha alpha;
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Craftiii4 <craftiii4@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.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
|
||||
public class ConfigItemsGroup
|
||||
{
|
||||
|
||||
@Getter(AccessLevel.PUBLIC)
|
||||
private final String group;
|
||||
|
||||
@Getter(AccessLevel.PUBLIC)
|
||||
private Collection<ConfigItemDescriptor> items;
|
||||
|
||||
public ConfigItemsGroup(String group)
|
||||
{
|
||||
this.group = group;
|
||||
this.items = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addItem(ConfigItemDescriptor item)
|
||||
{
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,628 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.config;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.ConfigChanged;
|
||||
import net.runelite.client.RuneLite;
|
||||
import static net.runelite.client.RuneLite.PROFILES_DIR;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.util.ColorUtil;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class ConfigManager
|
||||
{
|
||||
private static final String SETTINGS_FILE_NAME = "runeliteplus.properties";
|
||||
private static final String STANDARD_SETTINGS_FILE_NAME = "settings.properties";
|
||||
private static final File SETTINGS_FILE = new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME);
|
||||
private static final File STANDARD_SETTINGS_FILE = new File(RuneLite.RUNELITE_DIR, STANDARD_SETTINGS_FILE_NAME);
|
||||
|
||||
@Inject
|
||||
EventBus eventBus;
|
||||
|
||||
private final ScheduledExecutorService executor;
|
||||
private final ConfigInvocationHandler handler = new ConfigInvocationHandler(this);
|
||||
private final Properties properties = new Properties();
|
||||
private final Map<String, String> pendingChanges = new HashMap<>();
|
||||
|
||||
@Inject
|
||||
public ConfigManager(ScheduledExecutorService scheduledExecutorService)
|
||||
{
|
||||
this.executor = scheduledExecutorService;
|
||||
|
||||
executor.scheduleWithFixedDelay(this::sendConfig, 30, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public final void switchSession()
|
||||
{
|
||||
// Ensure existing config is saved
|
||||
load();
|
||||
}
|
||||
|
||||
public void load()
|
||||
{
|
||||
loadFromFile();
|
||||
}
|
||||
|
||||
private synchronized void syncPropertiesFromFile(File propertiesFile)
|
||||
{
|
||||
final Properties properties = new Properties();
|
||||
try (FileInputStream in = new FileInputStream(propertiesFile))
|
||||
{
|
||||
properties.load(new InputStreamReader(in, Charset.forName("UTF-8")));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.debug("Malformed properties, skipping update");
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<String, String> copy = (Map) ImmutableMap.copyOf(this.properties);
|
||||
copy.forEach((groupAndKey, value) ->
|
||||
{
|
||||
if (!properties.containsKey(groupAndKey))
|
||||
{
|
||||
final String[] split = groupAndKey.split("\\.", 2);
|
||||
if (split.length != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final String groupName = split[0];
|
||||
final String key = split[1];
|
||||
unsetConfiguration(groupName, key);
|
||||
}
|
||||
});
|
||||
|
||||
properties.forEach((objGroupAndKey, objValue) ->
|
||||
{
|
||||
final String groupAndKey = String.valueOf(objGroupAndKey);
|
||||
final String[] split = groupAndKey.split("\\.", 2);
|
||||
if (split.length != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final String groupName = split[0];
|
||||
final String key = split[1];
|
||||
final String value = String.valueOf(objValue);
|
||||
setConfiguration(groupName, key, value);
|
||||
});
|
||||
}
|
||||
|
||||
public void importLocal()
|
||||
{
|
||||
log.info("Nothing changed, don't worry!");
|
||||
}
|
||||
|
||||
private synchronized void loadFromFile()
|
||||
{
|
||||
properties.clear();
|
||||
|
||||
try (FileInputStream in = new FileInputStream(SETTINGS_FILE))
|
||||
{
|
||||
properties.load(new InputStreamReader(in, Charset.forName("UTF-8")));
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
log.debug("Unable to load settings - no such file, syncing from standard settings");
|
||||
syncLastModified();
|
||||
}
|
||||
catch (IllegalArgumentException | IOException ex)
|
||||
{
|
||||
log.warn("Unable to load settings", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Map<String, String> copy = (Map) ImmutableMap.copyOf(properties);
|
||||
copy.forEach((groupAndKey, value) ->
|
||||
{
|
||||
final String[] split = groupAndKey.split("\\.", 2);
|
||||
if (split.length != 2)
|
||||
{
|
||||
log.debug("Properties key malformed!: {}", groupAndKey);
|
||||
properties.remove(groupAndKey);
|
||||
return;
|
||||
}
|
||||
|
||||
final String groupName = split[0];
|
||||
final String key = split[1];
|
||||
|
||||
ConfigChanged configChanged = new ConfigChanged();
|
||||
configChanged.setGroup(groupName);
|
||||
configChanged.setKey(key);
|
||||
configChanged.setOldValue(null);
|
||||
configChanged.setNewValue(value);
|
||||
eventBus.post(configChanged);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("Error posting config events", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveToFile() throws IOException
|
||||
{
|
||||
ConfigManager.SETTINGS_FILE.getParentFile().mkdirs();
|
||||
|
||||
try (FileOutputStream out = new FileOutputStream(ConfigManager.SETTINGS_FILE))
|
||||
{
|
||||
final FileLock lock = out.getChannel().lock();
|
||||
|
||||
try
|
||||
{
|
||||
properties.store(new OutputStreamWriter(out, Charset.forName("UTF-8")), "RuneLite configuration");
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T getConfig(Class<T> clazz)
|
||||
{
|
||||
if (!Modifier.isPublic(clazz.getModifiers()))
|
||||
{
|
||||
throw new RuntimeException("Non-public configuration classes can't have default methods invoked");
|
||||
}
|
||||
|
||||
T t = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]
|
||||
{
|
||||
clazz
|
||||
}, handler);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
public List<String> getConfigurationKeys(String prefix)
|
||||
{
|
||||
return properties.keySet().stream().filter(v -> ((String) v).startsWith(prefix)).map(String.class::cast).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String getConfiguration(String groupName, String key)
|
||||
{
|
||||
return properties.getProperty(groupName + "." + key);
|
||||
}
|
||||
|
||||
public <T> T getConfiguration(String groupName, String key, Class<T> clazz)
|
||||
{
|
||||
String value = getConfiguration(groupName, key);
|
||||
if (!Strings.isNullOrEmpty(value))
|
||||
{
|
||||
try
|
||||
{
|
||||
return (T) stringToObject(value, clazz);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.warn("Unable to unmarshal {}.{} ", groupName, key, e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setConfiguration(String groupName, String key, String value)
|
||||
{
|
||||
String oldValue = (String) properties.setProperty(groupName + "." + key, value);
|
||||
|
||||
if (Objects.equals(oldValue, value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
|
||||
|
||||
synchronized (pendingChanges)
|
||||
{
|
||||
pendingChanges.put(groupName + "." + key, value);
|
||||
}
|
||||
|
||||
ConfigChanged configChanged = new ConfigChanged();
|
||||
configChanged.setGroup(groupName);
|
||||
configChanged.setKey(key);
|
||||
configChanged.setOldValue(oldValue);
|
||||
configChanged.setNewValue(value);
|
||||
|
||||
eventBus.post(configChanged);
|
||||
}
|
||||
|
||||
public void setConfiguration(String groupName, String key, Object value)
|
||||
{
|
||||
setConfiguration(groupName, key, objectToString(value));
|
||||
}
|
||||
|
||||
public void unsetConfiguration(String groupName, String key)
|
||||
{
|
||||
String oldValue = (String) properties.remove(groupName + "." + key);
|
||||
|
||||
if (oldValue == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Unsetting configuration value for {}.{}", groupName, key);
|
||||
|
||||
synchronized (pendingChanges)
|
||||
{
|
||||
pendingChanges.put(groupName + "." + key, null);
|
||||
}
|
||||
|
||||
ConfigChanged configChanged = new ConfigChanged();
|
||||
configChanged.setGroup(groupName);
|
||||
configChanged.setKey(key);
|
||||
configChanged.setOldValue(oldValue);
|
||||
|
||||
eventBus.post(configChanged);
|
||||
}
|
||||
|
||||
public ConfigDescriptor getConfigDescriptor(Object configurationProxy)
|
||||
{
|
||||
Class<?> inter = configurationProxy.getClass().getInterfaces()[0];
|
||||
ConfigGroup group = inter.getAnnotation(ConfigGroup.class);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Not a config group");
|
||||
}
|
||||
|
||||
final List<ConfigItemDescriptor> items = Arrays.stream(inter.getMethods())
|
||||
.filter(m -> m.getParameterCount() == 0)
|
||||
.map(m -> new ConfigItemDescriptor(
|
||||
m.getDeclaredAnnotation(ConfigItem.class),
|
||||
m.getReturnType(),
|
||||
m.getDeclaredAnnotation(Range.class),
|
||||
m.getDeclaredAnnotation(Alpha.class)
|
||||
))
|
||||
.sorted((a, b) -> ComparisonChain.start()
|
||||
.compare(a.getItem().position(), b.getItem().position())
|
||||
.compare(a.getItem().name(), b.getItem().name())
|
||||
.result())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Collection<ConfigItemsGroup> itemGroups = new ArrayList<>();
|
||||
|
||||
for (ConfigItemDescriptor item : items)
|
||||
{
|
||||
String groupName = item.getItem().group();
|
||||
boolean found = false;
|
||||
for (ConfigItemsGroup g : itemGroups)
|
||||
{
|
||||
if (g.getGroup().equals(groupName))
|
||||
{
|
||||
g.addItem(item);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
ConfigItemsGroup newGroup = new ConfigItemsGroup(groupName);
|
||||
newGroup.addItem(item);
|
||||
itemGroups.add(newGroup);
|
||||
}
|
||||
}
|
||||
|
||||
itemGroups = itemGroups.stream().sorted((a, b) -> ComparisonChain.start()
|
||||
.compare(a.getGroup(), b.getGroup())
|
||||
.result())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new ConfigDescriptor(group, itemGroups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the configuration from the default settings
|
||||
*
|
||||
* @param proxy
|
||||
*/
|
||||
public void setDefaultConfiguration(Object proxy, boolean override)
|
||||
{
|
||||
Class<?> clazz = proxy.getClass().getInterfaces()[0];
|
||||
ConfigGroup group = clazz.getAnnotation(ConfigGroup.class);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (Method method : clazz.getDeclaredMethods())
|
||||
{
|
||||
ConfigItem item = method.getAnnotation(ConfigItem.class);
|
||||
|
||||
// only apply default configuration for methods which read configuration (0 args)
|
||||
if (item == null || method.getParameterCount() != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!method.isDefault())
|
||||
{
|
||||
if (override)
|
||||
{
|
||||
String current = getConfiguration(group.value(), item.keyName());
|
||||
// only unset if already set
|
||||
if (current != null)
|
||||
{
|
||||
unsetConfiguration(group.value(), item.keyName());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!override)
|
||||
{
|
||||
String current = getConfiguration(group.value(), item.keyName());
|
||||
if (current != null)
|
||||
{
|
||||
continue; // something else is already set
|
||||
}
|
||||
}
|
||||
|
||||
Object defaultValue;
|
||||
try
|
||||
{
|
||||
defaultValue = ConfigInvocationHandler.callDefaultMethod(proxy, method, null);
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
log.warn(null, ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
String current = getConfiguration(group.value(), item.keyName());
|
||||
String valueString = objectToString(defaultValue);
|
||||
if (Objects.equals(current, valueString))
|
||||
{
|
||||
continue; // already set to the default value
|
||||
}
|
||||
|
||||
log.debug("Setting default configuration value for {}.{} to {}", group.value(), item.keyName(), defaultValue);
|
||||
|
||||
setConfiguration(group.value(), item.keyName(), valueString);
|
||||
}
|
||||
}
|
||||
|
||||
static Object stringToObject(String str, Class<?> type)
|
||||
{
|
||||
if (type == boolean.class || type == Boolean.class)
|
||||
{
|
||||
return Boolean.parseBoolean(str);
|
||||
}
|
||||
if (type == int.class)
|
||||
{
|
||||
return Integer.parseInt(str);
|
||||
}
|
||||
if (type == Color.class)
|
||||
{
|
||||
return ColorUtil.fromString(str);
|
||||
}
|
||||
if (type == Dimension.class)
|
||||
{
|
||||
String[] splitStr = str.split("x");
|
||||
int width = Integer.parseInt(splitStr[0]);
|
||||
int height = Integer.parseInt(splitStr[1]);
|
||||
return new Dimension(width, height);
|
||||
}
|
||||
if (type == Point.class)
|
||||
{
|
||||
String[] splitStr = str.split(":");
|
||||
int width = Integer.parseInt(splitStr[0]);
|
||||
int height = Integer.parseInt(splitStr[1]);
|
||||
return new Point(width, height);
|
||||
}
|
||||
if (type == Rectangle.class)
|
||||
{
|
||||
String[] splitStr = str.split(":");
|
||||
int x = Integer.parseInt(splitStr[0]);
|
||||
int y = Integer.parseInt(splitStr[1]);
|
||||
int width = Integer.parseInt(splitStr[2]);
|
||||
int height = Integer.parseInt(splitStr[3]);
|
||||
return new Rectangle(x, y, width, height);
|
||||
}
|
||||
if (type.isEnum())
|
||||
{
|
||||
return Enum.valueOf((Class<? extends Enum>) type, str);
|
||||
}
|
||||
if (type == Instant.class)
|
||||
{
|
||||
return Instant.parse(str);
|
||||
}
|
||||
if (type == Keybind.class || type == ModifierlessKeybind.class)
|
||||
{
|
||||
String[] splitStr = str.split(":");
|
||||
int code = Integer.parseInt(splitStr[0]);
|
||||
int mods = Integer.parseInt(splitStr[1]);
|
||||
if (type == ModifierlessKeybind.class)
|
||||
{
|
||||
return new ModifierlessKeybind(code, mods);
|
||||
}
|
||||
return new Keybind(code, mods);
|
||||
}
|
||||
if (type == WorldPoint.class)
|
||||
{
|
||||
String[] splitStr = str.split(":");
|
||||
int x = Integer.parseInt(splitStr[0]);
|
||||
int y = Integer.parseInt(splitStr[1]);
|
||||
int plane = Integer.parseInt(splitStr[2]);
|
||||
return new WorldPoint(x, y, plane);
|
||||
}
|
||||
if (type == Duration.class)
|
||||
{
|
||||
return Duration.ofMillis(Long.parseLong(str));
|
||||
}
|
||||
if (type == Map.class)
|
||||
{
|
||||
Map<String, String> output = new HashMap<>();
|
||||
str = str.substring(1, str.length() - 1);
|
||||
String[] splitStr = str.split(", ");
|
||||
for (String s : splitStr)
|
||||
{
|
||||
String[] keyVal = s.split("=");
|
||||
if (keyVal.length > 1)
|
||||
{
|
||||
output.put(keyVal[0], keyVal[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static String objectToString(Object object)
|
||||
{
|
||||
if (object instanceof Color)
|
||||
{
|
||||
return String.valueOf(((Color) object).getRGB());
|
||||
}
|
||||
if (object instanceof Enum)
|
||||
{
|
||||
return ((Enum) object).name();
|
||||
}
|
||||
if (object instanceof Dimension)
|
||||
{
|
||||
Dimension d = (Dimension) object;
|
||||
return d.width + "x" + d.height;
|
||||
}
|
||||
if (object instanceof Point)
|
||||
{
|
||||
Point p = (Point) object;
|
||||
return p.x + ":" + p.y;
|
||||
}
|
||||
if (object instanceof Rectangle)
|
||||
{
|
||||
Rectangle r = (Rectangle) object;
|
||||
return r.x + ":" + r.y + ":" + r.width + ":" + r.height;
|
||||
}
|
||||
if (object instanceof Instant)
|
||||
{
|
||||
return ((Instant) object).toString();
|
||||
}
|
||||
if (object instanceof Keybind)
|
||||
{
|
||||
Keybind k = (Keybind) object;
|
||||
return k.getKeyCode() + ":" + k.getModifiers();
|
||||
}
|
||||
if (object instanceof WorldPoint)
|
||||
{
|
||||
WorldPoint wp = (WorldPoint) object;
|
||||
return wp.getX() + ":" + wp.getY() + ":" + wp.getPlane();
|
||||
}
|
||||
if (object instanceof Duration)
|
||||
{
|
||||
return Long.toString(((Duration) object).toMillis());
|
||||
}
|
||||
return object.toString();
|
||||
}
|
||||
|
||||
public void sendConfig()
|
||||
{
|
||||
boolean changed;
|
||||
synchronized (pendingChanges)
|
||||
{
|
||||
changed = !pendingChanges.isEmpty();
|
||||
pendingChanges.clear();
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
try
|
||||
{
|
||||
saveToFile();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("unable to save configuration file", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void syncLastModified()
|
||||
{
|
||||
File newestFile;
|
||||
|
||||
newestFile = STANDARD_SETTINGS_FILE;
|
||||
|
||||
for (File profileDir : PROFILES_DIR.listFiles())
|
||||
{
|
||||
if (!profileDir.isDirectory())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (File settings : profileDir.listFiles())
|
||||
{
|
||||
if (!settings.getName().equals(STANDARD_SETTINGS_FILE_NAME) ||
|
||||
settings.lastModified() < newestFile.lastModified())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newestFile = settings;
|
||||
}
|
||||
}
|
||||
|
||||
syncPropertiesFromFile(newestFile);
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Craftiii4 <craftiii4@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.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
|
||||
public class ConfigPanelItem
|
||||
{
|
||||
|
||||
@Getter(AccessLevel.PUBLIC)
|
||||
private ConfigPanelItem parent;
|
||||
|
||||
@Getter(AccessLevel.PUBLIC)
|
||||
private List<ConfigPanelItem> children;
|
||||
|
||||
@Getter(AccessLevel.PUBLIC)
|
||||
private ConfigItemDescriptor item;
|
||||
|
||||
public ConfigPanelItem(ConfigPanelItem parent, ConfigItemDescriptor item)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.children = new ArrayList<>();
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
public List<ConfigPanelItem> getItemsAsList()
|
||||
{
|
||||
List<ConfigPanelItem> items = new ArrayList<>();
|
||||
|
||||
items.add(this);
|
||||
|
||||
for (ConfigPanelItem child : children)
|
||||
{
|
||||
items.addAll(child.getItemsAsList());
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
public int getDepth()
|
||||
{
|
||||
return (parent == null ? 0 : parent.getDepth() + 1);
|
||||
}
|
||||
|
||||
public boolean addChildIfMatchParent(ConfigItemDescriptor cid)
|
||||
{
|
||||
|
||||
if (item != null && item.getItem().keyName().equals(cid.getItem().parent()))
|
||||
{
|
||||
children.add(new ConfigPanelItem(this, cid));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ConfigPanelItem child : children)
|
||||
{
|
||||
if (child.addChildIfMatchParent(cid))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Woox <https://github.com/wooxsolo>
|
||||
* 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.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum ExpandResizeType
|
||||
{
|
||||
KEEP_WINDOW_SIZE("Keep window size"),
|
||||
KEEP_GAME_SIZE("Keep game size");
|
||||
|
||||
private final String type;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tanner <https://github.com/Reasel>
|
||||
* 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.Font;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum FontType
|
||||
{
|
||||
REGULAR("Regular", FontManager.getRunescapeFont()),
|
||||
BOLD("Bold", FontManager.getRunescapeBoldFont()),
|
||||
SMALL("Small", FontManager.getRunescapeSmallFont());
|
||||
|
||||
private final String name;
|
||||
private final Font font;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* A combination of zero or more modifier keys (Ctrl, alt, shift, meta)
|
||||
* and an optional non-modifier key
|
||||
*/
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
public class Keybind
|
||||
{
|
||||
private static final BiMap<Integer, Integer> MODIFIER_TO_KEY_CODE = new ImmutableBiMap.Builder<Integer, Integer>()
|
||||
.put(InputEvent.CTRL_DOWN_MASK, KeyEvent.VK_CONTROL)
|
||||
.put(InputEvent.ALT_DOWN_MASK, KeyEvent.VK_ALT)
|
||||
.put(InputEvent.SHIFT_DOWN_MASK, KeyEvent.VK_SHIFT)
|
||||
.put(InputEvent.META_DOWN_MASK, KeyEvent.VK_META)
|
||||
.build();
|
||||
|
||||
// Bitmask of all supported modifers
|
||||
private static final int KEYBOARD_MODIFIER_MASK = MODIFIER_TO_KEY_CODE.keySet().stream()
|
||||
.reduce((a, b) -> a | b).get();
|
||||
|
||||
public static final Keybind NOT_SET = new Keybind(KeyEvent.VK_UNDEFINED, 0);
|
||||
|
||||
public static final Keybind CTRL = new Keybind(KeyEvent.VK_UNDEFINED, InputEvent.CTRL_DOWN_MASK);
|
||||
public static final Keybind ALT = new Keybind(KeyEvent.VK_UNDEFINED, InputEvent.ALT_DOWN_MASK);
|
||||
public static final Keybind SHIFT = new Keybind(KeyEvent.VK_UNDEFINED, InputEvent.SHIFT_DOWN_MASK);
|
||||
|
||||
private final int keyCode;
|
||||
private final int modifiers;
|
||||
|
||||
protected Keybind(int keyCode, int modifiers, boolean ignoreModifiers)
|
||||
{
|
||||
modifiers &= KEYBOARD_MODIFIER_MASK;
|
||||
|
||||
// If the keybind is just modifiers we don't want the keyCode to contain the modifier too,
|
||||
// becasue this breaks if you do the keycode backwards
|
||||
Integer mf = getModifierForKeyCode(keyCode);
|
||||
if (mf != null)
|
||||
{
|
||||
assert (modifiers & mf) != 0;
|
||||
keyCode = KeyEvent.VK_UNDEFINED;
|
||||
}
|
||||
|
||||
if (ignoreModifiers && keyCode != KeyEvent.VK_UNDEFINED)
|
||||
{
|
||||
modifiers = 0;
|
||||
}
|
||||
|
||||
this.keyCode = keyCode;
|
||||
this.modifiers = modifiers;
|
||||
}
|
||||
|
||||
public Keybind(int keyCode, int modifiers)
|
||||
{
|
||||
this(keyCode, modifiers, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a keybind with that matches the passed KeyEvent
|
||||
*/
|
||||
public Keybind(KeyEvent e)
|
||||
{
|
||||
this(e.getExtendedKeyCode(), e.getModifiersEx());
|
||||
|
||||
assert matches(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the KeyEvent is from a KeyPressed event this returns if the
|
||||
* Event is this hotkey being pressed. If the KeyEvent is a
|
||||
* KeyReleased event this returns if the event is this hotkey being
|
||||
* released
|
||||
*/
|
||||
public boolean matches(KeyEvent e)
|
||||
{
|
||||
return matches(e, false);
|
||||
}
|
||||
|
||||
protected boolean matches(KeyEvent e, boolean ignoreModifiers)
|
||||
{
|
||||
if (NOT_SET.equals(this))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int keyCode = e.getExtendedKeyCode();
|
||||
int modifiers = e.getModifiersEx() & KEYBOARD_MODIFIER_MASK;
|
||||
|
||||
Integer mf = getModifierForKeyCode(keyCode);
|
||||
if (mf != null)
|
||||
{
|
||||
modifiers |= mf;
|
||||
keyCode = KeyEvent.VK_UNDEFINED;
|
||||
}
|
||||
|
||||
if (e.getID() == KeyEvent.KEY_RELEASED && keyCode != KeyEvent.VK_UNDEFINED)
|
||||
{
|
||||
return this.keyCode == keyCode;
|
||||
}
|
||||
|
||||
if (ignoreModifiers && keyCode != KeyEvent.VK_UNDEFINED)
|
||||
{
|
||||
return this.keyCode == keyCode;
|
||||
}
|
||||
|
||||
return this.keyCode == keyCode && this.modifiers == modifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (keyCode == KeyEvent.VK_UNDEFINED && modifiers == 0)
|
||||
{
|
||||
return "Not set";
|
||||
}
|
||||
|
||||
String key;
|
||||
if (keyCode == KeyEvent.VK_UNDEFINED)
|
||||
{
|
||||
key = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
key = KeyEvent.getKeyText(keyCode);
|
||||
}
|
||||
|
||||
String mod = "";
|
||||
if (modifiers != 0)
|
||||
{
|
||||
mod = getModifiersExText(modifiers);
|
||||
}
|
||||
|
||||
if (mod.isEmpty() && key.isEmpty())
|
||||
{
|
||||
return "Not set";
|
||||
}
|
||||
if (!mod.isEmpty() && !key.isEmpty())
|
||||
{
|
||||
return mod + "+" + key;
|
||||
}
|
||||
if (mod.isEmpty())
|
||||
{
|
||||
return key;
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
public static String getModifiersExText(int modifiers)
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
if ((modifiers & InputEvent.META_DOWN_MASK) != 0)
|
||||
{
|
||||
buf.append("Meta+");
|
||||
}
|
||||
if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0)
|
||||
{
|
||||
buf.append("Ctrl+");
|
||||
}
|
||||
if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0)
|
||||
{
|
||||
buf.append("Alt+");
|
||||
}
|
||||
if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0)
|
||||
{
|
||||
buf.append("Shift+");
|
||||
}
|
||||
|
||||
if (buf.length() > 0)
|
||||
{
|
||||
buf.setLength(buf.length() - 1); // remove trailing '+'
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Integer getModifierForKeyCode(int keyCode)
|
||||
{
|
||||
return MODIFIER_TO_KEY_CODE.inverse().get(keyCode);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class ModifierlessKeybind extends Keybind
|
||||
{
|
||||
public ModifierlessKeybind(int keyCode, int modifiers)
|
||||
{
|
||||
super(keyCode, modifiers, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a keybind with that matches the passed KeyEvent
|
||||
*/
|
||||
public ModifierlessKeybind(KeyEvent e)
|
||||
{
|
||||
this(e.getExtendedKeyCode(), e.getModifiersEx());
|
||||
|
||||
assert matches(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the KeyEvent is from a KeyPressed event this returns if the
|
||||
* Event is this hotkey being pressed. If the KeyEvent is a
|
||||
* KeyReleased event this returns if the event is this hotkey being
|
||||
* released
|
||||
*/
|
||||
public boolean matches(KeyEvent e)
|
||||
{
|
||||
return matches(e, true);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used with ConfigItem, describes valid int range for a config item.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface Range
|
||||
{
|
||||
int min() default 0;
|
||||
|
||||
int max() default Integer.MAX_VALUE;
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Tyler <https://github.com/tylerthardy>
|
||||
* 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.Dimension;
|
||||
import net.runelite.api.Constants;
|
||||
|
||||
@ConfigGroup("runelite")
|
||||
public interface RuneLiteConfig extends Config
|
||||
{
|
||||
@ConfigItem(
|
||||
keyName = "gameSize",
|
||||
name = "Game size",
|
||||
description = "The game will resize to this resolution upon starting the client",
|
||||
position = 10
|
||||
)
|
||||
default Dimension gameSize()
|
||||
{
|
||||
return Constants.GAME_FIXED_SIZE;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "automaticResizeType",
|
||||
name = "Resize type",
|
||||
description = "Choose how the window should resize when opening and closing panels",
|
||||
position = 11
|
||||
)
|
||||
default ExpandResizeType automaticResizeType()
|
||||
{
|
||||
return ExpandResizeType.KEEP_GAME_SIZE;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "lockWindowSize",
|
||||
name = "Lock window size",
|
||||
description = "Determines if the window resizing is allowed or not",
|
||||
position = 12
|
||||
)
|
||||
default boolean lockWindowSize()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "enablePlugins",
|
||||
name = "Enable loading of external plugins",
|
||||
description = "Enable loading of external plugins",
|
||||
position = 10
|
||||
)
|
||||
default boolean enablePlugins()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "containInScreen",
|
||||
name = "Contain in screen",
|
||||
description = "Makes the client stay contained in the screen when attempted to move out of it.<br>Note: Only works if custom chrome is enabled.",
|
||||
position = 13
|
||||
)
|
||||
default boolean containInScreen()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "rememberScreenBounds",
|
||||
name = "Remember client position",
|
||||
description = "Save the position and size of the client after exiting",
|
||||
position = 14
|
||||
)
|
||||
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
|
||||
)
|
||||
default boolean enableCustomChrome()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "gameAlwaysOnTop",
|
||||
name = "Enable client always on top",
|
||||
description = "The game will always be on the top of the screen",
|
||||
position = 16
|
||||
)
|
||||
default boolean gameAlwaysOnTop()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "warningOnExit",
|
||||
name = "Display warning on exit",
|
||||
description = "Toggles a warning popup when trying to exit the client",
|
||||
position = 17
|
||||
)
|
||||
default WarningOnExit warningOnExit()
|
||||
{
|
||||
return WarningOnExit.LOGGED_IN;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "usernameInTitle",
|
||||
name = "Show display name in title",
|
||||
description = "Toggles displaying of local player's display name in client title",
|
||||
position = 18
|
||||
)
|
||||
default boolean usernameInTitle()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "notificationTray",
|
||||
name = "Enable tray notifications",
|
||||
description = "Enables tray notifications",
|
||||
position = 20
|
||||
)
|
||||
default boolean enableTrayNotifications()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "notificationRequestFocus",
|
||||
name = "Request focus on notification",
|
||||
description = "Toggles window focus request",
|
||||
position = 21
|
||||
)
|
||||
default boolean requestFocusOnNotification()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "notificationSound",
|
||||
name = "Enable sound on notifications",
|
||||
description = "Enables the playing of a beep sound when notifications are displayed",
|
||||
position = 22
|
||||
)
|
||||
default boolean enableNotificationSound()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "notificationGameMessage",
|
||||
name = "Enable game message notifications",
|
||||
description = "Puts a notification message in the chatbox",
|
||||
position = 23
|
||||
)
|
||||
default boolean enableGameMessageNotification()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "notificationFlash",
|
||||
name = "Enable flash notification",
|
||||
description = "Flashes the game frame as a notification",
|
||||
position = 24
|
||||
)
|
||||
default boolean enableFlashNotification()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "notificationFocused",
|
||||
name = "Send notifications when focused",
|
||||
description = "Toggles all notifications for when the client is focused",
|
||||
position = 25
|
||||
)
|
||||
default boolean sendNotificationsWhenFocused()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@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 = 30
|
||||
)
|
||||
default FontType fontType()
|
||||
{
|
||||
return FontType.SMALL;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "tooltipFontType",
|
||||
name = "Tooltip Font",
|
||||
description = "Configures what font type is used for in-game tooltips such as food stats, NPC names, etc.",
|
||||
position = 31
|
||||
)
|
||||
default FontType tooltipFontType()
|
||||
{
|
||||
return FontType.SMALL;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
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 = 32
|
||||
)
|
||||
default FontType interfaceFontType()
|
||||
{
|
||||
return FontType.REGULAR;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "menuEntryShift",
|
||||
name = "Require Shift for overlay menu",
|
||||
description = "Overlay right-click menu will require shift to be added",
|
||||
position = 33
|
||||
)
|
||||
default boolean menuEntryShift()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "infoBoxVertical",
|
||||
name = "Display infoboxes vertically",
|
||||
description = "Toggles the infoboxes to display vertically",
|
||||
position = 40
|
||||
)
|
||||
default boolean infoBoxVertical()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "infoBoxWrap",
|
||||
name = "Infobox wrap count",
|
||||
description = "Configures the amount of infoboxes shown before wrapping",
|
||||
position = 41
|
||||
)
|
||||
default int infoBoxWrap()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "infoBoxSize",
|
||||
name = "Infobox size (px)",
|
||||
description = "Configures the size of each infobox in pixels",
|
||||
position = 42
|
||||
)
|
||||
default int infoBoxSize()
|
||||
{
|
||||
return 35;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package net.runelite.client.config;
|
||||
|
||||
public class Stub
|
||||
{
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Matt <https://github.com/ms813>
|
||||
* 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.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum WarningOnExit
|
||||
{
|
||||
ALWAYS("Always"),
|
||||
LOGGED_IN("Logged in"),
|
||||
NEVER("Never");
|
||||
|
||||
private final String type;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.discord;
|
||||
|
||||
import java.time.Instant;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* Represents Discord Rich Presence RPC data
|
||||
*/
|
||||
@Builder
|
||||
@Value
|
||||
public class DiscordPresence
|
||||
{
|
||||
/**
|
||||
* The user's current party status.
|
||||
* Example: "Looking to Play", "Playing Solo", "In a Group"
|
||||
*
|
||||
* <b>Maximum: 128 characters</b>
|
||||
*/
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* What the player is currently doing.
|
||||
* Example: "Competitive - Captain's Mode", "In Queue", "Unranked PvP"
|
||||
*
|
||||
* <b>Maximum: 128 characters</b>
|
||||
*/
|
||||
private String details;
|
||||
|
||||
/**
|
||||
* Unix timestamp (seconds) for the start of the game.
|
||||
*/
|
||||
private Instant startTimestamp;
|
||||
|
||||
/**
|
||||
* Unix timestamp (seconds) for the end of the game.
|
||||
*/
|
||||
private Instant endTimestamp;
|
||||
|
||||
/**
|
||||
* Name of the uploaded image for the large profile artwork.
|
||||
* Example: "default"
|
||||
*
|
||||
* <b>Maximum: 32 characters</b>
|
||||
*/
|
||||
private String largeImageKey;
|
||||
|
||||
/**
|
||||
* Tooltip for the largeImageKey.
|
||||
* Example: "Blade's Edge Arena", "Numbani", "Danger Zone"
|
||||
*
|
||||
* <b>Maximum: 128 characters</b>
|
||||
*/
|
||||
private String largeImageText;
|
||||
|
||||
/**
|
||||
* Name of the uploaded image for the small profile artwork.
|
||||
* Example: "rogue"
|
||||
*
|
||||
* <b>Maximum: 32 characters</b>
|
||||
*/
|
||||
private String smallImageKey;
|
||||
|
||||
/**
|
||||
* Tooltip for the smallImageKey.
|
||||
* Example: "Rogue - Level 100"
|
||||
*
|
||||
* <b>Maximum: 128 characters</b>
|
||||
*/
|
||||
private String smallImageText;
|
||||
|
||||
/**
|
||||
* ID of the player's party, lobby, or group.
|
||||
* Example: "ae488379-351d-4a4f-ad32-2b9b01c91657"
|
||||
*
|
||||
* <b>Maximum: 128 characters</b>
|
||||
*/
|
||||
private String partyId;
|
||||
|
||||
/**
|
||||
* Current size of the player's party, lobby, or group.
|
||||
* Example: 1
|
||||
*/
|
||||
private int partySize;
|
||||
|
||||
/**
|
||||
* Maximum size of the player's party, lobby, or group.
|
||||
* Example: 5
|
||||
*/
|
||||
private int partyMax;
|
||||
|
||||
/**
|
||||
* Unique hashed string for Spectate and Join.
|
||||
* Required to enable match interactive buttons in the user's presence.
|
||||
* Example: "MmhuZToxMjMxMjM6cWl3amR3MWlqZA=="
|
||||
*
|
||||
* <b>Maximum: 128 characters</b>
|
||||
*/
|
||||
private String matchSecret;
|
||||
|
||||
/**
|
||||
* Unique hashed string for Spectate button.
|
||||
* This will enable the "Spectate" button on the user's presence if whitelisted.
|
||||
* Example: "MTIzNDV8MTIzNDV8MTMyNDU0"
|
||||
*
|
||||
* <b>Maximum: 128 characters</b>
|
||||
*/
|
||||
private String joinSecret;
|
||||
|
||||
/**
|
||||
* Unique hashed string for chat invitations and Ask to Join.
|
||||
* This will enable the "Ask to Join" button on the user's presence if whitelisted.
|
||||
* Example: "MTI4NzM0OjFpMmhuZToxMjMxMjM="
|
||||
*
|
||||
* <b>Maximum: 128 characters</b>
|
||||
*/
|
||||
private String spectateSecret;
|
||||
|
||||
/**
|
||||
* Marks the matchSecret as a game session with a specific beginning and end.
|
||||
*/
|
||||
private boolean instance;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.discord;
|
||||
|
||||
/**
|
||||
* Discord reply type for request
|
||||
*/
|
||||
public enum DiscordReplyType
|
||||
{
|
||||
/**
|
||||
* Used to decline a request
|
||||
*/
|
||||
NO,
|
||||
|
||||
/**
|
||||
* Used to accept a request
|
||||
*/
|
||||
YES,
|
||||
|
||||
/**
|
||||
* Currently unused response, treated like NO.
|
||||
*/
|
||||
IGNORE
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.discord;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.RuneLiteProperties;
|
||||
import net.runelite.client.discord.events.DiscordDisconnected;
|
||||
import net.runelite.client.discord.events.DiscordErrored;
|
||||
import net.runelite.client.discord.events.DiscordJoinGame;
|
||||
import net.runelite.client.discord.events.DiscordJoinRequest;
|
||||
import net.runelite.client.discord.events.DiscordReady;
|
||||
import net.runelite.client.discord.events.DiscordSpectateGame;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.discord.DiscordEventHandlers;
|
||||
import net.runelite.discord.DiscordRPC;
|
||||
import net.runelite.discord.DiscordRichPresence;
|
||||
import net.runelite.discord.DiscordUser;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class DiscordService implements AutoCloseable
|
||||
{
|
||||
private final EventBus eventBus;
|
||||
public final RuneLiteProperties runeLiteProperties;
|
||||
private final ScheduledExecutorService executorService;
|
||||
private final DiscordRPC discordRPC;
|
||||
|
||||
// Hold a reference to the event handlers to prevent the garbage collector from deleting them
|
||||
private final DiscordEventHandlers discordEventHandlers;
|
||||
|
||||
@Getter
|
||||
private DiscordUser currentUser;
|
||||
|
||||
@Inject
|
||||
private DiscordService(
|
||||
final EventBus eventBus,
|
||||
final RuneLiteProperties runeLiteProperties,
|
||||
final ScheduledExecutorService executorService)
|
||||
{
|
||||
|
||||
this.eventBus = eventBus;
|
||||
this.runeLiteProperties = runeLiteProperties;
|
||||
this.executorService = executorService;
|
||||
|
||||
DiscordRPC discordRPC = null;
|
||||
DiscordEventHandlers discordEventHandlers = null;
|
||||
|
||||
try
|
||||
{
|
||||
discordRPC = DiscordRPC.INSTANCE;
|
||||
discordEventHandlers = new DiscordEventHandlers();
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
log.warn("Failed to load Discord library, Discord support will be disabled.");
|
||||
}
|
||||
|
||||
this.discordRPC = discordRPC;
|
||||
this.discordEventHandlers = discordEventHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Discord service, sets up the event handlers and starts worker thread that will poll discord
|
||||
* events every 2 seconds.
|
||||
* Before closing the application it is recommended to call {@link #close()}
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
if (discordEventHandlers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("Initializing Discord RPC service.");
|
||||
discordEventHandlers.ready = this::ready;
|
||||
discordEventHandlers.disconnected = this::disconnected;
|
||||
discordEventHandlers.errored = this::errored;
|
||||
discordEventHandlers.joinGame = this::joinGame;
|
||||
discordEventHandlers.spectateGame = this::spectateGame;
|
||||
discordEventHandlers.joinRequest = this::joinRequest;
|
||||
discordRPC.Discord_Initialize(RuneLiteProperties.discordAppID, discordEventHandlers, true, null);
|
||||
executorService.scheduleAtFixedRate(discordRPC::Discord_RunCallbacks, 0, 2, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts the RPC connection down.
|
||||
* If not currently connected, this does nothing.
|
||||
*/
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if (discordRPC != null)
|
||||
{
|
||||
discordRPC.Discord_Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the currently set presence of the logged in user.
|
||||
* <br>Note that the client only updates its presence every <b>15 seconds</b>
|
||||
* and queues all additional presence updates.
|
||||
*
|
||||
* @param discordPresence The new presence to use
|
||||
*/
|
||||
public void updatePresence(DiscordPresence discordPresence)
|
||||
{
|
||||
if (discordRPC == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final DiscordRichPresence discordRichPresence = new DiscordRichPresence();
|
||||
discordRichPresence.state = discordPresence.getState();
|
||||
discordRichPresence.details = discordPresence.getDetails();
|
||||
discordRichPresence.startTimestamp = discordPresence.getStartTimestamp() != null
|
||||
? discordPresence.getStartTimestamp().getEpochSecond()
|
||||
: 0;
|
||||
discordRichPresence.endTimestamp = discordPresence.getEndTimestamp() != null
|
||||
? discordPresence.getEndTimestamp().getEpochSecond()
|
||||
: 0;
|
||||
discordRichPresence.largeImageKey = Strings.isNullOrEmpty(discordPresence.getLargeImageKey())
|
||||
? "default"
|
||||
: discordPresence.getLargeImageKey();
|
||||
discordRichPresence.largeImageText = discordPresence.getLargeImageText();
|
||||
|
||||
if (!Strings.isNullOrEmpty(discordPresence.getSmallImageKey()))
|
||||
{
|
||||
discordRichPresence.smallImageKey = discordPresence.getSmallImageKey();
|
||||
}
|
||||
|
||||
discordRichPresence.smallImageText = discordPresence.getSmallImageText();
|
||||
discordRichPresence.partyId = discordPresence.getPartyId();
|
||||
discordRichPresence.partySize = discordPresence.getPartySize();
|
||||
discordRichPresence.partyMax = discordPresence.getPartyMax();
|
||||
discordRichPresence.matchSecret = discordPresence.getMatchSecret();
|
||||
discordRichPresence.joinSecret = discordPresence.getJoinSecret();
|
||||
discordRichPresence.spectateSecret = discordPresence.getSpectateSecret();
|
||||
discordRichPresence.instance = (byte) (discordPresence.isInstance() ? 1 : 0);
|
||||
|
||||
log.debug("Sending presence update {}", discordPresence);
|
||||
discordRPC.Discord_UpdatePresence(discordRichPresence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the currently set presence.
|
||||
*/
|
||||
public void clearPresence()
|
||||
{
|
||||
if (discordRPC != null)
|
||||
{
|
||||
discordRPC.Discord_ClearPresence();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to the given user with the specified reply type.
|
||||
*
|
||||
* @param userId The id of the user to respond to
|
||||
* @param reply The reply type
|
||||
*/
|
||||
public void respondToRequest(String userId, DiscordReplyType reply)
|
||||
{
|
||||
if (discordRPC != null)
|
||||
{
|
||||
discordRPC.Discord_Respond(userId, reply.ordinal());
|
||||
}
|
||||
}
|
||||
|
||||
private void ready(DiscordUser user)
|
||||
{
|
||||
log.info("Discord RPC service is ready with user {}.", user.username);
|
||||
currentUser = user;
|
||||
eventBus.post(new DiscordReady(
|
||||
user.userId,
|
||||
user.username,
|
||||
user.discriminator,
|
||||
user.avatar));
|
||||
}
|
||||
|
||||
private void disconnected(int errorCode, String message)
|
||||
{
|
||||
eventBus.post(new DiscordDisconnected(errorCode, message));
|
||||
}
|
||||
|
||||
private void errored(int errorCode, String message)
|
||||
{
|
||||
log.warn("Discord error: {} - {}", errorCode, message);
|
||||
eventBus.post(new DiscordErrored(errorCode, message));
|
||||
}
|
||||
|
||||
private void joinGame(String joinSecret)
|
||||
{
|
||||
eventBus.post(new DiscordJoinGame(joinSecret));
|
||||
}
|
||||
|
||||
private void spectateGame(String spectateSecret)
|
||||
{
|
||||
eventBus.post(new DiscordSpectateGame(spectateSecret));
|
||||
}
|
||||
|
||||
private void joinRequest(DiscordUser user)
|
||||
{
|
||||
eventBus.post(new DiscordJoinRequest(
|
||||
user.userId,
|
||||
user.username,
|
||||
user.discriminator,
|
||||
user.avatar));
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.discord.events;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* Called when the RPC connection has been severed
|
||||
*/
|
||||
@Value
|
||||
public class DiscordDisconnected
|
||||
{
|
||||
/**
|
||||
* Discord error code
|
||||
*/
|
||||
private int errorCode;
|
||||
|
||||
/**
|
||||
* Error message
|
||||
*/
|
||||
private String message;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.discord.events;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* Called when an internal error is caught within the SDK
|
||||
*/
|
||||
@Value
|
||||
public class DiscordErrored
|
||||
{
|
||||
/**
|
||||
* Discord error code.
|
||||
*/
|
||||
private int errorCode;
|
||||
|
||||
/**
|
||||
* Error message
|
||||
*/
|
||||
private String message;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.discord.events;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* Called when the logged in user joined a game
|
||||
*/
|
||||
@Value
|
||||
public class DiscordJoinGame
|
||||
{
|
||||
/**
|
||||
* Obfuscated data of your choosing used as join secret
|
||||
*/
|
||||
private String joinSecret;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.discord.events;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* Called when another discord user wants to join the game of the logged in user
|
||||
*/
|
||||
@Value
|
||||
public class DiscordJoinRequest
|
||||
{
|
||||
/**
|
||||
* The userId for the user that requests to join
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* The username of the user that requests to join
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* The discriminator of the user that requests to join
|
||||
*/
|
||||
private String discriminator;
|
||||
|
||||
/**
|
||||
* The avatar of the user that requests to join
|
||||
*/
|
||||
private String avatar;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.discord.events;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* Called when the RPC connection has been established
|
||||
*/
|
||||
@Value
|
||||
public class DiscordReady
|
||||
{
|
||||
/**
|
||||
* The userId for the active user
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* The username of the active user
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* The discriminator of the active user
|
||||
*/
|
||||
private String discriminator;
|
||||
|
||||
/**
|
||||
* The avatar of the active user
|
||||
*/
|
||||
private String avatar;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.discord.events;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* Called when the logged in user joined to spectate a game
|
||||
*/
|
||||
@Value
|
||||
public class DiscordSpectateGame
|
||||
{
|
||||
/**
|
||||
* Obfuscated data of your choosing used as spectate secret
|
||||
*/
|
||||
private String spectateSecret;
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
* 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.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.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
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;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@ThreadSafe
|
||||
public class EventBus
|
||||
{
|
||||
@FunctionalInterface
|
||||
public interface SubscriberMethod
|
||||
{
|
||||
void invoke(Object event);
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class Subscriber
|
||||
{
|
||||
private final Object object;
|
||||
private final Method method;
|
||||
@EqualsAndHashCode.Exclude
|
||||
private final SubscriberMethod lamda;
|
||||
|
||||
void invoke(final Object arg) throws Exception
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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 = 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, lambda);
|
||||
builder.put(parameterClazz, subscriber);
|
||||
log.debug("Registering {} - {}", parameterClazz, subscriber);
|
||||
}
|
||||
}
|
||||
|
||||
subscribers = builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters all subscribed methods from provided subscriber object.
|
||||
*
|
||||
* @param object object to unsubscribe from
|
||||
*/
|
||||
public synchronized void unregister(@Nonnull final Object object)
|
||||
{
|
||||
if (subscribers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Multimap<Class, Subscriber> map = HashMultimap.create();
|
||||
map.putAll(subscribers);
|
||||
|
||||
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, null));
|
||||
}
|
||||
}
|
||||
|
||||
subscribers = ImmutableMultimap.copyOf(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts provided event to all registered subscribers. Subscriber calls are invoked immediately and in order
|
||||
* in which subscribers were registered.
|
||||
*
|
||||
* @param event event to post
|
||||
*/
|
||||
public void post(@Nonnull final Object event)
|
||||
{
|
||||
for (final Subscriber subscriber : subscribers.get(event.getClass()))
|
||||
{
|
||||
try
|
||||
{
|
||||
subscriber.invoke(event);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exceptionHandler.accept(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodHandles.Lookup privateLookupIn(Class clazz) throws IllegalAccessException, NoSuchFieldException, InvocationTargetException
|
||||
{
|
||||
try
|
||||
{
|
||||
// Java 9+ has privateLookupIn method on MethodHandles, but since we are shipping and using Java 8
|
||||
// we need to access it via reflection. This is preferred way because it's Java 9+ public api and is
|
||||
// likely to not change
|
||||
final Method privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
|
||||
return (MethodHandles.Lookup) privateLookupIn.invoke(null, clazz, MethodHandles.lookup());
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
// In Java 8 we first do standard lookupIn class
|
||||
final MethodHandles.Lookup lookupIn = MethodHandles.lookup().in(clazz);
|
||||
|
||||
// and then we mark it as trusted for private lookup via reflection on private field
|
||||
final Field modes = MethodHandles.Lookup.class.getDeclaredField("allowedModes");
|
||||
modes.setAccessible(true);
|
||||
modes.setInt(lookupIn, -1); // -1 == TRUSTED
|
||||
return lookupIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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 java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a method as an event subscriber.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface Subscribe
|
||||
{
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* 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.events;
|
||||
|
||||
public abstract class ChatInput
|
||||
{
|
||||
public abstract void resume();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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.events;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class ChatboxInput extends ChatInput
|
||||
{
|
||||
private final String value;
|
||||
private final int chatType;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.events;
|
||||
|
||||
import lombok.Value;
|
||||
import net.runelite.client.ui.NavigationButton;
|
||||
|
||||
@Value
|
||||
public class NavigationButtonAdded
|
||||
{
|
||||
private NavigationButton button;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.events;
|
||||
|
||||
import lombok.Value;
|
||||
import net.runelite.client.ui.NavigationButton;
|
||||
|
||||
@Value
|
||||
public class NavigationButtonRemoved
|
||||
{
|
||||
private NavigationButton button;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.events;
|
||||
|
||||
import java.util.Collection;
|
||||
import lombok.Value;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.client.game.ItemStack;
|
||||
|
||||
@Value
|
||||
public class NpcLootReceived
|
||||
{
|
||||
private final NPC npc;
|
||||
private final Collection<ItemStack> items;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.events;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
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
|
||||
{
|
||||
private OverlayMenuEntry entry;
|
||||
private Overlay overlay;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.events;
|
||||
|
||||
import java.util.UUID;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class PartyChanged
|
||||
{
|
||||
private final UUID partyId;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.events;
|
||||
|
||||
import java.util.Collection;
|
||||
import lombok.Value;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.client.game.ItemStack;
|
||||
|
||||
@Value
|
||||
public class PlayerLootReceived
|
||||
{
|
||||
private final Player player;
|
||||
private final Collection<ItemStack> items;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Tomas Slusny <slusnucky@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.events;
|
||||
|
||||
import lombok.Data;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
|
||||
@Data
|
||||
public class PluginChanged
|
||||
{
|
||||
private final Plugin plugin;
|
||||
private final boolean loaded;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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.events;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class PrivateMessageInput extends ChatInput
|
||||
{
|
||||
private final String target;
|
||||
private final String message;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.events;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* An event where a new RuneLite account session has been closed,
|
||||
* typically when logging out of the account.
|
||||
* <p>
|
||||
* Note: This event is not to be confused with a RuneScape session,
|
||||
* it has nothing to do with whether an account is being logged out.
|
||||
*/
|
||||
@Data
|
||||
public class SessionClose
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.events;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* An event where a new RuneLite account session has been opened
|
||||
* with the server.
|
||||
* <p>
|
||||
* Note: This event is not to be confused with a RuneScape session,
|
||||
* it has nothing to do with whether an account is being logged in.
|
||||
*/
|
||||
@Data
|
||||
public class SessionOpen
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,338 +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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Modified java.awt.Robot for use with RuneLitePlus. Hopefully we can make it stand far apart.
|
||||
Uses
|
||||
https://github.com/JoonasVali/NaturalMouseMotion
|
||||
for mouse motion.
|
||||
*/
|
||||
|
||||
package net.runelite.client.flexo;
|
||||
|
||||
import com.github.joonasvali.naturalmouse.api.MouseMotionFactory;
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Color;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Point;
|
||||
import java.awt.Robot;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.peer.RobotPeer;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Logger;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import sun.awt.ComponentFactory;
|
||||
|
||||
public class Flexo extends Robot
|
||||
{
|
||||
public ThreadGroup flexoThreads = new ThreadGroup("flexo");
|
||||
public static boolean isActive;
|
||||
public static double scale;
|
||||
public static Client client;
|
||||
public static ClientUI clientUI;
|
||||
public static final int fixedWidth = Constants.GAME_FIXED_WIDTH;
|
||||
public static final int fixedHeight = Constants.GAME_FIXED_HEIGHT;
|
||||
public static boolean isStretched;
|
||||
public static int minDelay = 45;
|
||||
public static MouseMotionFactory currentMouseMotionFactory;
|
||||
public boolean pausedIndefinitely = false;
|
||||
private RobotPeer peer;
|
||||
|
||||
public Flexo() throws AWTException
|
||||
{
|
||||
if (GraphicsEnvironment.isHeadless())
|
||||
{
|
||||
throw new AWTException("headless environment");
|
||||
}
|
||||
init(GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice());
|
||||
}
|
||||
|
||||
private void init(GraphicsDevice screen) throws AWTException
|
||||
{
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
if (toolkit instanceof ComponentFactory)
|
||||
{
|
||||
peer = ((ComponentFactory) toolkit).createRobot(this, screen);
|
||||
RobotDisposer disposer = new RobotDisposer(peer);
|
||||
sun.java2d.Disposer.addRecord(anchor, disposer);
|
||||
}
|
||||
}
|
||||
|
||||
private transient Object anchor = new Object();
|
||||
|
||||
static class RobotDisposer implements sun.java2d.DisposerRecord
|
||||
{
|
||||
private final RobotPeer peer;
|
||||
|
||||
private RobotDisposer(RobotPeer peer)
|
||||
{
|
||||
this.peer = peer;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
if (peer != null)
|
||||
{
|
||||
peer.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void pauseMS(int delayMS)
|
||||
{
|
||||
long initialMS = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() < initialMS + delayMS)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(10);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mouseMove(int x, int y)
|
||||
{
|
||||
try
|
||||
{
|
||||
//TODO: Must be better way to determine titlebar width
|
||||
currentMouseMotionFactory.build(ClientUI.frame.getX() + x + determineHorizontalOffset(), ClientUI.frame.getY() + y + determineVerticalOffset()).move();
|
||||
this.delay(getMinDelay());
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void mouseMove(Point p)
|
||||
{
|
||||
mouseMove((int) p.getX(), (int) p.getY());
|
||||
try
|
||||
{
|
||||
Thread.sleep(150);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mousePress(int buttonID)
|
||||
{
|
||||
if (buttonID < 1 || buttonID > 5)
|
||||
{
|
||||
Logger.getAnonymousLogger().warning("Invalid mouse button ID. please use 1-5.");
|
||||
return;
|
||||
}
|
||||
peer.mousePress(InputEvent.getMaskForButton(buttonID));
|
||||
this.delay(getMinDelay());
|
||||
}
|
||||
|
||||
public synchronized void mousePressAndRelease(int buttonID)
|
||||
{
|
||||
if (buttonID < 1 || buttonID > 5)
|
||||
{
|
||||
Logger.getAnonymousLogger().warning("Invalid mouse button ID. please use 1-5.");
|
||||
return;
|
||||
}
|
||||
peer.mousePress(InputEvent.getMaskForButton(buttonID));
|
||||
this.delay(getMinDelay());
|
||||
peer.mouseRelease(InputEvent.getMaskForButton(buttonID));
|
||||
this.delay(getMinDelay());
|
||||
}
|
||||
|
||||
//TODO: Symbols are nut supported at this time
|
||||
public synchronized void typeMessage(String message)
|
||||
{
|
||||
|
||||
Random r = new Random();
|
||||
char[] charArray = message.toCharArray();
|
||||
for (char c : charArray)
|
||||
{
|
||||
keyPress(KeyEvent.getExtendedKeyCodeForChar(c));
|
||||
this.delay(93 + r.nextInt(getMinDelay()));
|
||||
}
|
||||
keyPress(KeyEvent.VK_ENTER);
|
||||
this.delay(93 + r.nextInt(getMinDelay()));
|
||||
ClientUI.allowInput = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void mouseRelease(int buttonID)
|
||||
{
|
||||
if (buttonID < 1 || buttonID > 5)
|
||||
{
|
||||
Logger.getAnonymousLogger().warning("Invalid mouse button ID. please use 1-5.");
|
||||
return;
|
||||
}
|
||||
peer.mouseRelease(InputEvent.getMaskForButton(buttonID));
|
||||
this.delay(getMinDelay());
|
||||
}
|
||||
|
||||
private int getMinDelay()
|
||||
{
|
||||
Random random = new Random();
|
||||
int random1 = random.nextInt(minDelay);
|
||||
if (random1 < minDelay / 2)
|
||||
{
|
||||
random1 = random.nextInt(minDelay / 2) + minDelay / 2 + random.nextInt(minDelay / 2);
|
||||
}
|
||||
return random1;
|
||||
}
|
||||
|
||||
private int getWheelDelay()
|
||||
{
|
||||
Random random = new Random();
|
||||
int random1 = random.nextInt(minDelay);
|
||||
if (random1 < minDelay / 2)
|
||||
{
|
||||
random1 = random.nextInt(minDelay / 2) + minDelay / 2 + random.nextInt(minDelay / 2);
|
||||
}
|
||||
return random1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the scroll wheel on wheel-equipped mice.
|
||||
*
|
||||
* @param wheelAmt number of "notches" to move the mouse wheel
|
||||
* Negative values indicate movement up/away from the user,
|
||||
* positive values indicate movement down/towards the user.
|
||||
* @since 1.4
|
||||
*/
|
||||
@Override
|
||||
public synchronized void mouseWheel(int wheelAmt)
|
||||
{
|
||||
for (int i : new int[wheelAmt])
|
||||
{
|
||||
peer.mouseWheel(wheelAmt);
|
||||
this.delay(getWheelDelay());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Presses a given key. The key should be released using the
|
||||
* <code>keyRelease</code> method.
|
||||
* <p>
|
||||
* Key codes that have more than one physical key associated with them
|
||||
* (e.g. <code>KeyEvent.VK_SHIFT</code> could mean either the
|
||||
* left or right shift key) will map to the left key.
|
||||
*
|
||||
* @param keycode Key to press (e.g. <code>KeyEvent.VK_A</code>)
|
||||
* @throws IllegalArgumentException if <code>keycode</code> is not
|
||||
* a valid key
|
||||
* @see #keyRelease(int)
|
||||
* @see java.awt.event.KeyEvent
|
||||
*/
|
||||
@Override
|
||||
public synchronized void keyPress(int keycode)
|
||||
{
|
||||
peer.keyPress(keycode);
|
||||
this.delay(getMinDelay());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void keyRelease(int keycode)
|
||||
{
|
||||
peer.keyRelease(keycode);
|
||||
this.delay(getMinDelay());
|
||||
}
|
||||
|
||||
public synchronized void holdKey(int keycode, int timeMS)
|
||||
{
|
||||
new Thread(() ->
|
||||
{
|
||||
peer.keyPress(keycode);
|
||||
long startTime = System.currentTimeMillis();
|
||||
while ((startTime + timeMS) > System.currentTimeMillis())
|
||||
{
|
||||
}
|
||||
peer.keyRelease(keycode);
|
||||
this.delay(getMinDelay());
|
||||
}).start();
|
||||
}
|
||||
|
||||
public synchronized void holdKeyIndefinitely(int keycode)
|
||||
{
|
||||
Thread holdKeyThread = new Thread(() ->
|
||||
{
|
||||
pausedIndefinitely = true;
|
||||
peer.keyPress(keycode);
|
||||
while (pausedIndefinitely)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(10);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
peer.keyRelease(keycode);
|
||||
this.delay(getMinDelay());
|
||||
});
|
||||
holdKeyThread.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getPixelColor(int x, int y)
|
||||
{
|
||||
return new Color(peer.getRGBPixel(x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delay(int ms)
|
||||
{
|
||||
pauseMS(ms);
|
||||
}
|
||||
|
||||
public int determineHorizontalOffset()
|
||||
{
|
||||
return clientUI.getCanvasOffset().getX();
|
||||
}
|
||||
|
||||
public int determineVerticalOffset()
|
||||
{
|
||||
return clientUI.getCanvasOffset().getY();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,225 +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.flexo;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Logger;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
|
||||
public class FlexoMouse
|
||||
{
|
||||
|
||||
/*
|
||||
Should pass unstretched coords, handles all conversions here.
|
||||
*/
|
||||
public static Point getClickPoint(Rectangle rect)
|
||||
{
|
||||
if (rect != null)
|
||||
{
|
||||
Random r = new Random();
|
||||
int x = -1;
|
||||
int y = -1;
|
||||
x = rect.x + r.nextInt(rect.width);
|
||||
y = rect.y + r.nextInt(rect.height);
|
||||
|
||||
if (Flexo.isStretched)
|
||||
{
|
||||
double wScale;
|
||||
double hScale;
|
||||
|
||||
if (Flexo.client.isResized())
|
||||
{
|
||||
wScale = (Flexo.client.getStretchedDimensions().width / (double) Flexo.client.getRealDimensions().width);
|
||||
hScale = (Flexo.client.getStretchedDimensions().height / (double) Flexo.client.getRealDimensions().height);
|
||||
int newX = (int) (x * wScale);
|
||||
int newY = (int) (y * hScale);
|
||||
if (newX > 0 && newX < ClientUI.frame.getWidth())
|
||||
{
|
||||
if (newY > 0 && newY < ClientUI.frame.getHeight())
|
||||
{
|
||||
return new Point(newX, newY);
|
||||
}
|
||||
}
|
||||
Logger.getAnonymousLogger().warning("[RuneLit]Flexo - Off screen point attempted. Split the step, or rotate the screen.");
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x > 0 && x < ClientUI.frame.getWidth())
|
||||
{
|
||||
if (y > 0 && y < ClientUI.frame.getHeight())
|
||||
{
|
||||
return new Point(x, y);
|
||||
}
|
||||
}
|
||||
Logger.getAnonymousLogger().warning("[RuneLit]Flexo - Off screen point attempted. Split the step, or rotate the screen.");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
else if (!Flexo.client.isResized())
|
||||
{
|
||||
final int fixedWidth = Constants.GAME_FIXED_WIDTH;
|
||||
int widthDif = ClientUI.frame.getWidth();
|
||||
|
||||
if (ClientUI.pluginToolbar.isVisible())
|
||||
{
|
||||
widthDif -= ClientUI.pluginToolbar.getWidth();
|
||||
}
|
||||
if (ClientUI.pluginPanel != null)
|
||||
{
|
||||
widthDif -= ClientUI.pluginPanel.getWidth();
|
||||
}
|
||||
|
||||
widthDif -= fixedWidth;
|
||||
if (x + (widthDif / 2) > 0 && x + (widthDif / 2) < ClientUI.frame.getWidth())
|
||||
{
|
||||
if (y > 0 && y < ClientUI.frame.getHeight())
|
||||
{
|
||||
return new Point(x, y);
|
||||
}
|
||||
}
|
||||
Logger.getAnonymousLogger().warning("[RuneLit]Flexo - Off screen point attempted. Split the step, or rotate the screen.");
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x > 0 && x < ClientUI.frame.getWidth())
|
||||
{
|
||||
if (y > 0 && y < ClientUI.frame.getHeight())
|
||||
{
|
||||
return new Point(x, y);
|
||||
}
|
||||
}
|
||||
Logger.getAnonymousLogger().warning("[RuneLit]Flexo - Off screen point attempted. Split the step, or rotate the screen.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Rectangle getClickArea(Rectangle rect)
|
||||
{
|
||||
if (Flexo.isStretched)
|
||||
{
|
||||
double wScale;
|
||||
double hScale;
|
||||
|
||||
if (Flexo.client.isResized())
|
||||
{
|
||||
wScale = (Flexo.client.getStretchedDimensions().width / (double) Flexo.client.getRealDimensions().width);
|
||||
hScale = (Flexo.client.getStretchedDimensions().height / (double) Flexo.client.getRealDimensions().height);
|
||||
}
|
||||
else
|
||||
{
|
||||
wScale = (Flexo.client.getStretchedDimensions().width) / (double) Flexo.fixedWidth;
|
||||
hScale = (Flexo.client.getStretchedDimensions().height) / (double) Flexo.fixedHeight;
|
||||
}
|
||||
|
||||
int xPadding = (int) rect.getWidth() / 5;
|
||||
int yPadding = (int) rect.getHeight() / 5;
|
||||
Random r = new Random();
|
||||
Rectangle clickRect = new Rectangle();
|
||||
clickRect.width = rect.width - xPadding * 2;
|
||||
clickRect.height = rect.height - yPadding * 2;
|
||||
clickRect.x = rect.x + xPadding;
|
||||
clickRect.y = rect.y + yPadding;
|
||||
if (clickRect.width > 0 && clickRect.height > 0)
|
||||
{
|
||||
int x = clickRect.x + r.nextInt(clickRect.width);
|
||||
int y = clickRect.y + r.nextInt(clickRect.height);
|
||||
double tScale = 1 + (Flexo.scale / 100);
|
||||
|
||||
if (Flexo.client.isResized())
|
||||
{
|
||||
return new Rectangle((int) (clickRect.x * wScale), (int) (clickRect.y * wScale), (int) (clickRect.width * wScale), (int) (clickRect.getHeight() * hScale));
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Rectangle(clickRect.x, clickRect.y, clickRect.width, (int) (clickRect.getHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//Fixed, not stretched
|
||||
else if (!Flexo.client.isResized())
|
||||
{
|
||||
int fixedWidth = 765;
|
||||
int widthDif = ClientUI.frame.getWidth();
|
||||
|
||||
if (ClientUI.pluginToolbar.isVisible())
|
||||
{
|
||||
widthDif -= ClientUI.pluginToolbar.getWidth();
|
||||
}
|
||||
if (ClientUI.pluginPanel != null)
|
||||
{
|
||||
widthDif -= ClientUI.pluginPanel.getWidth();
|
||||
}
|
||||
|
||||
widthDif -= fixedWidth;
|
||||
int xPadding = (int) rect.getWidth() / 5;
|
||||
int yPadding = (int) rect.getHeight() / 5;
|
||||
Random r = new Random();
|
||||
Rectangle clickRect = new Rectangle();
|
||||
clickRect.width = rect.width - xPadding;
|
||||
clickRect.height = rect.height - yPadding;
|
||||
clickRect.x = rect.x + xPadding;
|
||||
clickRect.y = rect.y + yPadding;
|
||||
if (clickRect.height > 0 && clickRect.width > 0)
|
||||
{
|
||||
int x = clickRect.x + r.nextInt(clickRect.width);
|
||||
int y = clickRect.y + r.nextInt(clickRect.height);
|
||||
return new Rectangle(clickRect.x, clickRect.y, clickRect.width, (int) (clickRect.getHeight()));
|
||||
}
|
||||
}
|
||||
//Resizable, not stretched
|
||||
else
|
||||
{
|
||||
int xPadding = (int) rect.getWidth() / 5;
|
||||
int yPadding = (int) rect.getHeight() / 5;
|
||||
Random r = new Random();
|
||||
Rectangle clickRect = new Rectangle();
|
||||
clickRect.width = rect.width - xPadding * 2;
|
||||
clickRect.height = rect.height - yPadding * 2;
|
||||
clickRect.x = rect.x + xPadding;
|
||||
clickRect.y = rect.y + yPadding;
|
||||
if (clickRect.height > 0 && clickRect.width > 0)
|
||||
{
|
||||
int x = clickRect.x + r.nextInt(clickRect.width);
|
||||
int y = clickRect.y + r.nextInt(clickRect.height);
|
||||
return new Rectangle(clickRect.x, clickRect.y, clickRect.width, (int) (clickRect.getHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,452 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* Copyright (c) 2019, MrGroggle
|
||||
* 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 lombok.Getter;
|
||||
import static net.runelite.api.NullObjectID.NULL_25337;
|
||||
import static net.runelite.api.NullObjectID.NULL_26371;
|
||||
import static net.runelite.api.NullObjectID.NULL_26375;
|
||||
import static net.runelite.api.NullObjectID.NULL_26884;
|
||||
import static net.runelite.api.NullObjectID.NULL_26886;
|
||||
import static net.runelite.api.NullObjectID.NULL_29868;
|
||||
import static net.runelite.api.NullObjectID.NULL_29869;
|
||||
import static net.runelite.api.NullObjectID.NULL_29870;
|
||||
import static net.runelite.api.NullObjectID.NULL_31823;
|
||||
import static net.runelite.api.NullObjectID.NULL_31849;
|
||||
import static net.runelite.api.NullObjectID.NULL_33327;
|
||||
import static net.runelite.api.NullObjectID.NULL_33328;
|
||||
import static net.runelite.api.ObjectID.A_WOODEN_LOG;
|
||||
import static net.runelite.api.ObjectID.BALANCING_LEDGE_23548;
|
||||
import static net.runelite.api.ObjectID.BIG_WINDOW;
|
||||
import static net.runelite.api.ObjectID.BOULDER_27990;
|
||||
import static net.runelite.api.ObjectID.BROKEN_FENCE;
|
||||
import static net.runelite.api.ObjectID.BROKEN_FENCE_2618;
|
||||
import static net.runelite.api.ObjectID.BROKEN_RAFT;
|
||||
import static net.runelite.api.ObjectID.BROKEN_WALL_33344;
|
||||
import static net.runelite.api.ObjectID.CASTLE_WALL;
|
||||
import static net.runelite.api.ObjectID.CLIMBING_ROCKS;
|
||||
import static net.runelite.api.ObjectID.CLIMBING_ROCKS_11948;
|
||||
import static net.runelite.api.ObjectID.CLIMBING_ROCKS_11949;
|
||||
import static net.runelite.api.ObjectID.CREVICE_16465;
|
||||
import static net.runelite.api.ObjectID.CREVICE_16539;
|
||||
import static net.runelite.api.ObjectID.CREVICE_16543;
|
||||
import static net.runelite.api.ObjectID.CREVICE_19043;
|
||||
import static net.runelite.api.ObjectID.CREVICE_30198;
|
||||
import static net.runelite.api.ObjectID.CREVICE_9739;
|
||||
import static net.runelite.api.ObjectID.CREVICE_9740;
|
||||
import static net.runelite.api.ObjectID.CROSSBOW_TREE_17062;
|
||||
import static net.runelite.api.ObjectID.CRUMBLING_WALL_24222;
|
||||
import static net.runelite.api.ObjectID.DARK_TUNNEL_10047;
|
||||
import static net.runelite.api.ObjectID.DENSE_FOREST;
|
||||
import static net.runelite.api.ObjectID.DENSE_FOREST_3938;
|
||||
import static net.runelite.api.ObjectID.DENSE_FOREST_3939;
|
||||
import static net.runelite.api.ObjectID.DENSE_FOREST_3998;
|
||||
import static net.runelite.api.ObjectID.DENSE_FOREST_3999;
|
||||
import static net.runelite.api.ObjectID.FALLEN_TREE_33192;
|
||||
import static net.runelite.api.ObjectID.FENCE_16518;
|
||||
import static net.runelite.api.ObjectID.GAP;
|
||||
import static net.runelite.api.ObjectID.GAP_2831;
|
||||
import static net.runelite.api.ObjectID.GAP_29326;
|
||||
import static net.runelite.api.ObjectID.HOLE_16520;
|
||||
import static net.runelite.api.ObjectID.HOLE_30966;
|
||||
import static net.runelite.api.ObjectID.HOLE_31481;
|
||||
import static net.runelite.api.ObjectID.HOLE_31482;
|
||||
import static net.runelite.api.ObjectID.ICE_CHUNKS_31822;
|
||||
import static net.runelite.api.ObjectID.ICE_CHUNKS_31990;
|
||||
import static net.runelite.api.ObjectID.JUTTING_WALL_17002;
|
||||
import static net.runelite.api.ObjectID.LADDER_30938;
|
||||
import static net.runelite.api.ObjectID.LADDER_30939;
|
||||
import static net.runelite.api.ObjectID.LADDER_30940;
|
||||
import static net.runelite.api.ObjectID.LADDER_30941;
|
||||
import static net.runelite.api.ObjectID.LEAVES;
|
||||
import static net.runelite.api.ObjectID.LEAVES_3924;
|
||||
import static net.runelite.api.ObjectID.LEAVES_3925;
|
||||
import static net.runelite.api.ObjectID.LEDGE_33190;
|
||||
import static net.runelite.api.ObjectID.LITTLE_BOULDER;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_16540;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_16541;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_16542;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_16546;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_16547;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_16548;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_20882;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_20884;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_23274;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_3929;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_3930;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_3931;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_3932;
|
||||
import static net.runelite.api.ObjectID.LOG_BALANCE_3933;
|
||||
import static net.runelite.api.ObjectID.LOOSE_RAILING;
|
||||
import static net.runelite.api.ObjectID.LOOSE_RAILING_2186;
|
||||
import static net.runelite.api.ObjectID.LOOSE_RAILING_28849;
|
||||
import static net.runelite.api.ObjectID.LOW_FENCE;
|
||||
import static net.runelite.api.ObjectID.MONKEYBARS_23566;
|
||||
import static net.runelite.api.ObjectID.MONKEYBARS_23567;
|
||||
import static net.runelite.api.ObjectID.MYSTERIOUS_PIPE;
|
||||
import static net.runelite.api.ObjectID.OBSTACLE;
|
||||
import static net.runelite.api.ObjectID.OBSTACLE_30767;
|
||||
import static net.runelite.api.ObjectID.OBSTACLE_30962;
|
||||
import static net.runelite.api.ObjectID.OBSTACLE_30964;
|
||||
import static net.runelite.api.ObjectID.OBSTACLE_PIPE_16509;
|
||||
import static net.runelite.api.ObjectID.OBSTACLE_PIPE_16511;
|
||||
import static net.runelite.api.ObjectID.OBSTACLE_PIPE_23140;
|
||||
import static net.runelite.api.ObjectID.ORNATE_RAILING;
|
||||
import static net.runelite.api.ObjectID.ORNATE_RAILING_17000;
|
||||
import static net.runelite.api.ObjectID.PILE_OF_RUBBLE_23563;
|
||||
import static net.runelite.api.ObjectID.PILE_OF_RUBBLE_23564;
|
||||
import static net.runelite.api.ObjectID.PILLAR_31561;
|
||||
import static net.runelite.api.ObjectID.PILLAR_31809;
|
||||
import static net.runelite.api.ObjectID.PIPE_21727;
|
||||
import static net.runelite.api.ObjectID.PIPE_21728;
|
||||
import static net.runelite.api.ObjectID.ROCKS;
|
||||
import static net.runelite.api.ObjectID.ROCKSLIDE_33184;
|
||||
import static net.runelite.api.ObjectID.ROCKSLIDE_33185;
|
||||
import static net.runelite.api.ObjectID.ROCKSLIDE_33191;
|
||||
import static net.runelite.api.ObjectID.ROCKS_14106;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16464;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16514;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16515;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16521;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16522;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16523;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16524;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16534;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16535;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16545;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16549;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16550;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16998;
|
||||
import static net.runelite.api.ObjectID.ROCKS_16999;
|
||||
import static net.runelite.api.ObjectID.ROCKS_17042;
|
||||
import static net.runelite.api.ObjectID.ROCKS_19849;
|
||||
import static net.runelite.api.ObjectID.ROCKS_2231;
|
||||
import static net.runelite.api.ObjectID.ROCKS_27984;
|
||||
import static net.runelite.api.ObjectID.ROCKS_27985;
|
||||
import static net.runelite.api.ObjectID.ROCKS_27987;
|
||||
import static net.runelite.api.ObjectID.ROCKS_27988;
|
||||
import static net.runelite.api.ObjectID.ROCKS_31757;
|
||||
import static net.runelite.api.ObjectID.ROCKS_31758;
|
||||
import static net.runelite.api.ObjectID.ROCKS_31759;
|
||||
import static net.runelite.api.ObjectID.ROCKS_34396;
|
||||
import static net.runelite.api.ObjectID.ROCKS_34397;
|
||||
import static net.runelite.api.ObjectID.ROCKS_34741;
|
||||
import static net.runelite.api.ObjectID.ROCKS_3748;
|
||||
import static net.runelite.api.ObjectID.ROCKS_3790;
|
||||
import static net.runelite.api.ObjectID.ROCKS_3791;
|
||||
import static net.runelite.api.ObjectID.ROCKS_3803;
|
||||
import static net.runelite.api.ObjectID.ROCKS_3804;
|
||||
import static net.runelite.api.ObjectID.ROCKS_6673;
|
||||
import static net.runelite.api.ObjectID.ROCKY_HANDHOLDS_26400;
|
||||
import static net.runelite.api.ObjectID.ROCKY_HANDHOLDS_26401;
|
||||
import static net.runelite.api.ObjectID.ROCKY_HANDHOLDS_26402;
|
||||
import static net.runelite.api.ObjectID.ROCKY_HANDHOLDS_26404;
|
||||
import static net.runelite.api.ObjectID.ROCKY_HANDHOLDS_26405;
|
||||
import static net.runelite.api.ObjectID.ROCKY_HANDHOLDS_26406;
|
||||
import static net.runelite.api.ObjectID.ROCK_16115;
|
||||
import static net.runelite.api.ObjectID.ROPESWING_23568;
|
||||
import static net.runelite.api.ObjectID.ROPESWING_23569;
|
||||
import static net.runelite.api.ObjectID.ROPE_ANCHOR;
|
||||
import static net.runelite.api.ObjectID.ROPE_ANCHOR_30917;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21306;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21307;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21308;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21309;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21310;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21311;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21312;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21313;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21314;
|
||||
import static net.runelite.api.ObjectID.ROPE_BRIDGE_21315;
|
||||
import static net.runelite.api.ObjectID.RUBBER_CAP_MUSHROOM;
|
||||
import static net.runelite.api.ObjectID.SPIKEY_CHAIN;
|
||||
import static net.runelite.api.ObjectID.SPIKEY_CHAIN_16538;
|
||||
import static net.runelite.api.ObjectID.STAIRS_31485;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONES;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONES_23646;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONES_23647;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_10663;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_11768;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_13504;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_14917;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_14918;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_16466;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_16513;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_16533;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_19040;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_19042;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_21738;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_21739;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_29728;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_29729;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_29730;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_5948;
|
||||
import static net.runelite.api.ObjectID.STEPPING_STONE_5949;
|
||||
import static net.runelite.api.ObjectID.STEPS;
|
||||
import static net.runelite.api.ObjectID.STEPS_29993;
|
||||
import static net.runelite.api.ObjectID.STICKS;
|
||||
import static net.runelite.api.ObjectID.STILE;
|
||||
import static net.runelite.api.ObjectID.STILE_12982;
|
||||
import static net.runelite.api.ObjectID.STRANGE_FLOOR;
|
||||
import static net.runelite.api.ObjectID.STRANGE_FLOOR_16544;
|
||||
import static net.runelite.api.ObjectID.STRONG_TREE_17074;
|
||||
import static net.runelite.api.ObjectID.TIGHTGAP;
|
||||
import static net.runelite.api.ObjectID.TRELLIS_20056;
|
||||
import static net.runelite.api.ObjectID.TRIPWIRE;
|
||||
import static net.runelite.api.ObjectID.TUNNEL_30174;
|
||||
import static net.runelite.api.ObjectID.TUNNEL_30175;
|
||||
import static net.runelite.api.ObjectID.TUNNEL_30959;
|
||||
import static net.runelite.api.ObjectID.UNDERWALL_TUNNEL;
|
||||
import static net.runelite.api.ObjectID.UNDERWALL_TUNNEL_16528;
|
||||
import static net.runelite.api.ObjectID.UNDERWALL_TUNNEL_16529;
|
||||
import static net.runelite.api.ObjectID.UNDERWALL_TUNNEL_16530;
|
||||
import static net.runelite.api.ObjectID.UNDERWALL_TUNNEL_19032;
|
||||
import static net.runelite.api.ObjectID.UNDERWALL_TUNNEL_19036;
|
||||
import static net.runelite.api.ObjectID.VINE_26880;
|
||||
import static net.runelite.api.ObjectID.VINE_26882;
|
||||
import static net.runelite.api.ObjectID.WALL_17047;
|
||||
import static net.runelite.api.ObjectID.WALL_17049;
|
||||
import static net.runelite.api.ObjectID.WALL_17050;
|
||||
import static net.runelite.api.ObjectID.WEATHERED_WALL;
|
||||
import static net.runelite.api.ObjectID.WEATHERED_WALL_16526;
|
||||
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,
|
||||
// Tree Gnome Village
|
||||
LOOSE_RAILING_2186,
|
||||
// Burgh de Rott
|
||||
LOW_FENCE,
|
||||
// Taverley
|
||||
STILE,
|
||||
// Asgarnian Ice Dungeon
|
||||
STEPS,
|
||||
// Fossil Island Wyvern Cave
|
||||
STAIRS_31485),
|
||||
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),
|
||||
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),
|
||||
KARAMJA_MOSS_GIANT_SWING(10, "Rope", null, ROPESWING_23568, ROPESWING_23569),
|
||||
FALADOR_GRAPPLE_WALL(11, "Grapple Wall", new WorldPoint(3031, 3391, 0), WALL_17049, WALL_17050),
|
||||
BRIMHAVEN_DUNGEON_STEPPING_STONES(12, "Stepping Stones", null, STEPPING_STONE_21738),
|
||||
VARROCK_SOUTH_FENCE(13, "Fence", new WorldPoint(3239, 3334, 0), FENCE_16518),
|
||||
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
|
||||
YANILLE_UNDERWALL_TUNNEL(16, "Underwall Tunnel", new WorldPoint(2574, 3109, 0), HOLE_16520, CASTLE_WALL),
|
||||
YANILLE_WATCHTOWER_TRELLIS(18, "Trellis", null, TRELLIS_20056),
|
||||
COAL_TRUCKS_LOG_BALANCE(20, "Log Balance", new WorldPoint(2598, 3475, 0), LOG_BALANCE_23274),
|
||||
GRAND_EXCHANGE_UNDERWALL_TUNNEL(21, "Underwall Tunnel", new WorldPoint(3139, 3515, 0), UNDERWALL_TUNNEL_16529, UNDERWALL_TUNNEL_16530),
|
||||
BRIMHAVEN_DUNGEON_PIPE(22, "Pipe Squeeze", new WorldPoint(2654, 9569, 0), PIPE_21728),
|
||||
OBSERVATORY_SCALE_CLIFF(23, "Grapple Rocks", new WorldPoint(2447, 3155, 0), NULL_31849),
|
||||
EAGLES_PEAK_ROCK_CLIMB(25, "Rock Climb", new WorldPoint(2320, 3499, 0), ROCKS_19849),
|
||||
FALADOR_UNDERWALL_TUNNEL(26, "Underwall Tunnel", new WorldPoint(2947, 3313, 0), UNDERWALL_TUNNEL, UNDERWALL_TUNNEL_16528),
|
||||
MOUNT_KARUULM_LOWER(29, "Rocks", new WorldPoint(1324, 3782, 0), ROCKS_34397),
|
||||
CORSAIR_COVE_RESOURCE_ROCKS(30, "Rocks", new WorldPoint(2486, 2898, 0), ROCKS_31758, ROCKS_31759),
|
||||
SOUTHEAST_KARAJMA_STEPPING_STONES(30, "Stepping Stones", new WorldPoint(2924, 2946, 0), STEPPING_STONES, STEPPING_STONES_23646, STEPPING_STONES_23647),
|
||||
BRIMHAVEN_DUNGEON_LOG_BALANCE(30, "Log Balance", null, LOG_BALANCE_20882),
|
||||
AGILITY_PYRAMID_ROCKS_EAST(30, "Rocks", null, CLIMBING_ROCKS_11949),
|
||||
DRAYNOR_MANOR_STEPPING_STONES(31, "Stepping Stones", new WorldPoint(3150, 3362, 0), STEPPING_STONE_16533),
|
||||
CATHERBY_CLIFFSIDE_GRAPPLE(32, "Grapple Rock", new WorldPoint(2868, 3429, 0), ROCKS_17042),
|
||||
CAIRN_ISLE_ROCKS(32, "Rocks", null, ROCKS_2231),
|
||||
ARDOUGNE_LOG_BALANCE(33, "Log Balance", new WorldPoint(2602, 3336, 0), LOG_BALANCE_16546, LOG_BALANCE_16547, LOG_BALANCE_16548),
|
||||
BRIMHAVEN_DUNGEON_MEDIUM_PIPE(34, "Pipe Squeeze", null, new WorldPoint(2698, 9501, 0), PIPE_21727),
|
||||
CATHERBY_OBELISK_GRAPPLE(36, "Grapple Rock", new WorldPoint(2841, 3434, 0), CROSSBOW_TREE_17062),
|
||||
GNOME_STRONGHOLD_ROCKS(37, "Rocks", new WorldPoint(2485, 3515, 0), ROCKS_16534, ROCKS_16535),
|
||||
AL_KHARID_MINING_PITCLIFF_SCRAMBLE(38, "Rocks", new WorldPoint(3305, 3315, 0), ROCKS_16549, ROCKS_16550),
|
||||
YANILLE_WALL_GRAPPLE(39, "Grapple Wall", new WorldPoint(2552, 3072, 0), WALL_17047),
|
||||
NEITIZNOT_BRIDGE_REPAIR(40, "Bridge Repair - Quest", new WorldPoint(2315, 3828, 0), ROPE_BRIDGE_21306, ROPE_BRIDGE_21307),
|
||||
NEITIZNOT_BRIDGE_SOUTHEAST(40, "Rope Bridge", null, ROPE_BRIDGE_21308, ROPE_BRIDGE_21309),
|
||||
NEITIZNOT_BRIDGE_NORTHWEST(40, "Rope Bridge", null, ROPE_BRIDGE_21310, ROPE_BRIDGE_21311),
|
||||
NEITIZNOT_BRIDGE_NORTH(40, "Rope Bridge", null, ROPE_BRIDGE_21312, ROPE_BRIDGE_21313),
|
||||
NEITIZNOT_BRIDGE_NORTHEAST(40, "Broken Rope bridge", null, ROPE_BRIDGE_21314, ROPE_BRIDGE_21315),
|
||||
KOUREND_LAKE_JUMP_EAST(40, "Stepping Stones", new WorldPoint(1612, 3570, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
|
||||
KOUREND_LAKE_JUMP_WEST(40, "Stepping Stones", new WorldPoint(1604, 3572, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
|
||||
YANILLE_DUNGEON_BALANCE(40, "Balancing Ledge", null, BALANCING_LEDGE_23548),
|
||||
TROLLHEIM_EASY_CLIFF_SCRAMBLE(41, "Rocks", new WorldPoint(2869, 3670, 0), ROCKS_16521),
|
||||
DWARVEN_MINE_NARROW_CREVICE(42, "Narrow Crevice", new WorldPoint(3034, 9806, 0), CREVICE_16543),
|
||||
DRAYNOR_UNDERWALL_TUNNEL(42, "Underwall Tunnel", new WorldPoint(3068, 3261, 0), UNDERWALL_TUNNEL_19032, UNDERWALL_TUNNEL_19036),
|
||||
TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_NORTH(43, "Rocks", new WorldPoint(2886, 3684, 0), ROCKS_3803, ROCKS_3804, ROCKS_16522),
|
||||
TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_SOUTH(43, "Rocks", new WorldPoint(2876, 3666, 0), ROCKS_3803, ROCKS_3804, ROCKS_16522),
|
||||
TROLLHEIM_ADVANCED_CLIFF_SCRAMBLE(44, "Rocks", new WorldPoint(2907, 3686, 0), ROCKS_16523, ROCKS_3748),
|
||||
KOUREND_RIVER_STEPPING_STONES(45, "Stepping Stones", new WorldPoint(1721, 3509, 0), STEPPING_STONE_29728),
|
||||
TIRANNWN_LOG_BALANCE(45, "Log Balance", null, LOG_BALANCE_3933, LOG_BALANCE_3931, LOG_BALANCE_3930, LOG_BALANCE_3929, LOG_BALANCE_3932),
|
||||
COSMIC_ALTAR_MEDIUM_WALKWAY(46, "Narrow Walkway", new WorldPoint(2399, 4403, 0), JUTTING_WALL_17002),
|
||||
DEEP_WILDERNESS_DUNGEON_CREVICE_NORTH(46, "Narrow Crevice", new WorldPoint(3047, 10335, 0), CREVICE_19043),
|
||||
DEEP_WILDERNESS_DUNGEON_CREVICE_SOUTH(46, "Narrow Crevice", new WorldPoint(3045, 10327, 0), CREVICE_19043),
|
||||
TROLLHEIM_HARD_CLIFF_SCRAMBLE(47, "Rocks", new WorldPoint(2902, 3680, 0), ROCKS_16524),
|
||||
FREMENNIK_LOG_BALANCE(48, "Log Balance", new WorldPoint(2721, 3591, 0), LOG_BALANCE_16540, LOG_BALANCE_16541, LOG_BALANCE_16542),
|
||||
YANILLE_DUNGEON_PIPE_SQUEEZE(49, "Pipe Squeeze", null, OBSTACLE_PIPE_23140),
|
||||
ARCEUUS_ESSENCE_MINE_BOULDER(49, "Boulder", new WorldPoint(1774, 3888, 0), BOULDER_27990),
|
||||
MORYTANIA_STEPPING_STONE(50, "Stepping Stone", new WorldPoint(3418, 3326, 0), STEPPING_STONE_13504),
|
||||
VARROCK_SEWERS_PIPE_SQUEEZE(51, "Pipe Squeeze", new WorldPoint(3152, 9905, 0), OBSTACLE_PIPE_16511),
|
||||
ARCEUUS_ESSENCE_MINE_EAST_SCRAMBLE(52, "Rock Climb", new WorldPoint(1770, 3851, 0), ROCKS_27987, ROCKS_27988),
|
||||
KARAMJA_VOLCANO_GRAPPLE_NORTH(53, "Grapple Rock", new WorldPoint(2873, 3143, 0), STRONG_TREE_17074),
|
||||
KARAMJA_VOLCANO_GRAPPLE_SOUTH(53, "Grapple Rock", new WorldPoint(2874, 3128, 0), STRONG_TREE_17074),
|
||||
MOTHERLODE_MINE_WALL_EAST(54, "Wall", new WorldPoint(3124, 9703, 0), DARK_TUNNEL_10047),
|
||||
MOTHERLODE_MINE_WALL_WEST(54, "Wall", new WorldPoint(3118, 9702, 0), DARK_TUNNEL_10047),
|
||||
MISCELLANIA_DOCK_STEPPING_STONE(55, "Stepping Stone", new WorldPoint(2572, 3862, 0), STEPPING_STONE_11768),
|
||||
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),
|
||||
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),
|
||||
ELVEN_OVERPASS_CLIFF_SCRAMBLE(59, "Rocks", new WorldPoint(2345, 3300, 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),
|
||||
WILDERNESS_GWD_CLIMB_WEST(60, "Rocks", new WorldPoint(2928, 3760, 0), ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406),
|
||||
MOS_LEHARMLESS_STEPPING_STONE(60, "Stepping Stone", new WorldPoint(3710, 2970, 0), STEPPING_STONE_19042),
|
||||
WINTERTODT_GAP(60, "Gap", new WorldPoint(1629, 4023, 0), GAP_29326),
|
||||
UNGAEL_ICE(60, "Ice Chunks", null, NULL_25337, NULL_29868, NULL_29869, NULL_29870, ICE_CHUNKS_31822, NULL_31823, ICE_CHUNKS_31990),
|
||||
SLAYER_TOWER_MEDIUM_CHAIN_FIRST(61, "Spiked Chain (Floor 1)", new WorldPoint(3421, 3550, 0), SPIKEY_CHAIN),
|
||||
SLAYER_TOWER_MEDIUM_CHAIN_SECOND(61, "Spiked Chain (Floor 2)", new WorldPoint(3420, 3551, 0), SPIKEY_CHAIN_16538),
|
||||
SLAYER_DUNGEON_CREVICE(62, "Narrow Crevice", new WorldPoint(2729, 10008, 0), CREVICE_16539),
|
||||
MOUNT_KARUULM_UPPER(62, "Rocks", new WorldPoint(1322, 3791, 0), ROCKS_34396),
|
||||
TAVERLEY_DUNGEON_RAILING(63, "Loose Railing", new WorldPoint(2935, 9811, 0), LOOSE_RAILING_28849),
|
||||
TROLLHEIM_WILDERNESS_ROCKS_EAST(64, "Rocks", new WorldPoint(2945, 3678, 0), ROCKS_16545),
|
||||
TROLLHEIM_WILDERNESS_ROCKS_WEST(64, "Rocks", new WorldPoint(2917, 3672, 0), ROCKS_16545),
|
||||
FOSSIL_ISLAND_VOLCANO(64, "Rope", new WorldPoint(3780, 3822, 0), ROPE_ANCHOR, ROPE_ANCHOR_30917),
|
||||
MORYTANIA_TEMPLE(65, "Loose Railing", new WorldPoint(3422, 3476, 0), ROCKS_16998, ROCKS_16999, ORNATE_RAILING, ORNATE_RAILING_17000),
|
||||
REVENANT_CAVES_GREEN_DRAGONS(65, "Jump", new WorldPoint(3220, 10086, 0), PILLAR_31561),
|
||||
COSMIC_ALTAR_ADVANCED_WALKWAY(66, "Narrow Walkway", new WorldPoint(2408, 4401, 0), JUTTING_WALL_17002),
|
||||
LUMBRIDGE_DESERT_STEPPING_STONE(66, "Stepping Stone", new WorldPoint(3210, 3135, 0), STEPPING_STONE_16513),
|
||||
HEROES_GUILD_TUNNEL_EAST(67, "Crevice", new WorldPoint(2898, 9901, 0), CREVICE_9739, CREVICE_9740),
|
||||
HEROES_GUILD_TUNNEL_WEST(67, "Crevice", new WorldPoint(2913, 9895, 0), CREVICE_9739, CREVICE_9740),
|
||||
YANILLE_DUNGEON_RUBBLE_CLIMB(67, "Pile of Rubble", null, PILE_OF_RUBBLE_23563, PILE_OF_RUBBLE_23564),
|
||||
ELVEN_OVERPASS_MEDIUM_CLIFF(68, "Rocks", new WorldPoint(2337, 3288, 0), ROCKS_16514, ROCKS_16515),
|
||||
WEISS_OBSTACLES(68, "Shortcut", null, LITTLE_BOULDER, ROCKSLIDE_33184, ROCKSLIDE_33185, NULL_33327, NULL_33328, LEDGE_33190, ROCKSLIDE_33191, FALLEN_TREE_33192),
|
||||
ARCEUUS_ESSENSE_NORTH(69, "Rock Climb", new WorldPoint(1761, 3873, 0), ROCKS_34741),
|
||||
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(3713, 3827, 0), HOLE_31481, HOLE_31482),
|
||||
FOSSIL_ISLAND_HARDWOOD_SOUTH(70, "Hole", new WorldPoint(3715, 3817, 0), HOLE_31481, HOLE_31482),
|
||||
AL_KHARID_WINDOW(70, "Window", new WorldPoint(3293, 3158, 0), BROKEN_WALL_33344, BIG_WINDOW),
|
||||
GWD_SARADOMIN_ROPE_NORTH(70, "Rope Descent", new WorldPoint(2912, 5300, 0), NULL_26371),
|
||||
GWD_SARADOMIN_ROPE_SOUTH(70, "Rope Descent", new WorldPoint(2951, 5267, 0), NULL_26375),
|
||||
SLAYER_TOWER_ADVANCED_CHAIN_FIRST(71, "Spiked Chain (Floor 2)", new WorldPoint(3447, 3578, 0), SPIKEY_CHAIN),
|
||||
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),
|
||||
LAVA_DRAGON_ISLE_JUMP(74, "Stepping Stone", new WorldPoint(3200, 3807, 0), STEPPING_STONE_14918),
|
||||
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),
|
||||
KHARAZI_JUNGLE_VINE_CLIMB(79, "Vine", new WorldPoint(2897, 2939, 0), NULL_26884, NULL_26886),
|
||||
TAVERLEY_DUNGEON_SPIKED_BLADES(80, "Strange Floor", new WorldPoint(2877, 9813, 0), STRANGE_FLOOR),
|
||||
SLAYER_DUNGEON_CHASM_JUMP(81, "Spiked Blades", new WorldPoint(2770, 10003, 0), STRANGE_FLOOR_16544),
|
||||
LAVA_MAZE_NORTH_JUMP(82, "Stepping Stone", new WorldPoint(3092, 3880, 0), STEPPING_STONE_14917),
|
||||
BRIMHAVEN_DUNGEON_EAST_STEPPING_STONES_NORTH(83, "Stepping Stones", new WorldPoint(2685, 9547, 0), STEPPING_STONE_19040),
|
||||
BRIMHAVEN_DUNGEON_EAST_STEPPING_STONES_SOUTH(83, "Stepping Stones", new WorldPoint(2693, 9529, 0), STEPPING_STONE_19040),
|
||||
ELVEN_ADVANCED_CLIFF_SCRAMBLE(85, "Rocks", new WorldPoint(2337, 3253, 0), ROCKS_16514, ROCKS_16514),
|
||||
KALPHITE_WALL(86, "Crevice", new WorldPoint(3214, 9508, 0), CREVICE_16465),
|
||||
BRIMHAVEN_DUNGEON_VINE_EAST(87, "Vine", new WorldPoint(2672, 9582, 0), VINE_26880, VINE_26882),
|
||||
BRIMHAVEN_DUNGEON_VINE_WEST(87, "Vine", new WorldPoint(2606, 9584, 0), VINE_26880, VINE_26882),
|
||||
MOUNT_KARUULM_PIPE_SOUTH(88, "Pipe", new WorldPoint(1316, 10214, 0), MYSTERIOUS_PIPE),
|
||||
MOUNT_KARUULM_PIPE_NORTH(88, "Pipe", new WorldPoint(1346, 10231, 0), MYSTERIOUS_PIPE),
|
||||
REVENANT_CAVES_CHAMBER_JUMP(89, "Jump", new WorldPoint(3240, 10144, 0), PILLAR_31561);
|
||||
|
||||
/**
|
||||
* The agility level required to pass the shortcut
|
||||
*/
|
||||
@Getter
|
||||
private final int level;
|
||||
/**
|
||||
* Brief description of the shortcut (e.g. 'Rocks', 'Stepping Stones', 'Jump')
|
||||
*/
|
||||
@Getter
|
||||
private final String description;
|
||||
/**
|
||||
* The location of the Shortcut icon on the world map (null if there is no icon)
|
||||
*/
|
||||
@Getter
|
||||
private final WorldPoint worldMapLocation;
|
||||
/**
|
||||
* An optional location in case the location of the shortcut icon is either
|
||||
* null or isn't close enough to the obstacle
|
||||
*/
|
||||
@Getter
|
||||
private final WorldPoint worldLocation;
|
||||
/**
|
||||
* Array of obstacles, null objects, decorations etc. that this shortcut uses.
|
||||
* Typically an ObjectID/NullObjectID
|
||||
*/
|
||||
@Getter
|
||||
private final int[] obstacleIds;
|
||||
|
||||
AgilityShortcut(int level, String description, WorldPoint mapLocation, WorldPoint worldLocation, int... obstacleIds)
|
||||
{
|
||||
this.level = level;
|
||||
this.description = description;
|
||||
this.worldMapLocation = mapLocation;
|
||||
this.worldLocation = worldLocation;
|
||||
this.obstacleIds = obstacleIds;
|
||||
}
|
||||
|
||||
AgilityShortcut(int level, String description, WorldPoint location, int... obstacleIds)
|
||||
{
|
||||
this(level, description, location, location, obstacleIds);
|
||||
}
|
||||
|
||||
public String getTooltip()
|
||||
{
|
||||
return description + " - Level " + level;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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.game;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
|
||||
public class AsyncBufferedImage extends BufferedImage
|
||||
{
|
||||
private final List<Runnable> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
public AsyncBufferedImage(int width, int height, int imageType)
|
||||
{
|
||||
super(width, height, imageType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when the buffer has been changed
|
||||
*/
|
||||
public void changed()
|
||||
{
|
||||
for (Runnable r : listeners)
|
||||
{
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a function to be ran when the buffer has changed
|
||||
*/
|
||||
public void onChanged(Runnable r)
|
||||
{
|
||||
listeners.add(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls setIcon on c, ensuring it is repainted when this changes
|
||||
*/
|
||||
public void addTo(JButton c)
|
||||
{
|
||||
c.setIcon(makeIcon(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls setIcon on c, ensuring it is repainted when this changes
|
||||
*/
|
||||
public void addTo(JLabel c)
|
||||
{
|
||||
c.setIcon(makeIcon(c));
|
||||
}
|
||||
|
||||
private ImageIcon makeIcon(JComponent c)
|
||||
{
|
||||
listeners.add(c::repaint);
|
||||
return new ImageIcon(this);
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* 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.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import net.runelite.api.ClanMember;
|
||||
import net.runelite.api.ClanMemberRank;
|
||||
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.ClanChanged;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@Singleton
|
||||
public class ClanManager
|
||||
{
|
||||
private static final int[] CLANCHAT_IMAGES =
|
||||
{
|
||||
SpriteID.CLAN_CHAT_RANK_SMILEY_FRIEND,
|
||||
SpriteID.CLAN_CHAT_RANK_SINGLE_CHEVRON_RECRUIT,
|
||||
SpriteID.CLAN_CHAT_RANK_DOUBLE_CHEVRON_CORPORAL,
|
||||
SpriteID.CLAN_CHAT_RANK_TRIPLE_CHEVRON_SERGEANT,
|
||||
SpriteID.CLAN_CHAT_RANK_BRONZE_STAR_LIEUTENANT,
|
||||
SpriteID.CLAN_CHAT_RANK_SILVER_STAR_CAPTAIN,
|
||||
SpriteID.CLAN_CHAT_RANK_GOLD_STAR_GENERAL,
|
||||
SpriteID.CLAN_CHAT_RANK_KEY_CHANNEL_OWNER,
|
||||
SpriteID.CLAN_CHAT_RANK_CROWN_JAGEX_MODERATOR,
|
||||
};
|
||||
private static final Dimension CLANCHAT_IMAGE_DIMENSION = new Dimension(11, 11);
|
||||
private static final Color CLANCHAT_IMAGE_OUTLINE_COLOR = new Color(33, 33, 33);
|
||||
|
||||
private final Client client;
|
||||
private final SpriteManager spriteManager;
|
||||
private final BufferedImage[] clanChatImages = new BufferedImage[CLANCHAT_IMAGES.length];
|
||||
|
||||
private final LoadingCache<String, ClanMemberRank> clanRanksCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(100)
|
||||
.expireAfterWrite(1, TimeUnit.MINUTES)
|
||||
.build(new CacheLoader<String, ClanMemberRank>()
|
||||
{
|
||||
@Override
|
||||
public ClanMemberRank load(@Nonnull String key)
|
||||
{
|
||||
final ClanMember[] clanMembersArr = client.getClanMembers();
|
||||
|
||||
if (clanMembersArr == null || clanMembersArr.length == 0)
|
||||
{
|
||||
return ClanMemberRank.UNRANKED;
|
||||
}
|
||||
|
||||
return Arrays.stream(clanMembersArr)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(clanMember -> sanitize(clanMember.getUsername()).equals(sanitize(key)))
|
||||
.map(ClanMember::getRank)
|
||||
.findAny()
|
||||
.orElse(ClanMemberRank.UNRANKED);
|
||||
}
|
||||
});
|
||||
|
||||
private int modIconsLength;
|
||||
|
||||
@Inject
|
||||
private ClanManager(Client client, SpriteManager spriteManager)
|
||||
{
|
||||
this.client = client;
|
||||
this.spriteManager = spriteManager;
|
||||
}
|
||||
|
||||
public ClanMemberRank getRank(String playerName)
|
||||
{
|
||||
return clanRanksCache.getUnchecked(playerName);
|
||||
}
|
||||
|
||||
public BufferedImage getClanImage(final ClanMemberRank clanMemberRank)
|
||||
{
|
||||
if (clanMemberRank == ClanMemberRank.UNRANKED)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return clanChatImages[clanMemberRank.ordinal() - 1];
|
||||
}
|
||||
|
||||
public int getIconNumber(final ClanMemberRank clanMemberRank)
|
||||
{
|
||||
return modIconsLength - CLANCHAT_IMAGES.length + clanMemberRank.ordinal() - 1;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||
{
|
||||
if (gameStateChanged.getGameState() == GameState.LOGGED_IN
|
||||
&& modIconsLength == 0)
|
||||
{
|
||||
loadClanChatIcons();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onClanChanged(ClanChanged clanChanged)
|
||||
{
|
||||
clanRanksCache.invalidateAll();
|
||||
}
|
||||
|
||||
private void loadClanChatIcons()
|
||||
{
|
||||
final IndexedSprite[] modIcons = client.getModIcons();
|
||||
final IndexedSprite[] newModIcons = Arrays.copyOf(modIcons, modIcons.length + CLANCHAT_IMAGES.length);
|
||||
int curPosition = newModIcons.length - CLANCHAT_IMAGES.length;
|
||||
|
||||
for (int i = 0; i < CLANCHAT_IMAGES.length; i++, curPosition++)
|
||||
{
|
||||
final int resource = CLANCHAT_IMAGES[i];
|
||||
clanChatImages[i] = clanChatImageFromSprite(spriteManager.getSprite(resource, 0));
|
||||
newModIcons[curPosition] = ImageUtil.getImageIndexedSprite(clanChatImages[i], client);
|
||||
}
|
||||
|
||||
client.setModIcons(newModIcons);
|
||||
modIconsLength = newModIcons.length;
|
||||
}
|
||||
|
||||
private static String sanitize(String lookup)
|
||||
{
|
||||
final String cleaned = Text.removeTags(lookup);
|
||||
return cleaned.replace('\u00A0', ' ');
|
||||
}
|
||||
|
||||
private static BufferedImage clanChatImageFromSprite(final BufferedImage clanSprite)
|
||||
{
|
||||
final BufferedImage clanChatCanvas = ImageUtil.resizeCanvas(clanSprite, CLANCHAT_IMAGE_DIMENSION.width, CLANCHAT_IMAGE_DIMENSION.height);
|
||||
return ImageUtil.outlineImage(clanChatCanvas, CLANCHAT_IMAGE_OUTLINE_COLOR);
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* 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.cache.CacheLoader;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import static net.runelite.client.game.HiscoreManager.EMPTY;
|
||||
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;
|
||||
|
||||
@Slf4j
|
||||
class HiscoreLoader extends CacheLoader<HiscoreManager.HiscoreKey, HiscoreResult>
|
||||
{
|
||||
private final ListeningExecutorService executorService;
|
||||
private final HiscoreClient hiscoreClient;
|
||||
|
||||
HiscoreLoader(ScheduledExecutorService executor, HiscoreClient client)
|
||||
{
|
||||
this.executorService = MoreExecutors.listeningDecorator(executor);
|
||||
this.hiscoreClient = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HiscoreResult load(HiscoreManager.HiscoreKey hiscoreKey) throws Exception
|
||||
{
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<HiscoreResult> reload(HiscoreManager.HiscoreKey hiscoreKey, HiscoreResult oldValue)
|
||||
{
|
||||
log.debug("Submitting hiscore lookup for {} type {}", hiscoreKey.getUsername(), hiscoreKey.getType());
|
||||
|
||||
return executorService.submit(() -> fetch(hiscoreKey));
|
||||
}
|
||||
|
||||
private HiscoreResult fetch(HiscoreManager.HiscoreKey hiscoreKey)
|
||||
{
|
||||
String username = hiscoreKey.getUsername();
|
||||
HiscoreEndpoint endpoint = hiscoreKey.getType();
|
||||
|
||||
try
|
||||
{
|
||||
HiscoreResult result = hiscoreClient.lookup(username, endpoint);
|
||||
if (result == null)
|
||||
{
|
||||
return NONE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("Unable to look up hiscore!", ex);
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* 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.cache.CacheBuilder;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.http.api.hiscore.HiscoreClient;
|
||||
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
||||
import net.runelite.http.api.hiscore.HiscoreResult;
|
||||
|
||||
@Singleton
|
||||
public class HiscoreManager
|
||||
{
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
static class HiscoreKey
|
||||
{
|
||||
String username;
|
||||
HiscoreEndpoint type;
|
||||
}
|
||||
|
||||
static final HiscoreResult EMPTY = new HiscoreResult();
|
||||
static final HiscoreResult NONE = new HiscoreResult();
|
||||
|
||||
private final HiscoreClient hiscoreClient = new HiscoreClient();
|
||||
private final LoadingCache<HiscoreKey, HiscoreResult> hiscoreCache;
|
||||
|
||||
@Inject
|
||||
public HiscoreManager(Client client, ScheduledExecutorService executor, ClientThread clientThread)
|
||||
{
|
||||
hiscoreCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(128L)
|
||||
.expireAfterWrite(1, TimeUnit.HOURS)
|
||||
.build(new HiscoreLoader(executor, hiscoreClient));
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously look up a players hiscore from a specified endpoint
|
||||
*
|
||||
* @param username Players username
|
||||
* @param endpoint Hiscore endpoint
|
||||
* @return HiscoreResult or null
|
||||
* @throws IOException Upon error in fetching hiscore
|
||||
*/
|
||||
public HiscoreResult lookup(String username, HiscoreEndpoint endpoint) throws IOException
|
||||
{
|
||||
HiscoreKey hiscoreKey = new HiscoreKey(username, endpoint);
|
||||
HiscoreResult hiscoreResult = hiscoreCache.getIfPresent(hiscoreKey);
|
||||
if (hiscoreResult != null && hiscoreResult != EMPTY)
|
||||
{
|
||||
return hiscoreResult == NONE ? null : hiscoreResult;
|
||||
}
|
||||
|
||||
hiscoreResult = hiscoreClient.lookup(username, endpoint);
|
||||
if (hiscoreResult == null)
|
||||
{
|
||||
hiscoreCache.put(hiscoreKey, NONE);
|
||||
return null;
|
||||
}
|
||||
|
||||
hiscoreCache.put(hiscoreKey, hiscoreResult);
|
||||
return hiscoreResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously look up a players hiscore from a specified endpoint
|
||||
*
|
||||
* @param username Players username
|
||||
* @param endpoint Hiscore endpoint
|
||||
* @return HiscoreResult or null
|
||||
*/
|
||||
public HiscoreResult lookupAsync(String username, HiscoreEndpoint endpoint)
|
||||
{
|
||||
HiscoreKey hiscoreKey = new HiscoreKey(username, endpoint);
|
||||
HiscoreResult hiscoreResult = hiscoreCache.getIfPresent(hiscoreKey);
|
||||
if (hiscoreResult != null && hiscoreResult != EMPTY)
|
||||
{
|
||||
return hiscoreResult == NONE ? null : hiscoreResult;
|
||||
}
|
||||
|
||||
hiscoreCache.refresh(hiscoreKey);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,615 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.game;
|
||||
|
||||
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 java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.Value;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import static net.runelite.api.Constants.CLIENT_DEFAULT_ZOOM;
|
||||
import static net.runelite.api.Constants.HIGH_ALCHEMY_CONSTANT;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.api.ItemID;
|
||||
import static net.runelite.api.ItemID.AGILITY_CAPE;
|
||||
import static net.runelite.api.ItemID.AGILITY_CAPET;
|
||||
import static net.runelite.api.ItemID.AGILITY_CAPET_13341;
|
||||
import static net.runelite.api.ItemID.AGILITY_CAPE_13340;
|
||||
import static net.runelite.api.ItemID.BOOTS_OF_LIGHTNESS;
|
||||
import static net.runelite.api.ItemID.BOOTS_OF_LIGHTNESS_89;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_11861;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13589;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13590;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13601;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13602;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13613;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13614;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13625;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13626;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13637;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13638;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13677;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13678;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_21076;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_21078;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_11853;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13581;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13582;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13593;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13594;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13605;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13606;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13617;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13618;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13629;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13630;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13669;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13670;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_21064;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_CAPE_21066;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_11859;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13587;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13588;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13599;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13600;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13611;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13612;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13623;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13624;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13635;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13636;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13675;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13676;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_21073;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_21075;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_11851;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13579;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13580;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13591;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13592;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13603;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13604;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13615;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13616;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13627;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13628;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13667;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13668;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_21061;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_HOOD_21063;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_11857;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13585;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13586;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13597;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13598;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13609;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13610;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13621;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13622;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13633;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13634;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13673;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13674;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_21070;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_LEGS_21072;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_11855;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13583;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13584;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13595;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13596;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13607;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13608;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13619;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13620;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13631;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13632;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13671;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_13672;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_21067;
|
||||
import static net.runelite.api.ItemID.GRACEFUL_TOP_21069;
|
||||
import static net.runelite.api.ItemID.MAX_CAPE;
|
||||
import static net.runelite.api.ItemID.MAX_CAPE_13342;
|
||||
import static net.runelite.api.ItemID.PENANCE_GLOVES;
|
||||
import static net.runelite.api.ItemID.PENANCE_GLOVES_10554;
|
||||
import static net.runelite.api.ItemID.SPOTTED_CAPE;
|
||||
import static net.runelite.api.ItemID.SPOTTED_CAPE_10073;
|
||||
import static net.runelite.api.ItemID.SPOTTIER_CAPE;
|
||||
import static net.runelite.api.ItemID.SPOTTIER_CAPE_10074;
|
||||
import net.runelite.api.SpritePixels;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.PostItemComposition;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.http.api.item.ItemClient;
|
||||
import net.runelite.http.api.item.ItemPrice;
|
||||
import net.runelite.http.api.item.ItemStats;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class ItemManager
|
||||
{
|
||||
@Value
|
||||
private static class ImageKey
|
||||
{
|
||||
private final int itemId;
|
||||
private final int itemQuantity;
|
||||
private final boolean stackable;
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class OutlineKey
|
||||
{
|
||||
private final int itemId;
|
||||
private final int itemQuantity;
|
||||
private final Color outlineColor;
|
||||
}
|
||||
|
||||
private final Client client;
|
||||
private final ScheduledExecutorService scheduledExecutorService;
|
||||
private final ClientThread clientThread;
|
||||
|
||||
private final ItemClient itemClient = new ItemClient();
|
||||
private Map<Integer, ItemPrice> itemPrices = Collections.emptyMap();
|
||||
private Map<Integer, ItemStats> itemStats = Collections.emptyMap();
|
||||
private final LoadingCache<ImageKey, AsyncBufferedImage> itemImages;
|
||||
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
|
||||
private static final ImmutableMap<Integer, Integer> WORN_ITEMS = ImmutableMap.<Integer, Integer>builder().
|
||||
put(BOOTS_OF_LIGHTNESS_89, BOOTS_OF_LIGHTNESS).
|
||||
put(PENANCE_GLOVES_10554, PENANCE_GLOVES).
|
||||
|
||||
put(GRACEFUL_HOOD_11851, GRACEFUL_HOOD).
|
||||
put(GRACEFUL_CAPE_11853, GRACEFUL_CAPE).
|
||||
put(GRACEFUL_TOP_11855, GRACEFUL_TOP).
|
||||
put(GRACEFUL_LEGS_11857, GRACEFUL_LEGS).
|
||||
put(GRACEFUL_GLOVES_11859, GRACEFUL_GLOVES).
|
||||
put(GRACEFUL_BOOTS_11861, GRACEFUL_BOOTS).
|
||||
put(GRACEFUL_HOOD_13580, GRACEFUL_HOOD_13579).
|
||||
put(GRACEFUL_CAPE_13582, GRACEFUL_CAPE_13581).
|
||||
put(GRACEFUL_TOP_13584, GRACEFUL_TOP_13583).
|
||||
put(GRACEFUL_LEGS_13586, GRACEFUL_LEGS_13585).
|
||||
put(GRACEFUL_GLOVES_13588, GRACEFUL_GLOVES_13587).
|
||||
put(GRACEFUL_BOOTS_13590, GRACEFUL_BOOTS_13589).
|
||||
put(GRACEFUL_HOOD_13592, GRACEFUL_HOOD_13591).
|
||||
put(GRACEFUL_CAPE_13594, GRACEFUL_CAPE_13593).
|
||||
put(GRACEFUL_TOP_13596, GRACEFUL_TOP_13595).
|
||||
put(GRACEFUL_LEGS_13598, GRACEFUL_LEGS_13597).
|
||||
put(GRACEFUL_GLOVES_13600, GRACEFUL_GLOVES_13599).
|
||||
put(GRACEFUL_BOOTS_13602, GRACEFUL_BOOTS_13601).
|
||||
put(GRACEFUL_HOOD_13604, GRACEFUL_HOOD_13603).
|
||||
put(GRACEFUL_CAPE_13606, GRACEFUL_CAPE_13605).
|
||||
put(GRACEFUL_TOP_13608, GRACEFUL_TOP_13607).
|
||||
put(GRACEFUL_LEGS_13610, GRACEFUL_LEGS_13609).
|
||||
put(GRACEFUL_GLOVES_13612, GRACEFUL_GLOVES_13611).
|
||||
put(GRACEFUL_BOOTS_13614, GRACEFUL_BOOTS_13613).
|
||||
put(GRACEFUL_HOOD_13616, GRACEFUL_HOOD_13615).
|
||||
put(GRACEFUL_CAPE_13618, GRACEFUL_CAPE_13617).
|
||||
put(GRACEFUL_TOP_13620, GRACEFUL_TOP_13619).
|
||||
put(GRACEFUL_LEGS_13622, GRACEFUL_LEGS_13621).
|
||||
put(GRACEFUL_GLOVES_13624, GRACEFUL_GLOVES_13623).
|
||||
put(GRACEFUL_BOOTS_13626, GRACEFUL_BOOTS_13625).
|
||||
put(GRACEFUL_HOOD_13628, GRACEFUL_HOOD_13627).
|
||||
put(GRACEFUL_CAPE_13630, GRACEFUL_CAPE_13629).
|
||||
put(GRACEFUL_TOP_13632, GRACEFUL_TOP_13631).
|
||||
put(GRACEFUL_LEGS_13634, GRACEFUL_LEGS_13633).
|
||||
put(GRACEFUL_GLOVES_13636, GRACEFUL_GLOVES_13635).
|
||||
put(GRACEFUL_BOOTS_13638, GRACEFUL_BOOTS_13637).
|
||||
put(GRACEFUL_HOOD_13668, GRACEFUL_HOOD_13667).
|
||||
put(GRACEFUL_CAPE_13670, GRACEFUL_CAPE_13669).
|
||||
put(GRACEFUL_TOP_13672, GRACEFUL_TOP_13671).
|
||||
put(GRACEFUL_LEGS_13674, GRACEFUL_LEGS_13673).
|
||||
put(GRACEFUL_GLOVES_13676, GRACEFUL_GLOVES_13675).
|
||||
put(GRACEFUL_BOOTS_13678, GRACEFUL_BOOTS_13677).
|
||||
put(GRACEFUL_HOOD_21063, GRACEFUL_HOOD_21061).
|
||||
put(GRACEFUL_CAPE_21066, GRACEFUL_CAPE_21064).
|
||||
put(GRACEFUL_TOP_21069, GRACEFUL_TOP_21067).
|
||||
put(GRACEFUL_LEGS_21072, GRACEFUL_LEGS_21070).
|
||||
put(GRACEFUL_GLOVES_21075, GRACEFUL_GLOVES_21073).
|
||||
put(GRACEFUL_BOOTS_21078, GRACEFUL_BOOTS_21076).
|
||||
|
||||
put(MAX_CAPE_13342, MAX_CAPE).
|
||||
|
||||
put(SPOTTED_CAPE_10073, SPOTTED_CAPE).
|
||||
put(SPOTTIER_CAPE_10074, SPOTTIER_CAPE).
|
||||
|
||||
put(AGILITY_CAPET_13341, AGILITY_CAPET).
|
||||
put(AGILITY_CAPE_13340, AGILITY_CAPE).
|
||||
build();
|
||||
|
||||
@Inject
|
||||
public ItemManager(Client client, ScheduledExecutorService executor, ClientThread clientThread)
|
||||
{
|
||||
this.client = client;
|
||||
this.scheduledExecutorService = executor;
|
||||
this.clientThread = clientThread;
|
||||
|
||||
scheduledExecutorService.scheduleWithFixedDelay(this::loadPrices, 0, 30, TimeUnit.MINUTES);
|
||||
scheduledExecutorService.submit(this::loadStats);
|
||||
|
||||
itemImages = CacheBuilder.newBuilder()
|
||||
.maximumSize(128L)
|
||||
.expireAfterAccess(1, TimeUnit.HOURS)
|
||||
.build(new CacheLoader<ImageKey, AsyncBufferedImage>()
|
||||
{
|
||||
@Override
|
||||
public AsyncBufferedImage load(ImageKey key) throws Exception
|
||||
{
|
||||
return loadImage(key.itemId, key.itemQuantity, key.stackable);
|
||||
}
|
||||
});
|
||||
|
||||
itemCompositions = CacheBuilder.newBuilder()
|
||||
.maximumSize(1024L)
|
||||
.expireAfterAccess(1, TimeUnit.HOURS)
|
||||
.build(new CacheLoader<Integer, ItemComposition>()
|
||||
{
|
||||
@Override
|
||||
public ItemComposition load(Integer key) throws Exception
|
||||
{
|
||||
return client.getItemDefinition(key);
|
||||
}
|
||||
});
|
||||
|
||||
itemOutlines = CacheBuilder.newBuilder()
|
||||
.maximumSize(128L)
|
||||
.expireAfterAccess(1, TimeUnit.HOURS)
|
||||
.build(new CacheLoader<OutlineKey, BufferedImage>()
|
||||
{
|
||||
@Override
|
||||
public BufferedImage load(OutlineKey key) throws Exception
|
||||
{
|
||||
return loadItemOutline(key.itemId, key.itemQuantity, key.outlineColor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadPrices()
|
||||
{
|
||||
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()
|
||||
{
|
||||
try
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(final GameStateChanged event)
|
||||
{
|
||||
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#getItemCompositionCache()
|
||||
*/
|
||||
public void invalidateItemCompositionCache()
|
||||
{
|
||||
itemCompositions.invalidateAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up an item's price
|
||||
*
|
||||
* @param itemID item id
|
||||
* @return item price
|
||||
*/
|
||||
public int getItemPrice(int itemID)
|
||||
{
|
||||
if (itemID == ItemID.COINS_995)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (itemID == ItemID.PLATINUM_TOKEN)
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
|
||||
UntradeableItemMapping p = UntradeableItemMapping.map(ItemVariationMapping.map(itemID));
|
||||
if (p != null)
|
||||
{
|
||||
return getItemPrice(p.getPriceID()) * p.getQuantity();
|
||||
}
|
||||
|
||||
int price = 0;
|
||||
for (int mappedID : ItemMapping.map(itemID))
|
||||
{
|
||||
ItemPrice ip = itemPrices.get(mappedID);
|
||||
if (ip != null)
|
||||
{
|
||||
price += ip.getPrice();
|
||||
}
|
||||
}
|
||||
|
||||
return price;
|
||||
}
|
||||
|
||||
public int getAlchValue(ItemComposition composition)
|
||||
{
|
||||
if (composition.getId() == ItemID.COINS_995)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (composition.getId() == ItemID.PLATINUM_TOKEN)
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
|
||||
return (int) Math.max(1, composition.getPrice() * HIGH_ALCHEMY_CONSTANT);
|
||||
}
|
||||
|
||||
public int getAlchValue(int itemID)
|
||||
{
|
||||
if (itemID == ItemID.COINS_995)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (itemID == ItemID.PLATINUM_TOKEN)
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
|
||||
return (int) Math.max(1, getItemComposition(itemID).getPrice() * HIGH_ALCHEMY_CONSTANT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up an item's stats
|
||||
*
|
||||
* @param itemId item id
|
||||
* @return item stats
|
||||
*/
|
||||
@Nullable
|
||||
public ItemStats getItemStats(int itemId, boolean allowNote)
|
||||
{
|
||||
ItemComposition itemComposition = getItemComposition(itemId);
|
||||
|
||||
if (itemComposition == null || itemComposition.getName() == null || (!allowNote && itemComposition.getNote() != -1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return itemStats.get(canonicalize(itemId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for tradeable items based on item name
|
||||
*
|
||||
* @param itemName item name
|
||||
* @return
|
||||
*/
|
||||
public List<ItemPrice> search(String itemName)
|
||||
{
|
||||
itemName = itemName.toLowerCase();
|
||||
|
||||
List<ItemPrice> result = new ArrayList<>();
|
||||
for (ItemPrice itemPrice : itemPrices.values())
|
||||
{
|
||||
final String name = itemPrice.getName();
|
||||
if (name.toLowerCase().contains(itemName))
|
||||
{
|
||||
result.add(itemPrice);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up an item's composition
|
||||
*
|
||||
* @param itemId item id
|
||||
* @return item composition
|
||||
*/
|
||||
public ItemComposition getItemComposition(int itemId)
|
||||
{
|
||||
assert client.isClientThread() : "getItemComposition must be called on client thread";
|
||||
return itemCompositions.getUnchecked(itemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item's un-noted, un-placeholdered ID
|
||||
*/
|
||||
public int canonicalize(int itemID)
|
||||
{
|
||||
ItemComposition itemComposition = getItemComposition(itemID);
|
||||
|
||||
if (itemComposition.getNote() != -1)
|
||||
{
|
||||
return itemComposition.getLinkedNoteId();
|
||||
}
|
||||
|
||||
if (itemComposition.getPlaceholderTemplateId() != -1)
|
||||
{
|
||||
return itemComposition.getPlaceholderId();
|
||||
}
|
||||
|
||||
return WORN_ITEMS.getOrDefault(itemID, itemID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads item sprite from game, makes transparent, and generates image
|
||||
*
|
||||
* @param itemId
|
||||
* @return
|
||||
*/
|
||||
private AsyncBufferedImage loadImage(int itemId, int quantity, boolean stackable)
|
||||
{
|
||||
AsyncBufferedImage img = new AsyncBufferedImage(36, 32, BufferedImage.TYPE_INT_ARGB);
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
if (client.getGameState().ordinal() < GameState.LOGIN_SCREEN.ordinal())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
SpritePixels sprite = client.createItemSprite(itemId, quantity, 1, SpritePixels.DEFAULT_SHADOW_COLOR,
|
||||
stackable ? 1 : 0, false, CLIENT_DEFAULT_ZOOM);
|
||||
if (sprite == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
sprite.toBufferedImage(img);
|
||||
img.changed();
|
||||
return true;
|
||||
});
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item sprite image as BufferedImage.
|
||||
* <p>
|
||||
* This method may return immediately with a blank image if not called on the game thread.
|
||||
* The image will be filled in later. If this is used for a UI label/button, it should be added
|
||||
* using AsyncBufferedImage::addTo to ensure it is painted properly
|
||||
*
|
||||
* @param itemId
|
||||
* @return
|
||||
*/
|
||||
public AsyncBufferedImage getImage(int itemId)
|
||||
{
|
||||
return getImage(itemId, 1, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item sprite image as BufferedImage.
|
||||
* <p>
|
||||
* This method may return immediately with a blank image if not called on the game thread.
|
||||
* The image will be filled in later. If this is used for a UI label/button, it should be added
|
||||
* using AsyncBufferedImage::addTo to ensure it is painted properly
|
||||
*
|
||||
* @param itemId
|
||||
* @param quantity
|
||||
* @return
|
||||
*/
|
||||
public AsyncBufferedImage getImage(int itemId, int quantity, boolean stackable)
|
||||
{
|
||||
try
|
||||
{
|
||||
return itemImages.get(new ImageKey(itemId, quantity, stackable));
|
||||
}
|
||||
catch (ExecutionException ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create item sprite and applies an outline.
|
||||
*
|
||||
* @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 SpritePixels itemSprite = client.createItemSprite(itemId, itemQuantity, 1, 0, 0, true, 710);
|
||||
return itemSprite.toBufferedOutline(outlineColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item outline with a specific color.
|
||||
*
|
||||
* @param itemId item id
|
||||
* @param itemQuantity item quantity
|
||||
* @param outlineColor outline color
|
||||
* @return image
|
||||
*/
|
||||
public BufferedImage getItemOutline(final int itemId, final int itemQuantity, final Color outlineColor)
|
||||
{
|
||||
try
|
||||
{
|
||||
return itemOutlines.get(new OutlineKey(itemId, itemQuantity, outlineColor));
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||
* Copyright (c) 2018, Seth <Sethtroll3@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.game;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import static net.runelite.api.ItemID.*;
|
||||
|
||||
/**
|
||||
* Converts untradeable items to it's tradeable counterparts
|
||||
*/
|
||||
public enum ItemMapping
|
||||
{
|
||||
// Barrows equipment
|
||||
ITEM_AHRIMS_HOOD(AHRIMS_HOOD, AHRIMS_HOOD_25, AHRIMS_HOOD_50, AHRIMS_HOOD_75, AHRIMS_HOOD_100),
|
||||
ITEM_AHRIMS_ROBETOP(AHRIMS_ROBETOP, AHRIMS_ROBETOP_25, AHRIMS_ROBETOP_50, AHRIMS_ROBETOP_75, AHRIMS_ROBETOP_100),
|
||||
ITEM_AHRIMS_ROBEBOTTOM(AHRIMS_ROBESKIRT, AHRIMS_ROBESKIRT_25, AHRIMS_ROBESKIRT_50, AHRIMS_ROBESKIRT_75, AHRIMS_ROBESKIRT_100),
|
||||
ITEM_AHRIMS_STAFF(AHRIMS_STAFF, AHRIMS_STAFF_25, AHRIMS_STAFF_50, AHRIMS_STAFF_75, AHRIMS_STAFF_100),
|
||||
ITEM_KARILS_COIF(KARILS_COIF, KARILS_COIF_25, KARILS_COIF_50, KARILS_COIF_75, KARILS_COIF_100),
|
||||
ITEM_KARILS_LEATHERTOP(KARILS_LEATHERTOP, KARILS_LEATHERTOP_25, KARILS_LEATHERTOP_50, KARILS_LEATHERTOP_75, KARILS_LEATHERTOP_100),
|
||||
ITEM_KARILS_LEATHERSKIRT(KARILS_LEATHERSKIRT, KARILS_LEATHERSKIRT_25, KARILS_LEATHERSKIRT_50, KARILS_LEATHERSKIRT_75, KARILS_LEATHERSKIRT_100),
|
||||
ITEM_KARILS_CROSSBOW(KARILS_CROSSBOW, KARILS_CROSSBOW_25, KARILS_CROSSBOW_50, KARILS_CROSSBOW_75, KARILS_CROSSBOW_100),
|
||||
ITEM_DHAROKS_HELM(DHAROKS_HELM, DHAROKS_HELM_25, DHAROKS_HELM_50, DHAROKS_HELM_75, DHAROKS_HELM_100),
|
||||
ITEM_DHAROKS_PLATEBODY(DHAROKS_PLATEBODY, DHAROKS_PLATEBODY_25, DHAROKS_PLATEBODY_50, DHAROKS_PLATEBODY_75, DHAROKS_PLATEBODY_100),
|
||||
ITEM_DHAROKS_PLATELEGS(DHAROKS_PLATELEGS, DHAROKS_PLATELEGS_25, DHAROKS_PLATELEGS_50, DHAROKS_PLATELEGS_75, DHAROKS_PLATELEGS_100),
|
||||
ITEM_DHARKS_GREATEAXE(DHAROKS_GREATAXE, DHAROKS_GREATAXE_25, DHAROKS_GREATAXE_50, DHAROKS_GREATAXE_75, DHAROKS_GREATAXE_100),
|
||||
ITEM_GUTHANS_HELM(GUTHANS_HELM, GUTHANS_HELM_25, GUTHANS_HELM_50, GUTHANS_HELM_75, GUTHANS_HELM_100),
|
||||
ITEM_GUTHANS_PLATEBODY(GUTHANS_PLATEBODY, GUTHANS_PLATEBODY_25, GUTHANS_PLATEBODY_50, GUTHANS_PLATEBODY_75, GUTHANS_PLATEBODY_100),
|
||||
ITEM_GUTHANS_CHAINSKIRT(GUTHANS_CHAINSKIRT, GUTHANS_CHAINSKIRT_25, GUTHANS_CHAINSKIRT_50, GUTHANS_CHAINSKIRT_75, GUTHANS_CHAINSKIRT_100),
|
||||
ITEM_GUTHANS_WARSPEAR(GUTHANS_WARSPEAR, GUTHANS_WARSPEAR_25, GUTHANS_WARSPEAR_50, GUTHANS_WARSPEAR_75, GUTHANS_WARSPEAR_100),
|
||||
ITEM_TORAGS_HELM(TORAGS_HELM, TORAGS_HELM_25, TORAGS_HELM_50, TORAGS_HELM_75, TORAGS_HELM_100),
|
||||
ITEM_TORAGS_PLATEBODY(TORAGS_PLATEBODY, TORAGS_PLATEBODY_25, TORAGS_PLATEBODY_50, TORAGS_PLATEBODY_75, TORAGS_PLATEBODY_100),
|
||||
ITEM_TORAGS_PLATELEGS(TORAGS_PLATELEGS, TORAGS_PLATELEGS_25, TORAGS_PLATELEGS_50, TORAGS_PLATELEGS_75, TORAGS_PLATELEGS_100),
|
||||
ITEM_TORAGS_HAMMERS(TORAGS_HAMMERS, TORAGS_HAMMERS_25, TORAGS_HAMMERS_50, TORAGS_HAMMERS_75, TORAGS_HAMMERS_100),
|
||||
ITEM_VERACS_HELM(VERACS_HELM, VERACS_HELM_25, VERACS_HELM_50, VERACS_HELM_75, VERACS_HELM_100),
|
||||
ITEM_VERACS_BRASSARD(VERACS_BRASSARD, VERACS_BRASSARD_25, VERACS_BRASSARD_50, VERACS_BRASSARD_75, VERACS_BRASSARD_100),
|
||||
ITEM_VERACS_PLATESKIRT(VERACS_PLATESKIRT, VERACS_PLATESKIRT_25, VERACS_PLATESKIRT_50, VERACS_PLATESKIRT_75, VERACS_PLATESKIRT_100),
|
||||
ITEM_VERACS_FLAIL(VERACS_FLAIL, VERACS_FLAIL_25, VERACS_FLAIL_50, VERACS_FLAIL_75, VERACS_FLAIL_100),
|
||||
|
||||
// Dragon equipment ornament kits
|
||||
ITEM_DRAGON_SCIMITAR(DRAGON_SCIMITAR, DRAGON_SCIMITAR_OR),
|
||||
ITEM_DRAGON_SCIMITAR_ORNAMENT_KIT(DRAGON_SCIMITAR_ORNAMENT_KIT, DRAGON_SCIMITAR_OR),
|
||||
ITEM_DRAGON_DEFENDER(DRAGON_DEFENDER_ORNAMENT_KIT, DRAGON_DEFENDER_T),
|
||||
ITEM_DRAGON_PICKAXE(DRAGON_PICKAXE, DRAGON_PICKAXE_12797),
|
||||
ITEM_DRAGON_KITESHIELD(DRAGON_KITESHIELD, DRAGON_KITESHIELD_G),
|
||||
ITEM_DRAGON_KITESHIELD_ORNAMENT_KIT(DRAGON_KITESHIELD_ORNAMENT_KIT, DRAGON_KITESHIELD_G),
|
||||
ITEM_DRAGON_FULL_HELM(DRAGON_FULL_HELM, DRAGON_FULL_HELM_G),
|
||||
ITEM_DRAGON_FULL_HELM_ORNAMENT_KIT(DRAGON_FULL_HELM_ORNAMENT_KIT, DRAGON_FULL_HELM_G),
|
||||
ITEM_DRAGON_CHAINBODY(DRAGON_CHAINBODY_3140, DRAGON_CHAINBODY_G),
|
||||
ITEM_DRAGON_CHAINBODY_ORNAMENT_KIT(DRAGON_CHAINBODY_ORNAMENT_KIT, DRAGON_CHAINBODY_G),
|
||||
ITEM_DRAGON_PLATEBODY(DRAGON_PLATEBODY, DRAGON_PLATEBODY_G),
|
||||
ITEM_DRAGON_PLATEBODY_ORNAMENT_KIT(DRAGON_PLATEBODY_ORNAMENT_KIT, DRAGON_PLATEBODY_G),
|
||||
ITEM_DRAGON_PLATESKIRT(DRAGON_PLATESKIRT, DRAGON_PLATESKIRT_G),
|
||||
ITEM_DRAGON_SKIRT_ORNAMENT_KIT(DRAGON_LEGSSKIRT_ORNAMENT_KIT, DRAGON_PLATESKIRT_G),
|
||||
ITEM_DRAGON_PLATELEGS(DRAGON_PLATELEGS, DRAGON_PLATELEGS_G),
|
||||
ITEM_DRAGON_LEGS_ORNAMENT_KIT(DRAGON_LEGSSKIRT_ORNAMENT_KIT, DRAGON_PLATELEGS_G),
|
||||
ITEM_DRAGON_SQ_SHIELD(DRAGON_SQ_SHIELD, DRAGON_SQ_SHIELD_G),
|
||||
ITEM_DRAGON_SQ_SHIELD_ORNAMENT_KIT(DRAGON_SQ_SHIELD_ORNAMENT_KIT, DRAGON_SQ_SHIELD_G),
|
||||
ITEM_DRAGON_BOOTS(DRAGON_BOOTS, DRAGON_BOOTS_G),
|
||||
ITEM_DRAGON_BOOTS_ORNAMENT_KIT(DRAGON_BOOTS_ORNAMENT_KIT, DRAGON_BOOTS_G),
|
||||
|
||||
// Godsword ornament kits
|
||||
ITEM_ARMADYL_GODSWORD(ARMADYL_GODSWORD, ARMADYL_GODSWORD_OR),
|
||||
ITEM_ARMADYL_GODSWORD_ORNAMENT_KIT(ARMADYL_GODSWORD_ORNAMENT_KIT, ARMADYL_GODSWORD_OR),
|
||||
ITEM_BANDOS_GODSWORD(BANDOS_GODSWORD, BANDOS_GODSWORD_OR),
|
||||
ITEM_BANDOS_GODSWORD_ORNAMENT_KIT(BANDOS_GODSWORD_ORNAMENT_KIT, BANDOS_GODSWORD_OR),
|
||||
ITEM_ZAMORAK_GODSWORD(ZAMORAK_GODSWORD, ZAMORAK_GODSWORD_OR),
|
||||
ITEM_ZAMORAK_GODSWORD_ORNAMENT_KIT(ZAMORAK_GODSWORD_ORNAMENT_KIT, ZAMORAK_GODSWORD_OR),
|
||||
ITEM_SARADOMIN_GODSWORD(SARADOMIN_GODSWORD, SARADOMIN_GODSWORD_OR),
|
||||
ITEM_SARADOMIN_GODSWORD_ORNAMENT_KIT(SARADOMIN_GODSWORD_ORNAMENT_KIT, SARADOMIN_GODSWORD_OR),
|
||||
|
||||
// Jewellery ornament kits
|
||||
ITEM_AMULET_OF_TORTURE(AMULET_OF_TORTURE, AMULET_OF_TORTURE_OR),
|
||||
ITEM_TORTURE_ORNAMENT_KIT(TORTURE_ORNAMENT_KIT, AMULET_OF_TORTURE_OR),
|
||||
ITEM_NECKLACE_OF_ANGUISH(NECKLACE_OF_ANGUISH, NECKLACE_OF_ANGUISH_OR),
|
||||
ITEM_ANGUISH_ORNAMENT_KIT(ANGUISH_ORNAMENT_KIT, NECKLACE_OF_ANGUISH_OR),
|
||||
ITEM_OCCULT_NECKLACE(OCCULT_NECKLACE, OCCULT_NECKLACE_OR),
|
||||
ITEM_OCCULT_ORNAMENT_KIT(OCCULT_ORNAMENT_KIT, OCCULT_NECKLACE_OR),
|
||||
ITEM_AMULET_OF_FURY(AMULET_OF_FURY, AMULET_OF_FURY_OR),
|
||||
ITEM_FURY_ORNAMENT_KIT(FURY_ORNAMENT_KIT, AMULET_OF_FURY_OR),
|
||||
ITEM_TORMENTED_BRACELET(TORMENTED_BRACELET, TORMENTED_BRACELET_OR),
|
||||
ITEM_TORMENTED_ORNAMENT_KIT(TORMENTED_ORNAMENT_KIT, TORMENTED_BRACELET_OR),
|
||||
|
||||
// Ensouled heads
|
||||
ITEM_ENSOULED_GOBLIN_HEAD(ENSOULED_GOBLIN_HEAD_13448, ENSOULED_GOBLIN_HEAD),
|
||||
ITEM_ENSOULED_MONKEY_HEAD(ENSOULED_MONKEY_HEAD_13451, ENSOULED_MONKEY_HEAD),
|
||||
ITEM_ENSOULED_IMP_HEAD(ENSOULED_IMP_HEAD_13454, ENSOULED_IMP_HEAD),
|
||||
ITEM_ENSOULED_MINOTAUR_HEAD(ENSOULED_MINOTAUR_HEAD_13457, ENSOULED_MINOTAUR_HEAD),
|
||||
ITEM_ENSOULED_SCORPION_HEAD(ENSOULED_SCORPION_HEAD_13460, ENSOULED_SCORPION_HEAD),
|
||||
ITEM_ENSOULED_BEAR_HEAD(ENSOULED_BEAR_HEAD_13463, ENSOULED_BEAR_HEAD),
|
||||
ITEM_ENSOULED_UNICORN_HEAD(ENSOULED_UNICORN_HEAD_13466, ENSOULED_UNICORN_HEAD),
|
||||
ITEM_ENSOULED_DOG_HEAD(ENSOULED_DOG_HEAD_13469, ENSOULED_DOG_HEAD),
|
||||
ITEM_ENSOULED_CHAOS_DRUID_HEAD(ENSOULED_CHAOS_DRUID_HEAD_13472, ENSOULED_CHAOS_DRUID_HEAD),
|
||||
ITEM_ENSOULED_GIANT_HEAD(ENSOULED_GIANT_HEAD_13475, ENSOULED_GIANT_HEAD),
|
||||
ITEM_ENSOULED_OGRE_HEAD(ENSOULED_OGRE_HEAD_13478, ENSOULED_OGRE_HEAD),
|
||||
ITEM_ENSOULED_ELF_HEAD(ENSOULED_ELF_HEAD_13481, ENSOULED_ELF_HEAD),
|
||||
ITEM_ENSOULED_TROLL_HEAD(ENSOULED_TROLL_HEAD_13484, ENSOULED_TROLL_HEAD),
|
||||
ITEM_ENSOULED_HORROR_HEAD(ENSOULED_HORROR_HEAD_13487, ENSOULED_HORROR_HEAD),
|
||||
ITEM_ENSOULED_KALPHITE_HEAD(ENSOULED_KALPHITE_HEAD_13490, ENSOULED_KALPHITE_HEAD),
|
||||
ITEM_ENSOULED_DAGANNOTH_HEAD(ENSOULED_DAGANNOTH_HEAD_13493, ENSOULED_DAGANNOTH_HEAD),
|
||||
ITEM_ENSOULED_BLOODVELD_HEAD(ENSOULED_BLOODVELD_HEAD_13496, ENSOULED_BLOODVELD_HEAD),
|
||||
ITEM_ENSOULED_TZHAAR_HEAD(ENSOULED_TZHAAR_HEAD_13499, ENSOULED_TZHAAR_HEAD),
|
||||
ITEM_ENSOULED_DEMON_HEAD(ENSOULED_DEMON_HEAD_13502, ENSOULED_DEMON_HEAD),
|
||||
ITEM_ENSOULED_AVIANSIE_HEAD(ENSOULED_AVIANSIE_HEAD_13505, ENSOULED_AVIANSIE_HEAD),
|
||||
ITEM_ENSOULED_ABYSSAL_HEAD(ENSOULED_ABYSSAL_HEAD_13508, ENSOULED_ABYSSAL_HEAD),
|
||||
ITEM_ENSOULED_DRAGON_HEAD(ENSOULED_DRAGON_HEAD_13511, ENSOULED_DRAGON_HEAD),
|
||||
|
||||
// Imbued rings
|
||||
ITEM_BERSERKER_RING(BERSERKER_RING, BERSERKER_RING_I),
|
||||
ITEM_SEERS_RING(SEERS_RING, SEERS_RING_I),
|
||||
ITEM_WARRIOR_RING(WARRIOR_RING, WARRIOR_RING_I),
|
||||
ITEM_ARCHERS_RING(ARCHERS_RING, ARCHERS_RING_I),
|
||||
ITEM_TREASONOUS_RING(TREASONOUS_RING, TREASONOUS_RING_I),
|
||||
ITEM_TYRANNICAL_RING(TYRANNICAL_RING, TYRANNICAL_RING_I),
|
||||
ITEM_RING_OF_THE_GODS(RING_OF_THE_GODS, RING_OF_THE_GODS_I),
|
||||
ITEM_RING_OF_SUFFERING(RING_OF_SUFFERING, RING_OF_SUFFERING_I, RING_OF_SUFFERING_R, RING_OF_SUFFERING_RI),
|
||||
ITEM_GRANITE_RING(GRANITE_RING, GRANITE_RING_I),
|
||||
|
||||
// Bounty hunter
|
||||
ITEM_GRANITE_MAUL(GRANITE_MAUL, GRANITE_MAUL_12848),
|
||||
ITEM_MAGIC_SHORTBOW(MAGIC_SHORTBOW, MAGIC_SHORTBOW_I),
|
||||
ITEM_SARADOMINS_BLESSED_SWORD(SARADOMINS_TEAR, SARADOMINS_BLESSED_SWORD),
|
||||
|
||||
// Jewellery with charges
|
||||
ITEM_RING_OF_WEALTH(RING_OF_WEALTH, RING_OF_WEALTH_I, RING_OF_WEALTH_1, RING_OF_WEALTH_I1, RING_OF_WEALTH_2, RING_OF_WEALTH_I2, RING_OF_WEALTH_3, RING_OF_WEALTH_I3, RING_OF_WEALTH_4, RING_OF_WEALTH_I4, RING_OF_WEALTH_I5),
|
||||
ITEM_AMULET_OF_GLORY(AMULET_OF_GLORY, AMULET_OF_GLORY1, AMULET_OF_GLORY2, AMULET_OF_GLORY3, AMULET_OF_GLORY5),
|
||||
ITEM_AMULET_OF_GLORY_T(AMULET_OF_GLORY_T, AMULET_OF_GLORY_T1, AMULET_OF_GLORY_T2, AMULET_OF_GLORY_T3, AMULET_OF_GLORY_T5),
|
||||
ITEM_SKILLS_NECKLACE(SKILLS_NECKLACE, SKILLS_NECKLACE1, SKILLS_NECKLACE2, SKILLS_NECKLACE3, SKILLS_NECKLACE5),
|
||||
ITEM_RING_OF_DUELING(RING_OF_DUELING8, RING_OF_DUELING1, RING_OF_DUELING2, RING_OF_DUELING3, RING_OF_DUELING4, RING_OF_DUELING5, RING_OF_DUELING6, RING_OF_DUELING7),
|
||||
ITEM_GAMES_NECKLACE(GAMES_NECKLACE8, GAMES_NECKLACE1, GAMES_NECKLACE2, GAMES_NECKLACE3, GAMES_NECKLACE4, GAMES_NECKLACE5, GAMES_NECKLACE6, GAMES_NECKLACE7),
|
||||
|
||||
// Degradable/charged weaponry/armour
|
||||
ITEM_ABYSSAL_WHIP(ABYSSAL_WHIP, VOLCANIC_ABYSSAL_WHIP, FROZEN_ABYSSAL_WHIP),
|
||||
ITEM_KRAKEN_TENTACLE(KRAKEN_TENTACLE, ABYSSAL_TENTACLE),
|
||||
ITEM_TRIDENT_OF_THE_SEAS(UNCHARGED_TRIDENT, TRIDENT_OF_THE_SEAS),
|
||||
ITEM_TRIDENT_OF_THE_SEAS_E(UNCHARGED_TRIDENT_E, TRIDENT_OF_THE_SEAS_E),
|
||||
ITEM_TRIDENT_OF_THE_SWAMP(UNCHARGED_TOXIC_TRIDENT, TRIDENT_OF_THE_SWAMP),
|
||||
ITEM_TRIDENT_OF_THE_SWAMP_E(UNCHARGED_TOXIC_TRIDENT_E, TRIDENT_OF_THE_SWAMP_E),
|
||||
ITEM_TOXIC_BLOWPIPE(TOXIC_BLOWPIPE_EMPTY, TOXIC_BLOWPIPE),
|
||||
ITEM_TOXIC_STAFF_OFF_THE_DEAD(TOXIC_STAFF_UNCHARGED, TOXIC_STAFF_OF_THE_DEAD),
|
||||
ITEM_SERPENTINE_HELM(SERPENTINE_HELM_UNCHARGED, SERPENTINE_HELM, TANZANITE_HELM_UNCHARGED, TANZANITE_HELM, MAGMA_HELM_UNCHARGED, MAGMA_HELM),
|
||||
ITEM_DRAGONFIRE_SHIELD(DRAGONFIRE_SHIELD_11284, DRAGONFIRE_SHIELD),
|
||||
ITEM_DRAGONFIRE_WARD(DRAGONFIRE_WARD_22003, DRAGONFIRE_WARD),
|
||||
ITEM_ANCIENT_WYVERN_SHIELD(ANCIENT_WYVERN_SHIELD_21634, ANCIENT_WYVERN_SHIELD),
|
||||
ITEM_SANGUINESTI_STAFF(SANGUINESTI_STAFF_UNCHARGED, SANGUINESTI_STAFF),
|
||||
ITEM_SCYTHE_OF_VITUR(SCYTHE_OF_VITUR_UNCHARGED, SCYTHE_OF_VITUR),
|
||||
ITEM_TOME_OF_FIRE(TOME_OF_FIRE_EMPTY, TOME_OF_FIRE),
|
||||
ITEM_CRAWS_BOW(CRAWS_BOW_U, CRAWS_BOW),
|
||||
ITEM_VIGGORAS_CHAINMACE(VIGGORAS_CHAINMACE_U, VIGGORAS_CHAINMACE),
|
||||
ITEM_THAMMARONS_SCEPTRE(THAMMARONS_SCEPTRE_U, THAMMARONS_SCEPTRE),
|
||||
|
||||
// Infinity colour kits
|
||||
ITEM_INFINITY_TOP(INFINITY_TOP, INFINITY_TOP_10605, INFINITY_TOP_20574, DARK_INFINITY_TOP, LIGHT_INFINITY_TOP),
|
||||
ITEM_INFINITY_TOP_LIGHT_COLOUR_KIT(LIGHT_INFINITY_COLOUR_KIT, LIGHT_INFINITY_TOP),
|
||||
ITEM_INFINITY_TOP_DARK_COLOUR_KIT(DARK_INFINITY_COLOUR_KIT, DARK_INFINITY_TOP),
|
||||
ITEM_INFINITY_BOTTOMS(INFINITY_BOTTOMS, INFINITY_BOTTOMS_20575, DARK_INFINITY_BOTTOMS, LIGHT_INFINITY_BOTTOMS),
|
||||
ITEM_INFINITY_BOTTOMS_LIGHT_COLOUR_KIT(LIGHT_INFINITY_COLOUR_KIT, LIGHT_INFINITY_BOTTOMS),
|
||||
ITEM_INFINITY_BOTTOMS_DARK_COLOUR_KIT(DARK_INFINITY_COLOUR_KIT, DARK_INFINITY_BOTTOMS),
|
||||
ITEM_INFINITY_HAT(INFINITY_HAT, DARK_INFINITY_HAT, LIGHT_INFINITY_HAT),
|
||||
ITEM_INFINITY_HAT_LIGHT_COLOUR_KIT(LIGHT_INFINITY_COLOUR_KIT, LIGHT_INFINITY_HAT),
|
||||
ITEM_INFINITY_HAT_DARK_COLOUR_KIT(DARK_INFINITY_COLOUR_KIT, DARK_INFINITY_HAT),
|
||||
|
||||
// Miscellaneous ornament kits
|
||||
ITEM_DARK_BOW(DARK_BOW, DARK_BOW_12765, DARK_BOW_12766, DARK_BOW_12767, DARK_BOW_12768, DARK_BOW_20408),
|
||||
ITEM_ODIUM_WARD(ODIUM_WARD, ODIUM_WARD_12807),
|
||||
ITEM_MALEDICTION_WARD(MALEDICTION_WARD, MALEDICTION_WARD_12806),
|
||||
ITEM_STEAM_BATTLESTAFF(STEAM_BATTLESTAFF, STEAM_BATTLESTAFF_12795),
|
||||
ITEM_LAVA_BATTLESTAFF(LAVA_BATTLESTAFF, LAVA_BATTLESTAFF_21198),
|
||||
|
||||
// Slayer helm/black mask
|
||||
ITEM_BLACK_MASK(
|
||||
BLACK_MASK, BLACK_MASK_I, BLACK_MASK_1, BLACK_MASK_1_I, BLACK_MASK_2, BLACK_MASK_2_I, BLACK_MASK_3, BLACK_MASK_3_I, BLACK_MASK_4, BLACK_MASK_4_I, BLACK_MASK_5,
|
||||
BLACK_MASK_5_I, BLACK_MASK_6, BLACK_MASK_6_I, BLACK_MASK_7, BLACK_MASK_7_I, BLACK_MASK_8, BLACK_MASK_8_I, BLACK_MASK_9, BLACK_MASK_9_I, BLACK_MASK_10_I,
|
||||
SLAYER_HELMET, SLAYER_HELMET_I, BLACK_SLAYER_HELMET, BLACK_SLAYER_HELMET_I, PURPLE_SLAYER_HELMET, PURPLE_SLAYER_HELMET_I, RED_SLAYER_HELMET, RED_SLAYER_HELMET_I,
|
||||
GREEN_SLAYER_HELMET, GREEN_SLAYER_HELMET_I, TURQUOISE_SLAYER_HELMET, TURQUOISE_SLAYER_HELMET_I, HYDRA_SLAYER_HELMET, HYDRA_SLAYER_HELMET_I),
|
||||
|
||||
// Pharaoh's Sceptres
|
||||
ITEM_PHARAOHS_SCEPTRE_1(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_1),
|
||||
ITEM_PHARAOHS_SCEPTRE_2(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_2),
|
||||
ITEM_PHARAOHS_SCEPTRE_4(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_4),
|
||||
ITEM_PHARAOHS_SCEPTRE_5(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_5),
|
||||
ITEM_PHARAOHS_SCEPTRE_6(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_6),
|
||||
ITEM_PHARAOHS_SCEPTRE_7(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_7),
|
||||
ITEM_PHARAOHS_SCEPTRE_8(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_8),
|
||||
|
||||
// Revertible items
|
||||
ITEM_HYDRA_LEATHER(HYDRA_LEATHER, FEROCIOUS_GLOVES),
|
||||
ITEM_HYDRA_TAIL(HYDRA_TAIL, BONECRUSHER_NECKLACE),
|
||||
ITEM_DRAGONBONE_NECKLACE(DRAGONBONE_NECKLACE, BONECRUSHER_NECKLACE),
|
||||
ITEM_BOTTOMLESS_COMPOST_BUCKET(BOTTOMLESS_COMPOST_BUCKET, BOTTOMLESS_COMPOST_BUCKET_22997);
|
||||
|
||||
private static final Multimap<Integer, Integer> MAPPINGS = HashMultimap.create();
|
||||
private final int tradeableItem;
|
||||
private final int[] untradableItems;
|
||||
|
||||
static
|
||||
{
|
||||
for (final ItemMapping item : values())
|
||||
{
|
||||
for (int itemId : item.untradableItems)
|
||||
{
|
||||
MAPPINGS.put(itemId, item.tradeableItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemMapping(int tradeableItem, int... untradableItems)
|
||||
{
|
||||
this.tradeableItem = tradeableItem;
|
||||
this.untradableItems = untradableItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get collection of items that are mapped from single item id.
|
||||
*
|
||||
* @param itemId the item id
|
||||
* @return the collection
|
||||
*/
|
||||
public static Collection<Integer> map(int itemId)
|
||||
{
|
||||
final Collection<Integer> mapping = MAPPINGS.get(itemId);
|
||||
|
||||
if (mapping == null || mapping.isEmpty())
|
||||
{
|
||||
return Collections.singleton(itemId);
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map an item from its untradeable version to its tradeable version
|
||||
*
|
||||
* @param itemId
|
||||
* @return
|
||||
*/
|
||||
public static int mapFirst(int itemId)
|
||||
{
|
||||
final Collection<Integer> mapping = MAPPINGS.get(itemId);
|
||||
|
||||
if (mapping == null || mapping.isEmpty())
|
||||
{
|
||||
return itemId;
|
||||
}
|
||||
|
||||
return mapping.iterator().next();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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 lombok.Value;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
|
||||
@Value
|
||||
public class ItemStack
|
||||
{
|
||||
private final int id;
|
||||
private final int quantity;
|
||||
private final LocalPoint location;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Ron Young <https://github.com/raiyni>
|
||||
* 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 com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Converts variation items to it's base item counterparts
|
||||
*/
|
||||
public class ItemVariationMapping
|
||||
{
|
||||
private static final Map<Integer, Integer> MAPPINGS;
|
||||
|
||||
static
|
||||
{
|
||||
final Gson gson = new Gson();
|
||||
final TypeToken<Map<String, Collection<Integer>>> typeToken = new TypeToken<Map<String, Collection<Integer>>>()
|
||||
{
|
||||
};
|
||||
|
||||
final InputStream geLimitData = ItemVariationMapping.class.getResourceAsStream("/item_variations.json");
|
||||
final Map<String, Collection<Integer>> itemVariations = gson.fromJson(new InputStreamReader(geLimitData), typeToken.getType());
|
||||
|
||||
ImmutableMap.Builder<Integer, Integer> builder = new ImmutableMap.Builder<>();
|
||||
for (Collection<Integer> value : itemVariations.values())
|
||||
{
|
||||
final Iterator<Integer> iterator = value.iterator();
|
||||
final int base = iterator.next();
|
||||
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
builder.put(iterator.next(), base);
|
||||
}
|
||||
}
|
||||
MAPPINGS = builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base item id for provided variation item id.
|
||||
*
|
||||
* @param itemId the item id
|
||||
* @return the base item id
|
||||
*/
|
||||
public static int map(int itemId)
|
||||
{
|
||||
return MAPPINGS.getOrDefault(itemId, itemId);
|
||||
}
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
/*
|
||||
* 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.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.Item;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.NpcID;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Tile;
|
||||
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.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;
|
||||
|
||||
@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.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_474:
|
||||
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 Item 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 Item 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 Item 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 onGameTick(GameTick gameTick)
|
||||
{
|
||||
playerLocationLastTick = client.getLocalPlayer().getWorldLocation();
|
||||
itemSpawns.clear();
|
||||
killPoints.clear();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
* 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 com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class NPCManager
|
||||
{
|
||||
private final ImmutableMap<Integer, NPCStats> statsMap;
|
||||
|
||||
@Inject
|
||||
private NPCManager()
|
||||
{
|
||||
final Gson gson = new Gson();
|
||||
|
||||
final Type typeToken = new TypeToken<Map<Integer, NPCStats>>()
|
||||
{
|
||||
}.getType();
|
||||
|
||||
final InputStream statsFile = getClass().getResourceAsStream("/npc_stats.json");
|
||||
final Map<Integer, NPCStats> stats = gson.fromJson(new InputStreamReader(statsFile), typeToken);
|
||||
statsMap = ImmutableMap.copyOf(stats);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return statsMap.get(npcId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns health for target NPC ID
|
||||
* @param npcId NPC id
|
||||
* @return health or null if unknown
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getHealth(final int npcId)
|
||||
{
|
||||
final NPCStats s = statsMap.get(npcId);
|
||||
if (s == null || s.getHitpoints() == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return s.getHitpoints();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
final NPCStats s = statsMap.get(npcId);
|
||||
if (s == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return s.calculateXpModifier();
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 lombok.Value;
|
||||
|
||||
@Value
|
||||
public class NPCStats
|
||||
{
|
||||
private final String name;
|
||||
|
||||
private final int hitpoints;
|
||||
private final int combatLevel;
|
||||
private final int slayerLevel;
|
||||
|
||||
private final int attackLevel;
|
||||
private final int strengthLevel;
|
||||
private final int defenceLevel;
|
||||
private final int rangeLevel;
|
||||
private final int magicLevel;
|
||||
|
||||
private final int stab;
|
||||
private final int slash;
|
||||
private final int crush;
|
||||
private final int range;
|
||||
private final int magic;
|
||||
|
||||
private final int stabDef;
|
||||
private final int slashDef;
|
||||
private final int crushDef;
|
||||
private final int rangeDef;
|
||||
private final int magicDef;
|
||||
|
||||
private final int bonusAttack;
|
||||
private final int bonusStrength;
|
||||
private final int bonusRangeStrength;
|
||||
private final int bonusMagicDamage;
|
||||
|
||||
private final boolean poisonImmune;
|
||||
private final boolean venomImmune;
|
||||
|
||||
private final boolean dragon;
|
||||
private final boolean demon;
|
||||
private final boolean undead;
|
||||
|
||||
/**
|
||||
* Based off the formula found here: http://services.runescape.com/m=forum/c=PLuJ4cy6gtA/forums.ws?317,318,712,65587452,209,337584542#209
|
||||
* @return bonus XP modifier
|
||||
*/
|
||||
public double calculateXpModifier()
|
||||
{
|
||||
final double averageLevel = Math.floor((attackLevel + strengthLevel + defenceLevel + hitpoints) / 4);
|
||||
final double averageDefBonus = Math.floor((stabDef + slashDef + crushDef) / 3);
|
||||
|
||||
return (1 + Math.floor(averageLevel * (averageDefBonus + bonusStrength + bonusAttack) / 5120) / 40);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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 java.awt.image.BufferedImage;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class SkillIconManager
|
||||
{
|
||||
// * 2 to account for the small version of each icon
|
||||
private final BufferedImage[] imgCache = new BufferedImage[Skill.values().length * 2];
|
||||
|
||||
public BufferedImage getSkillImage(Skill skill, boolean small)
|
||||
{
|
||||
int skillIdx = skill.ordinal() + (small ? Skill.values().length : 0);
|
||||
BufferedImage skillImage = null;
|
||||
|
||||
if (imgCache[skillIdx] != null)
|
||||
{
|
||||
return imgCache[skillIdx];
|
||||
}
|
||||
|
||||
String skillIconPath = (small ? "/skill_icons_small/" : "/skill_icons/")
|
||||
+ skill.getName().toLowerCase() + ".png";
|
||||
log.debug("Loading skill icon from {}", skillIconPath);
|
||||
skillImage = ImageUtil.getResourceStreamFromClass(getClass(), skillIconPath);
|
||||
imgCache[skillIdx] = skillImage;
|
||||
|
||||
return skillImage;
|
||||
}
|
||||
|
||||
public BufferedImage getSkillImage(Skill skill)
|
||||
{
|
||||
return getSkillImage(skill, false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* 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.game;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.inject.Inject;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Singleton;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.SpritePixels;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class SpriteManager
|
||||
{
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
public Cache<Long, BufferedImage> cache = CacheBuilder.newBuilder()
|
||||
.maximumSize(128L)
|
||||
.expireAfterAccess(1, TimeUnit.HOURS)
|
||||
.build();
|
||||
|
||||
@Nullable
|
||||
public BufferedImage getSprite(int archive, int file)
|
||||
{
|
||||
assert client.isClientThread();
|
||||
if (client.getGameState().ordinal() < GameState.LOGIN_SCREEN.ordinal())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Long key = (long) archive << 32 | file;
|
||||
BufferedImage cached = cache.getIfPresent(key);
|
||||
if (cached != null)
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
SpritePixels[] sp = client.getSprites(client.getIndexSprites(), archive, 0);
|
||||
BufferedImage img = sp[file].toBufferedImage();
|
||||
|
||||
cache.put(key, img);
|
||||
return img;
|
||||
}
|
||||
|
||||
public void getSpriteAsync(int archive, int file, Consumer<BufferedImage> user)
|
||||
{
|
||||
BufferedImage cached = cache.getIfPresent((long) archive << 32 | file);
|
||||
if (cached != null)
|
||||
{
|
||||
user.accept(cached);
|
||||
return;
|
||||
}
|
||||
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
BufferedImage img = getSprite(archive, file);
|
||||
if (img == null)
|
||||
{
|
||||
// Cache isn't loaded yet
|
||||
return false;
|
||||
}
|
||||
user.accept(img);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls setIcon on c, ensuring it is repainted when this changes
|
||||
*/
|
||||
public void addSpriteTo(JButton c, int archive, int file)
|
||||
{
|
||||
getSpriteAsync(archive, file, img ->
|
||||
{
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
c.setIcon(new ImageIcon(img));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls setIcon on c, ensuring it is repainted when this changes
|
||||
*/
|
||||
public void addSpriteTo(JLabel c, int archive, int file)
|
||||
{
|
||||
getSpriteAsync(archive, file, img ->
|
||||
{
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
c.setIcon(new ImageIcon(img));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void addSpriteOverrides(SpriteOverride[] add)
|
||||
{
|
||||
if (add.length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
Map<Integer, SpritePixels> overrides = client.getSpriteOverrides();
|
||||
Class<?> owner = add[0].getClass();
|
||||
for (SpriteOverride o : add)
|
||||
{
|
||||
BufferedImage image = ImageUtil.getResourceStreamFromClass(owner, o.getFileName());
|
||||
SpritePixels sp = ImageUtil.getImageSpritePixels(image, client);
|
||||
overrides.put(o.getSpriteId(), sp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeSpriteOverrides(SpriteOverride[] remove)
|
||||
{
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
Map<Integer, SpritePixels> overrides = client.getSpriteOverrides();
|
||||
for (SpriteOverride o : remove)
|
||||
{
|
||||
overrides.remove(o.getSpriteId());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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.game;
|
||||
|
||||
import net.runelite.api.SpriteID;
|
||||
|
||||
public interface SpriteOverride
|
||||
{
|
||||
/**
|
||||
* An ID for a sprite. Negative numbers are used by RuneLite specific sprites
|
||||
*
|
||||
* @see SpriteID
|
||||
*/
|
||||
int getSpriteId();
|
||||
|
||||
/**
|
||||
* The file name for the resource to be loaded, relative to the implementing class
|
||||
*/
|
||||
String getFileName();
|
||||
}
|
||||
@@ -1,72 +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 lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.runelite.api.ItemID;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum UntradeableItemMapping
|
||||
{
|
||||
MARK_OF_GRACE(ItemID.MARK_OF_GRACE, 10, ItemID.AMYLASE_CRYSTAL),
|
||||
GRACEFUL_HOOD(ItemID.GRACEFUL_HOOD, 28, ItemID.MARK_OF_GRACE),
|
||||
GRACEFUL_TOP(ItemID.GRACEFUL_TOP, 44, ItemID.MARK_OF_GRACE),
|
||||
GRACEFUL_LEGS(ItemID.GRACEFUL_LEGS, 48, ItemID.MARK_OF_GRACE),
|
||||
GRACEFUL_GLOVES(ItemID.GRACEFUL_GLOVES, 24, ItemID.MARK_OF_GRACE),
|
||||
GRACEFUL_BOOTS(ItemID.GRACEFUL_BOOTS, 32, ItemID.MARK_OF_GRACE),
|
||||
GRACEFUL_CAPE(ItemID.GRACEFUL_CAPE, 32, ItemID.MARK_OF_GRACE),
|
||||
|
||||
// 10 golden nuggets = 100 soft clay
|
||||
GOLDEN_NUGGET(ItemID.GOLDEN_NUGGET, 10, ItemID.SOFT_CLAY),
|
||||
PROSPECTOR_HELMET(ItemID.PROSPECTOR_HELMET, 32, ItemID.GOLDEN_NUGGET),
|
||||
PROSPECTOR_JACKET(ItemID.PROSPECTOR_JACKET, 48, ItemID.GOLDEN_NUGGET),
|
||||
PROSPECTOR_LEGS(ItemID.PROSPECTOR_LEGS, 40, ItemID.GOLDEN_NUGGET),
|
||||
PROSPECTOR_BOOTS(ItemID.PROSPECTOR_BOOTS, 24, ItemID.GOLDEN_NUGGET);
|
||||
|
||||
private static final ImmutableMap<Integer, UntradeableItemMapping> UNTRADEABLE_RECLAIM_MAP;
|
||||
|
||||
private final int itemID;
|
||||
private final int quantity;
|
||||
private final int priceID;
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableMap.Builder<Integer, UntradeableItemMapping> map = ImmutableMap.builder();
|
||||
for (UntradeableItemMapping p : values())
|
||||
{
|
||||
map.put(p.getItemID(), p);
|
||||
}
|
||||
UNTRADEABLE_RECLAIM_MAP = map.build();
|
||||
}
|
||||
|
||||
public static UntradeableItemMapping map(int itemId)
|
||||
{
|
||||
return UNTRADEABLE_RECLAIM_MAP.get(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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.game.chatbox;
|
||||
|
||||
/**
|
||||
* A modal input that lives in the chatbox panel.
|
||||
*/
|
||||
public abstract class ChatboxInput
|
||||
{
|
||||
protected void open()
|
||||
{
|
||||
}
|
||||
|
||||
protected void close()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* 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.game.chatbox;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.ScriptID;
|
||||
import net.runelite.api.VarClientInt;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.ScriptCallbackEvent;
|
||||
import net.runelite.api.vars.InputType;
|
||||
import net.runelite.api.widgets.JavaScriptCallback;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.input.KeyListener;
|
||||
import net.runelite.client.input.KeyManager;
|
||||
import net.runelite.client.input.MouseListener;
|
||||
import net.runelite.client.input.MouseManager;
|
||||
import net.runelite.client.input.MouseWheelListener;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class ChatboxPanelManager
|
||||
{
|
||||
private final Client client;
|
||||
private final ClientThread clientThread;
|
||||
private final EventBus eventBus;
|
||||
|
||||
private final KeyManager keyManager;
|
||||
private final MouseManager mouseManager;
|
||||
|
||||
private final Provider<ChatboxTextMenuInput> chatboxTextMenuInputProvider;
|
||||
private final Provider<ChatboxTextInput> chatboxTextInputProvider;
|
||||
|
||||
@Getter
|
||||
private ChatboxInput currentInput = null;
|
||||
|
||||
@Inject
|
||||
private ChatboxPanelManager(EventBus eventBus, Client client, ClientThread clientThread,
|
||||
KeyManager keyManager, MouseManager mouseManager,
|
||||
Provider<ChatboxTextMenuInput> chatboxTextMenuInputProvider, Provider<ChatboxTextInput> chatboxTextInputProvider)
|
||||
{
|
||||
this.client = client;
|
||||
this.clientThread = clientThread;
|
||||
this.eventBus = eventBus;
|
||||
|
||||
this.keyManager = keyManager;
|
||||
this.mouseManager = mouseManager;
|
||||
|
||||
this.chatboxTextMenuInputProvider = chatboxTextMenuInputProvider;
|
||||
this.chatboxTextInputProvider = chatboxTextInputProvider;
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
clientThread.invokeLater(this::unsafeCloseInput);
|
||||
}
|
||||
|
||||
private void unsafeCloseInput()
|
||||
{
|
||||
client.runScript(
|
||||
ScriptID.RESET_CHATBOX_INPUT,
|
||||
0,
|
||||
1
|
||||
);
|
||||
if (currentInput != null)
|
||||
{
|
||||
killCurrentPanel();
|
||||
}
|
||||
}
|
||||
|
||||
private void unsafeOpenInput(ChatboxInput input)
|
||||
{
|
||||
client.runScript(ScriptID.CLEAR_CHATBOX_PANEL);
|
||||
|
||||
eventBus.register(input);
|
||||
if (input instanceof KeyListener)
|
||||
{
|
||||
keyManager.registerKeyListener((KeyListener) input);
|
||||
}
|
||||
if (input instanceof MouseListener)
|
||||
{
|
||||
mouseManager.registerMouseListener((MouseListener) input);
|
||||
}
|
||||
if (input instanceof MouseWheelListener)
|
||||
{
|
||||
mouseManager.registerMouseWheelListener((MouseWheelListener) input);
|
||||
}
|
||||
|
||||
if (currentInput != null)
|
||||
{
|
||||
killCurrentPanel();
|
||||
}
|
||||
|
||||
currentInput = input;
|
||||
client.setVar(VarClientInt.INPUT_TYPE, InputType.RUNELITE_CHATBOX_PANEL.getType());
|
||||
client.getWidget(WidgetInfo.CHATBOX_TITLE).setHidden(true);
|
||||
client.getWidget(WidgetInfo.CHATBOX_FULL_INPUT).setHidden(true);
|
||||
|
||||
Widget c = getContainerWidget();
|
||||
c.deleteAllChildren();
|
||||
c.setOnDialogAbortListener((JavaScriptCallback) ev -> this.unsafeCloseInput());
|
||||
input.open();
|
||||
}
|
||||
|
||||
public void openInput(ChatboxInput input)
|
||||
{
|
||||
clientThread.invokeLater(() -> unsafeOpenInput(input));
|
||||
}
|
||||
|
||||
public ChatboxTextMenuInput openTextMenuInput(String title)
|
||||
{
|
||||
return chatboxTextMenuInputProvider.get()
|
||||
.title(title);
|
||||
}
|
||||
|
||||
public ChatboxTextInput openTextInput(String prompt)
|
||||
{
|
||||
return chatboxTextInputProvider.get()
|
||||
.prompt(prompt);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onScriptCallbackEvent(ScriptCallbackEvent ev)
|
||||
{
|
||||
if (currentInput != null && "resetChatboxInput".equals(ev.getEventName()))
|
||||
{
|
||||
killCurrentPanel();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameStateChanged(GameStateChanged ev)
|
||||
{
|
||||
if (currentInput != null && ev.getGameState() == GameState.LOGIN_SCREEN)
|
||||
{
|
||||
killCurrentPanel();
|
||||
}
|
||||
}
|
||||
|
||||
private void killCurrentPanel()
|
||||
{
|
||||
try
|
||||
{
|
||||
currentInput.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.warn("Exception closing {}", currentInput.getClass(), e);
|
||||
}
|
||||
|
||||
eventBus.unregister(currentInput);
|
||||
if (currentInput instanceof KeyListener)
|
||||
{
|
||||
keyManager.unregisterKeyListener((KeyListener) currentInput);
|
||||
}
|
||||
if (currentInput instanceof MouseListener)
|
||||
{
|
||||
mouseManager.unregisterMouseListener((MouseListener) currentInput);
|
||||
}
|
||||
if (currentInput instanceof MouseWheelListener)
|
||||
{
|
||||
mouseManager.unregisterMouseWheelListener((MouseWheelListener) currentInput);
|
||||
}
|
||||
currentInput = null;
|
||||
}
|
||||
|
||||
public Widget getContainerWidget()
|
||||
{
|
||||
return client.getWidget(WidgetInfo.CHATBOX_CONTAINER);
|
||||
}
|
||||
}
|
||||
@@ -1,865 +0,0 @@
|
||||
/*
|
||||
* 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.game.chatbox;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.SwingUtilities;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.FontID;
|
||||
import net.runelite.api.FontTypeFace;
|
||||
import net.runelite.api.widgets.JavaScriptCallback;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetPositionMode;
|
||||
import net.runelite.api.widgets.WidgetSizeMode;
|
||||
import net.runelite.api.widgets.WidgetTextAlignment;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.input.KeyListener;
|
||||
import net.runelite.client.input.MouseListener;
|
||||
import net.runelite.client.util.MiscUtils;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@Slf4j
|
||||
public class ChatboxTextInput extends ChatboxInput implements KeyListener, MouseListener
|
||||
{
|
||||
private static final int CURSOR_FLASH_RATE_MILLIS = 1000;
|
||||
private static final Pattern BREAK_MATCHER = Pattern.compile("[^a-zA-Z0-9']");
|
||||
|
||||
private final ChatboxPanelManager chatboxPanelManager;
|
||||
private final ClientThread clientThread;
|
||||
|
||||
private static IntPredicate getDefaultCharValidator()
|
||||
{
|
||||
return i -> i >= 32 && i < 127;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private static class Line
|
||||
{
|
||||
private final int start;
|
||||
private final int end;
|
||||
private final String text;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private String prompt;
|
||||
|
||||
@Getter
|
||||
private int lines;
|
||||
|
||||
private StringBuffer value = new StringBuffer();
|
||||
|
||||
@Getter
|
||||
private int cursorStart = 0;
|
||||
|
||||
@Getter
|
||||
private int cursorEnd = 0;
|
||||
|
||||
private int selectionStart = -1;
|
||||
private int selectionEnd = -1;
|
||||
|
||||
@Getter
|
||||
private IntPredicate charValidator = getDefaultCharValidator();
|
||||
|
||||
@Getter
|
||||
private Runnable onClose = null;
|
||||
|
||||
@Getter
|
||||
private Consumer<String> onDone = null;
|
||||
|
||||
@Getter
|
||||
private Consumer<String> onChanged = null;
|
||||
|
||||
@Getter
|
||||
private int fontID = FontID.QUILL_8;
|
||||
|
||||
@Getter
|
||||
private boolean built = false;
|
||||
|
||||
// These are lambdas for atomic updates
|
||||
private Predicate<MouseEvent> isInBounds = null;
|
||||
private ToIntFunction<Integer> getLineOffset = null;
|
||||
private ToIntFunction<Point> getPointCharOffset = null;
|
||||
|
||||
@Inject
|
||||
protected ChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread)
|
||||
{
|
||||
this.chatboxPanelManager = chatboxPanelManager;
|
||||
this.clientThread = clientThread;
|
||||
}
|
||||
|
||||
public ChatboxTextInput lines(int lines)
|
||||
{
|
||||
this.lines = lines;
|
||||
if (built)
|
||||
{
|
||||
clientThread.invoke(this::update);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextInput prompt(String prompt)
|
||||
{
|
||||
this.prompt = prompt;
|
||||
if (built)
|
||||
{
|
||||
clientThread.invoke(this::update);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextInput value(String value)
|
||||
{
|
||||
this.value = new StringBuffer(value);
|
||||
cursorAt(this.value.length());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextInput cursorAt(int index)
|
||||
{
|
||||
return cursorAt(index, index);
|
||||
}
|
||||
|
||||
public ChatboxTextInput cursorAt(int indexA, int indexB)
|
||||
{
|
||||
if (indexA < 0)
|
||||
{
|
||||
indexA = 0;
|
||||
}
|
||||
if (indexB < 0)
|
||||
{
|
||||
indexB = 0;
|
||||
}
|
||||
if (indexA > value.length())
|
||||
{
|
||||
indexA = value.length();
|
||||
}
|
||||
if (indexB > value.length())
|
||||
{
|
||||
indexB = value.length();
|
||||
}
|
||||
int start = indexA;
|
||||
int end = indexB;
|
||||
if (start > end)
|
||||
{
|
||||
int v = start;
|
||||
start = end;
|
||||
end = v;
|
||||
}
|
||||
|
||||
this.cursorStart = start;
|
||||
this.cursorEnd = end;
|
||||
|
||||
if (built)
|
||||
{
|
||||
clientThread.invoke(this::update);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
public ChatboxTextInput charValidator(IntPredicate val)
|
||||
{
|
||||
if (val == null)
|
||||
{
|
||||
val = getDefaultCharValidator();
|
||||
}
|
||||
this.charValidator = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextInput onClose(Runnable onClose)
|
||||
{
|
||||
this.onClose = onClose;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextInput onDone(Consumer<String> onDone)
|
||||
{
|
||||
this.onDone = onDone;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextInput onChanged(Consumer<String> onChanged)
|
||||
{
|
||||
this.onChanged = onChanged;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextInput fontID(int fontID)
|
||||
{
|
||||
this.fontID = fontID;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void update()
|
||||
{
|
||||
Widget container = chatboxPanelManager.getContainerWidget();
|
||||
container.deleteAllChildren();
|
||||
|
||||
Widget promptWidget = container.createChild(-1, WidgetType.TEXT);
|
||||
promptWidget.setText(this.prompt);
|
||||
promptWidget.setTextColor(0x800000);
|
||||
promptWidget.setFontId(fontID);
|
||||
promptWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
|
||||
promptWidget.setOriginalX(0);
|
||||
promptWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
promptWidget.setOriginalY(8);
|
||||
promptWidget.setOriginalHeight(24);
|
||||
promptWidget.setXTextAlignment(WidgetTextAlignment.CENTER);
|
||||
promptWidget.setYTextAlignment(WidgetTextAlignment.CENTER);
|
||||
promptWidget.setWidthMode(WidgetSizeMode.MINUS);
|
||||
promptWidget.revalidate();
|
||||
|
||||
buildEdit(0, 50, container.getWidth(), 0);
|
||||
}
|
||||
|
||||
protected void buildEdit(int x, int y, int w, int h)
|
||||
{
|
||||
final List<Line> editLines = new ArrayList<>();
|
||||
|
||||
Widget container = chatboxPanelManager.getContainerWidget();
|
||||
|
||||
final Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
|
||||
long start = System.currentTimeMillis();
|
||||
cursor.setOnTimerListener((JavaScriptCallback) ev ->
|
||||
{
|
||||
boolean on = (System.currentTimeMillis() - start) % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
|
||||
cursor.setOpacity(on ? 255 : 0);
|
||||
});
|
||||
cursor.setTextColor(0xFFFFFF);
|
||||
cursor.setHasListener(true);
|
||||
cursor.setFilled(true);
|
||||
cursor.setFontId(fontID);
|
||||
|
||||
FontTypeFace font = cursor.getFont();
|
||||
if (h <= 0)
|
||||
{
|
||||
h = font.getBaseline();
|
||||
}
|
||||
|
||||
final int oy = y;
|
||||
final int ox = x;
|
||||
final int oh = h;
|
||||
|
||||
int breakIndex = -1;
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < value.length(); i++)
|
||||
{
|
||||
int count = i - sb.length();
|
||||
final String c = value.charAt(i) + "";
|
||||
sb.append(c);
|
||||
if (BREAK_MATCHER.matcher(c).matches())
|
||||
{
|
||||
breakIndex = sb.length();
|
||||
}
|
||||
|
||||
if (i == value.length() - 1)
|
||||
{
|
||||
Line line = new Line(count, count + sb.length() - 1, sb.toString());
|
||||
editLines.add(line);
|
||||
break;
|
||||
}
|
||||
|
||||
if (font.getTextWidth(sb.toString() + value.charAt(i + 1)) < w)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (editLines.size() < this.lines - 1 || this.lines == 0)
|
||||
{
|
||||
if (breakIndex > 1)
|
||||
{
|
||||
String str = sb.substring(0, breakIndex);
|
||||
Line line = new Line(count, count + str.length() - 1, str);
|
||||
editLines.add(line);
|
||||
|
||||
sb.replace(0, breakIndex, "");
|
||||
breakIndex = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
Line line = new Line(count, count + sb.length() - 1, sb.toString());
|
||||
editLines.add(line);
|
||||
sb.replace(0, sb.length(), "");
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle bounds = new Rectangle(container.getCanvasLocation().getX() + container.getWidth(), y, 0, editLines.size() * oh);
|
||||
for (int i = 0; i < editLines.size() || i == 0; i++)
|
||||
{
|
||||
final Line line = editLines.size() > 0 ? editLines.get(i) : new Line(0, 0, "");
|
||||
final String text = line.text;
|
||||
final int len = text.length();
|
||||
|
||||
String lt = Text.escapeJagex(text);
|
||||
String mt = "";
|
||||
String rt = "";
|
||||
|
||||
final boolean isStartLine = cursorOnLine(cursorStart, line.start, line.end)
|
||||
|| (cursorOnLine(cursorStart, line.start, line.end + 1) && i == editLines.size() - 1);
|
||||
|
||||
final boolean isEndLine = cursorOnLine(cursorEnd, line.start, line.end);
|
||||
|
||||
if (isStartLine || isEndLine || (cursorEnd > line.end && cursorStart < line.start))
|
||||
{
|
||||
final int cIdx = MiscUtils.clamp(cursorStart - line.start, 0, len);
|
||||
final int ceIdx = MiscUtils.clamp(cursorEnd - line.start, 0, len);
|
||||
|
||||
lt = Text.escapeJagex(text.substring(0, cIdx));
|
||||
mt = Text.escapeJagex(text.substring(cIdx, ceIdx));
|
||||
rt = Text.escapeJagex(text.substring(ceIdx));
|
||||
}
|
||||
|
||||
final int ltw = font.getTextWidth(lt);
|
||||
final int mtw = font.getTextWidth(mt);
|
||||
final int rtw = font.getTextWidth(rt);
|
||||
final int fullWidth = ltw + mtw + rtw;
|
||||
|
||||
int ltx = ox;
|
||||
if (w > 0)
|
||||
{
|
||||
ltx += (w - fullWidth) / 2;
|
||||
}
|
||||
|
||||
final int mtx = ltx + ltw;
|
||||
final int rtx = mtx + mtw;
|
||||
|
||||
if (ltx < bounds.x)
|
||||
{
|
||||
bounds.setLocation(ltx, bounds.y);
|
||||
}
|
||||
|
||||
if (fullWidth > bounds.width)
|
||||
{
|
||||
bounds.setSize(fullWidth, bounds.height);
|
||||
}
|
||||
|
||||
if (editLines.size() == 0 || isStartLine)
|
||||
{
|
||||
cursor.setOriginalX(mtx - 1);
|
||||
cursor.setOriginalY(y);
|
||||
cursor.setOriginalWidth(2);
|
||||
cursor.setOriginalHeight(h);
|
||||
cursor.revalidate();
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(lt))
|
||||
{
|
||||
final Widget leftText = container.createChild(-1, WidgetType.TEXT);
|
||||
leftText.setFontId(fontID);
|
||||
leftText.setText(lt);
|
||||
leftText.setOriginalX(ltx);
|
||||
leftText.setOriginalY(y);
|
||||
leftText.setOriginalWidth(ltw);
|
||||
leftText.setOriginalHeight(h);
|
||||
leftText.revalidate();
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(mt))
|
||||
{
|
||||
final Widget background = container.createChild(-1, WidgetType.RECTANGLE);
|
||||
background.setTextColor(0x113399);
|
||||
background.setFilled(true);
|
||||
background.setOriginalX(mtx - 1);
|
||||
background.setOriginalY(y);
|
||||
background.setOriginalWidth(2 + mtw);
|
||||
background.setOriginalHeight(h);
|
||||
background.revalidate();
|
||||
|
||||
final Widget middleText = container.createChild(-1, WidgetType.TEXT);
|
||||
middleText.setText(mt);
|
||||
middleText.setFontId(fontID);
|
||||
middleText.setOriginalX(mtx);
|
||||
middleText.setOriginalY(y);
|
||||
middleText.setOriginalWidth(mtw);
|
||||
middleText.setOriginalHeight(h);
|
||||
middleText.setTextColor(0xFFFFFF);
|
||||
middleText.revalidate();
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(rt))
|
||||
{
|
||||
final Widget rightText = container.createChild(-1, WidgetType.TEXT);
|
||||
rightText.setText(rt);
|
||||
rightText.setFontId(fontID);
|
||||
rightText.setOriginalX(rtx);
|
||||
rightText.setOriginalY(y);
|
||||
rightText.setOriginalWidth(rtw);
|
||||
rightText.setOriginalHeight(h);
|
||||
rightText.revalidate();
|
||||
}
|
||||
|
||||
y += h;
|
||||
}
|
||||
|
||||
net.runelite.api.Point ccl = container.getCanvasLocation();
|
||||
|
||||
isInBounds = ev -> bounds.contains(new Point(ev.getX() - ccl.getX(), ev.getY() - ccl.getY()));
|
||||
getPointCharOffset = p ->
|
||||
{
|
||||
if (bounds.width <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cx = p.x - ccl.getX() - ox;
|
||||
int cy = p.y - ccl.getY() - oy;
|
||||
|
||||
int currentLine = MiscUtils.clamp(cy / oh, 0, editLines.size() - 1);
|
||||
|
||||
final Line line = editLines.get(currentLine);
|
||||
final String tsValue = line.text;
|
||||
int charIndex = tsValue.length();
|
||||
int fullWidth = font.getTextWidth(tsValue);
|
||||
|
||||
int tx = ox;
|
||||
if (w > 0)
|
||||
{
|
||||
tx += (w - fullWidth) / 2;
|
||||
}
|
||||
cx -= tx;
|
||||
|
||||
// `i` is used to track max execution time incase there is a font with ligature width data that causes this to fail
|
||||
for (int i = tsValue.length(); i >= 0 && charIndex >= 0 && charIndex <= tsValue.length(); i--)
|
||||
{
|
||||
int lcx = charIndex > 0 ? font.getTextWidth(Text.escapeJagex(tsValue.substring(0, charIndex - 1))) : 0;
|
||||
int mcx = font.getTextWidth(Text.escapeJagex(tsValue.substring(0, charIndex)));
|
||||
int rcx = charIndex + 1 <= tsValue.length() ? font.getTextWidth(Text.escapeJagex(tsValue.substring(0, charIndex + 1))) : mcx;
|
||||
|
||||
int leftBound = (lcx + mcx) / 2;
|
||||
int rightBound = (mcx + rcx) / 2;
|
||||
|
||||
if (cx < leftBound)
|
||||
{
|
||||
charIndex--;
|
||||
continue;
|
||||
}
|
||||
if (cx > rightBound)
|
||||
{
|
||||
charIndex++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
charIndex = MiscUtils.clamp(charIndex, 0, tsValue.length());
|
||||
return line.start + charIndex;
|
||||
};
|
||||
|
||||
getLineOffset = code ->
|
||||
{
|
||||
if (editLines.size() < 2)
|
||||
{
|
||||
return cursorStart;
|
||||
}
|
||||
|
||||
int currentLine = -1;
|
||||
for (int i = 0; i < editLines.size(); i++)
|
||||
{
|
||||
Line l = editLines.get(i);
|
||||
if (cursorOnLine(cursorStart, l.start, l.end)
|
||||
|| (cursorOnLine(cursorStart, l.start, l.end + 1) && i == editLines.size() - 1))
|
||||
{
|
||||
currentLine = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLine == -1
|
||||
|| (code == KeyEvent.VK_UP && currentLine == 0)
|
||||
|| (code == KeyEvent.VK_DOWN && currentLine == editLines.size() - 1))
|
||||
{
|
||||
return cursorStart;
|
||||
}
|
||||
|
||||
final Line line = editLines.get(currentLine);
|
||||
final int direction = code == KeyEvent.VK_UP ? -1 : 1;
|
||||
final Point dest = new Point(cursor.getCanvasLocation().getX(), cursor.getCanvasLocation().getY() + (direction * oh));
|
||||
final int charOffset = getPointCharOffset.applyAsInt(dest);
|
||||
|
||||
// Place cursor on right line if whitespace keep it on the same line or skip a line
|
||||
final Line nextLine = editLines.get(currentLine + direction);
|
||||
if ((direction == -1 && charOffset >= line.start)
|
||||
|| (direction == 1 && (charOffset > nextLine.end && (currentLine + direction != editLines.size() - 1))))
|
||||
{
|
||||
return nextLine.end;
|
||||
}
|
||||
|
||||
return charOffset;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean cursorOnLine(final int cursor, final int start, final int end)
|
||||
{
|
||||
return (cursor >= start) && (cursor <= end);
|
||||
}
|
||||
|
||||
private int getCharOffset(MouseEvent ev)
|
||||
{
|
||||
if (getPointCharOffset == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getPointCharOffset.applyAsInt(ev.getPoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void open()
|
||||
{
|
||||
this.built = true;
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void close()
|
||||
{
|
||||
if (this.onClose != null)
|
||||
{
|
||||
this.onClose.run();
|
||||
}
|
||||
}
|
||||
|
||||
public ChatboxTextInput build()
|
||||
{
|
||||
if (prompt == null)
|
||||
{
|
||||
throw new IllegalStateException("prompt must be non-null");
|
||||
}
|
||||
chatboxPanelManager.openInput(this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e)
|
||||
{
|
||||
char c = e.getKeyChar();
|
||||
if (charValidator.test(c))
|
||||
{
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
}
|
||||
value.insert(cursorStart, c);
|
||||
cursorAt(cursorStart + 1);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent ev)
|
||||
{
|
||||
int code = ev.getKeyCode();
|
||||
if (ev.isControlDown())
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case KeyEvent.VK_X:
|
||||
case KeyEvent.VK_C:
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
String s = value.substring(cursorStart, cursorEnd);
|
||||
if (code == KeyEvent.VK_X)
|
||||
{
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
cursorAt(cursorStart);
|
||||
}
|
||||
Toolkit.getDefaultToolkit()
|
||||
.getSystemClipboard()
|
||||
.setContents(new StringSelection(s), null);
|
||||
}
|
||||
return;
|
||||
case KeyEvent.VK_V:
|
||||
try
|
||||
{
|
||||
String s = Toolkit.getDefaultToolkit()
|
||||
.getSystemClipboard()
|
||||
.getData(DataFlavor.stringFlavor)
|
||||
.toString();
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
}
|
||||
for (int i = 0; i < s.length(); i++)
|
||||
{
|
||||
char ch = s.charAt(i);
|
||||
if (charValidator.test(ch))
|
||||
{
|
||||
value.insert(cursorStart, ch);
|
||||
cursorStart++;
|
||||
}
|
||||
}
|
||||
cursorAt(cursorStart);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
}
|
||||
}
|
||||
catch (IOException | UnsupportedFlavorException ex)
|
||||
{
|
||||
log.warn("Unable to get clipboard", ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
int newPos = cursorStart;
|
||||
if (ev.isShiftDown())
|
||||
{
|
||||
if (selectionEnd == -1 || selectionStart == -1)
|
||||
{
|
||||
selectionStart = cursorStart;
|
||||
selectionEnd = cursorStart;
|
||||
}
|
||||
newPos = selectionEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectionStart = -1;
|
||||
selectionEnd = -1;
|
||||
}
|
||||
switch (code)
|
||||
{
|
||||
case KeyEvent.VK_DELETE:
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
cursorAt(cursorStart);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cursorStart < value.length())
|
||||
{
|
||||
value.deleteCharAt(cursorStart);
|
||||
cursorAt(cursorStart);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
}
|
||||
}
|
||||
return;
|
||||
case KeyEvent.VK_BACK_SPACE:
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
cursorAt(cursorStart);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cursorStart > 0)
|
||||
{
|
||||
value.deleteCharAt(cursorStart - 1);
|
||||
cursorAt(cursorStart - 1);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
}
|
||||
}
|
||||
return;
|
||||
case KeyEvent.VK_LEFT:
|
||||
ev.consume();
|
||||
newPos--;
|
||||
break;
|
||||
case KeyEvent.VK_RIGHT:
|
||||
ev.consume();
|
||||
newPos++;
|
||||
break;
|
||||
case KeyEvent.VK_UP:
|
||||
ev.consume();
|
||||
newPos = getLineOffset.applyAsInt(code);
|
||||
break;
|
||||
case KeyEvent.VK_DOWN:
|
||||
ev.consume();
|
||||
newPos = getLineOffset.applyAsInt(code);
|
||||
break;
|
||||
case KeyEvent.VK_HOME:
|
||||
ev.consume();
|
||||
newPos = 0;
|
||||
break;
|
||||
case KeyEvent.VK_END:
|
||||
ev.consume();
|
||||
newPos = value.length();
|
||||
break;
|
||||
case KeyEvent.VK_ENTER:
|
||||
ev.consume();
|
||||
if (onDone != null)
|
||||
{
|
||||
onDone.accept(getValue());
|
||||
}
|
||||
chatboxPanelManager.close();
|
||||
return;
|
||||
case KeyEvent.VK_ESCAPE:
|
||||
ev.consume();
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
cursorAt(cursorStart);
|
||||
return;
|
||||
}
|
||||
chatboxPanelManager.close();
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (newPos > value.length())
|
||||
{
|
||||
newPos = value.length();
|
||||
}
|
||||
if (newPos < 0)
|
||||
{
|
||||
newPos = 0;
|
||||
}
|
||||
if (ev.isShiftDown())
|
||||
{
|
||||
selectionEnd = newPos;
|
||||
cursorAt(selectionStart, newPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
cursorAt(newPos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseClicked(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
if (mouseEvent.getButton() != MouseEvent.BUTTON1)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
if (isInBounds == null || !isInBounds.test(mouseEvent))
|
||||
{
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
selectionStart = -1;
|
||||
selectionEnd = -1;
|
||||
cursorAt(getCharOffset(mouseEvent));
|
||||
}
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
int nco = getCharOffset(mouseEvent);
|
||||
|
||||
if (mouseEvent.isShiftDown() && selectionEnd != -1)
|
||||
{
|
||||
selectionEnd = nco;
|
||||
cursorAt(selectionStart, selectionEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectionStart = nco;
|
||||
cursorAt(nco);
|
||||
}
|
||||
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseReleased(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseDragged(MouseEvent mouseEvent)
|
||||
{
|
||||
if (!SwingUtilities.isLeftMouseButton(mouseEvent))
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
int nco = getCharOffset(mouseEvent);
|
||||
if (selectionStart != -1)
|
||||
{
|
||||
selectionEnd = nco;
|
||||
cursorAt(selectionStart, selectionEnd);
|
||||
}
|
||||
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseMoved(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
/*
|
||||
* 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.game.chatbox;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.FontID;
|
||||
import net.runelite.api.widgets.JavaScriptCallback;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetPositionMode;
|
||||
import net.runelite.api.widgets.WidgetSizeMode;
|
||||
import net.runelite.api.widgets.WidgetTextAlignment;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.client.input.KeyListener;
|
||||
|
||||
@Slf4j
|
||||
public class ChatboxTextMenuInput extends ChatboxInput implements KeyListener
|
||||
{
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
private static final class Entry
|
||||
{
|
||||
private String text;
|
||||
private Runnable callback;
|
||||
}
|
||||
|
||||
private final ChatboxPanelManager chatboxPanelManager;
|
||||
|
||||
@Getter
|
||||
private String title;
|
||||
|
||||
@Getter
|
||||
private List<Entry> options = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
private Runnable onClose;
|
||||
|
||||
@Inject
|
||||
protected ChatboxTextMenuInput(ChatboxPanelManager chatboxPanelManager)
|
||||
{
|
||||
this.chatboxPanelManager = chatboxPanelManager;
|
||||
}
|
||||
|
||||
public ChatboxTextMenuInput title(String title)
|
||||
{
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextMenuInput option(String text, Runnable callback)
|
||||
{
|
||||
options.add(new Entry(text, callback));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextMenuInput onClose(Runnable onClose)
|
||||
{
|
||||
this.onClose = onClose;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextMenuInput build()
|
||||
{
|
||||
if (title == null)
|
||||
{
|
||||
throw new IllegalStateException("Title must be set");
|
||||
}
|
||||
|
||||
if (options.size() < 1)
|
||||
{
|
||||
throw new IllegalStateException("You must have atleast 1 option");
|
||||
}
|
||||
|
||||
chatboxPanelManager.openInput(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void open()
|
||||
{
|
||||
Widget container = chatboxPanelManager.getContainerWidget();
|
||||
|
||||
Widget prompt = container.createChild(-1, WidgetType.TEXT);
|
||||
prompt.setText(title);
|
||||
prompt.setTextColor(0x800000);
|
||||
prompt.setFontId(FontID.QUILL_8);
|
||||
prompt.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
|
||||
prompt.setOriginalX(0);
|
||||
prompt.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
prompt.setOriginalY(8);
|
||||
prompt.setOriginalHeight(24);
|
||||
prompt.setXTextAlignment(WidgetTextAlignment.CENTER);
|
||||
prompt.setYTextAlignment(WidgetTextAlignment.CENTER);
|
||||
prompt.setWidthMode(WidgetSizeMode.MINUS);
|
||||
prompt.revalidate();
|
||||
|
||||
int y = prompt.getRelativeX() + prompt.getHeight() + 6;
|
||||
int height = container.getHeight() - y - 8;
|
||||
int step = height / options.size();
|
||||
int maxStep = options.size() >= 3 ? 25 : 30;
|
||||
if (step > maxStep)
|
||||
{
|
||||
int ds = step - maxStep;
|
||||
step = maxStep;
|
||||
y += (ds * options.size()) / 2;
|
||||
}
|
||||
|
||||
for (Entry option : options)
|
||||
{
|
||||
Widget optWidget = container.createChild(-1, WidgetType.TEXT);
|
||||
optWidget.setText(option.text);
|
||||
optWidget.setFontId(FontID.QUILL_8);
|
||||
optWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
|
||||
optWidget.setOriginalX(0);
|
||||
optWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
optWidget.setOriginalY(y);
|
||||
optWidget.setOriginalHeight(24);
|
||||
optWidget.setXTextAlignment(WidgetTextAlignment.CENTER);
|
||||
optWidget.setYTextAlignment(WidgetTextAlignment.CENTER);
|
||||
optWidget.setWidthMode(WidgetSizeMode.MINUS);
|
||||
optWidget.setAction(0, "Continue");
|
||||
optWidget.setOnOpListener((JavaScriptCallback) ev -> callback(option));
|
||||
optWidget.setOnMouseOverListener((JavaScriptCallback) ev -> optWidget.setTextColor(0xFFFFFF));
|
||||
optWidget.setOnMouseLeaveListener((JavaScriptCallback) ev -> optWidget.setTextColor(0));
|
||||
optWidget.setHasListener(true);
|
||||
optWidget.revalidate();
|
||||
|
||||
y += step;
|
||||
}
|
||||
}
|
||||
|
||||
private void callback(Entry entry)
|
||||
{
|
||||
Widget container = chatboxPanelManager.getContainerWidget();
|
||||
container.setOnKeyListener((Object[]) null);
|
||||
|
||||
chatboxPanelManager.close();
|
||||
|
||||
entry.callback.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void close()
|
||||
{
|
||||
if (onClose != null)
|
||||
{
|
||||
onClose.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e)
|
||||
{
|
||||
char c = e.getKeyChar();
|
||||
|
||||
if (c == '\033')
|
||||
{
|
||||
chatboxPanelManager.close();
|
||||
e.consume();
|
||||
return;
|
||||
}
|
||||
|
||||
int n = c - '1';
|
||||
if (n >= 0 && n < options.size())
|
||||
{
|
||||
callback(options.get(n));
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e)
|
||||
{
|
||||
if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
|
||||
{
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,973 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Woox <https://github.com/wooxsolo>
|
||||
* 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.graphics;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.MainBufferProvider;
|
||||
import net.runelite.api.Model;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.NPCComposition;
|
||||
import net.runelite.api.Perspective;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.client.task.Schedule;
|
||||
|
||||
@Singleton
|
||||
public class ModelOutlineRenderer
|
||||
{
|
||||
/*
|
||||
* This class doesn't really "need" static variables, but they are
|
||||
* static for performance reasons. Arrays are kept outside methods
|
||||
* to avoid frequent big allocations. Arrays should mostly be seen
|
||||
* as ArrayLists. The size of them is increased whenever they need
|
||||
* to become bigger.
|
||||
*/
|
||||
|
||||
private final Client client;
|
||||
|
||||
private boolean isReset;
|
||||
private boolean usedSinceLastCheck;
|
||||
|
||||
// Dimensions of the underlying image
|
||||
private int imageWidth;
|
||||
private int imageHeight;
|
||||
|
||||
// Boundaries for the current rasterization
|
||||
private int clipX1;
|
||||
private int clipY1;
|
||||
private int clipX2;
|
||||
private int clipY2;
|
||||
|
||||
// Pixel points that would be rendered to
|
||||
private int[] visited;
|
||||
private int currentVisitedNumber = 0;
|
||||
|
||||
// Transformed vertex positions
|
||||
private int[] projectedVerticesX;
|
||||
private int[] projectedVerticesY;
|
||||
private boolean[] projectedVerticesRenderable;
|
||||
|
||||
// An array of pixel points to raster onto the image. These are checked against
|
||||
// clip boundaries and the visited array to prevent drawing on top of the model
|
||||
// and outside the scene area. They are grouped per distance to the closest pixel
|
||||
// drawn on the model.
|
||||
private int[][] outlinePixels;
|
||||
private int[] outlinePixelsLengths; // outlinePixelsLength[i] is the used length of outlinePixels[i]
|
||||
private int outlineArrayWidth;
|
||||
|
||||
// A list of pixel distances ordered from shortest to longest distance for
|
||||
// each outline width. These are calculated once upon first usage and then
|
||||
// stored here to prevent reevaluation.
|
||||
private List<List<PixelDistanceAlpha>> precomputedDistancePriorities;
|
||||
|
||||
@Inject
|
||||
private ModelOutlineRenderer(Client client)
|
||||
{
|
||||
this.client = client;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
@Schedule(period = 5, unit = ChronoUnit.SECONDS)
|
||||
public void checkUsage()
|
||||
{
|
||||
if (!isReset && !usedSinceLastCheck)
|
||||
{
|
||||
// Reset memory allocated when the rasterizer becomes inactive
|
||||
reset();
|
||||
}
|
||||
usedSinceLastCheck = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset memory used by the rasterizer
|
||||
*/
|
||||
private void reset()
|
||||
{
|
||||
visited = new int[0];
|
||||
projectedVerticesX = new int[0];
|
||||
projectedVerticesY = new int[0];
|
||||
projectedVerticesRenderable = new boolean[0];
|
||||
outlinePixels = new int[0][];
|
||||
outlinePixelsLengths = new int[0];
|
||||
precomputedDistancePriorities = new ArrayList<>(0);
|
||||
isReset = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the next power of two of a value
|
||||
*
|
||||
* @param value The value to find the next power of two of
|
||||
* @return Returns the next power of two
|
||||
*/
|
||||
private static int nextPowerOfTwo(int value)
|
||||
{
|
||||
value--;
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a triangle goes counter clockwise
|
||||
*
|
||||
* @return Returns true if the triangle goes counter clockwise and should be culled, otherwise false
|
||||
*/
|
||||
private static boolean cullFace(int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
return
|
||||
(y2 - y1) * (x3 - x2) -
|
||||
(x2 - x1) * (y3 - y2) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of pixel distances ordered by distance from closest pixel for a specific outline width.
|
||||
*
|
||||
* @param outlineWidth The outline width
|
||||
* @return Returns the list of pixel distances
|
||||
*/
|
||||
private List<PixelDistanceAlpha> getPriorityList(int outlineWidth)
|
||||
{
|
||||
while (precomputedDistancePriorities.size() <= outlineWidth)
|
||||
{
|
||||
precomputedDistancePriorities.add(null);
|
||||
}
|
||||
|
||||
// Grab the cached outline width if we have one
|
||||
if (precomputedDistancePriorities.get(outlineWidth) != null)
|
||||
{
|
||||
return precomputedDistancePriorities.get(outlineWidth);
|
||||
}
|
||||
|
||||
List<PixelDistanceAlpha> ps = new ArrayList<>();
|
||||
for (int x = 0; x <= outlineWidth; x++)
|
||||
{
|
||||
for (int y = 0; y <= outlineWidth; y++)
|
||||
{
|
||||
if (x == 0 && y == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double dist = Math.sqrt(x * x + y * y);
|
||||
if (dist > outlineWidth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int outerAlpha = outlineWidth == 1 ? 255 // For preventing division by 0
|
||||
: (int) (255 * (dist - 1) / (outlineWidth - 1));
|
||||
ps.add(new PixelDistanceAlpha(outerAlpha, x + y * outlineArrayWidth));
|
||||
}
|
||||
}
|
||||
ps.sort(Comparator.comparingDouble(PixelDistanceAlpha::getOuterAlpha));
|
||||
precomputedDistancePriorities.set(outlineWidth, ps);
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the size of outlinePixels is big enough to hold a specific
|
||||
* amount of elements. This is used to reduce the amount of if checks needed
|
||||
* when adding elements to outlinePixels.
|
||||
*
|
||||
* @param distArrayPos The position in the array
|
||||
* @param additionalMinimumSize The additional minimum size required
|
||||
*/
|
||||
private void ensureMinimumOutlineQueueSize(int distArrayPos, int additionalMinimumSize)
|
||||
{
|
||||
int minimumSize = outlinePixelsLengths[distArrayPos] + additionalMinimumSize;
|
||||
while (outlinePixels[distArrayPos].length < minimumSize)
|
||||
{
|
||||
int[] newArr = new int[nextPowerOfTwo(minimumSize)];
|
||||
System.arraycopy(outlinePixels[distArrayPos], 0, newArr, 0,
|
||||
outlinePixels[distArrayPos].length);
|
||||
outlinePixels[distArrayPos] = newArr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the visited flag for a specific amount of pixels
|
||||
*
|
||||
* @param pixelAmount The amount of pixels to reset
|
||||
*/
|
||||
private void resetVisited(int pixelAmount)
|
||||
{
|
||||
// The visited array is essentially a boolean array, but by
|
||||
// making it an int array and checking if visited[i] == currentVisitedNumber
|
||||
// and changing currentVisitedNumber for every new outline, we can essentially
|
||||
// reset the whole array without having to iterate over every element
|
||||
|
||||
if (visited.length < pixelAmount)
|
||||
{
|
||||
visited = new int[nextPowerOfTwo(pixelAmount)];
|
||||
currentVisitedNumber = 0;
|
||||
}
|
||||
|
||||
currentVisitedNumber++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the pixels that are queued for outlining
|
||||
*
|
||||
* @param outlineWidth The width of the outline to reset pixels for
|
||||
*/
|
||||
private void resetOutline(int outlineWidth)
|
||||
{
|
||||
outlineArrayWidth = outlineWidth + 2;
|
||||
|
||||
int arraySizes = outlineArrayWidth * outlineArrayWidth;
|
||||
if (outlinePixels.length < arraySizes)
|
||||
{
|
||||
outlinePixels = new int[arraySizes][];
|
||||
outlinePixelsLengths = new int[arraySizes];
|
||||
for (int i = 0; i < arraySizes; i++)
|
||||
{
|
||||
outlinePixels[i] = new int[4];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < arraySizes; i++)
|
||||
{
|
||||
outlinePixelsLengths[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates a horizontal line rasterization and adds the pixels to the left
|
||||
* and to the right to the outline queue if they are within the clip area.
|
||||
*
|
||||
* @param pixelPos The pixel position in the line where x == 0
|
||||
* @param x1 The starting x position
|
||||
* @param x2 The ending x position
|
||||
*/
|
||||
private void simulateHorizontalLineRasterizationForOutline(
|
||||
int pixelPos, int x1, int x2)
|
||||
{
|
||||
if (x2 > clipX2)
|
||||
{
|
||||
x2 = clipX2;
|
||||
}
|
||||
if (x1 < clipX1)
|
||||
{
|
||||
x1 = clipX1;
|
||||
}
|
||||
if (x1 >= x2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Queue the pixel positions to the left and to the right of the line
|
||||
ensureMinimumOutlineQueueSize(1, 2);
|
||||
if (x2 < clipX2)
|
||||
{
|
||||
outlinePixels[1][outlinePixelsLengths[1]++] = pixelPos + x2;
|
||||
}
|
||||
if (x1 > clipX1)
|
||||
{
|
||||
outlinePixels[1][outlinePixelsLengths[1]++] = pixelPos + x1 - 1;
|
||||
}
|
||||
|
||||
// Divide by 4 to account for loop unrolling
|
||||
int xDist = x2 - x1 >> 2;
|
||||
pixelPos += x1;
|
||||
|
||||
// This loop could run over 100m times per second without loop unrolling in some cases,
|
||||
// so unrolling it can give a noticeable performance boost.
|
||||
while (xDist-- > 0)
|
||||
{
|
||||
visited[pixelPos++] = currentVisitedNumber;
|
||||
visited[pixelPos++] = currentVisitedNumber;
|
||||
visited[pixelPos++] = currentVisitedNumber;
|
||||
visited[pixelPos++] = currentVisitedNumber;
|
||||
}
|
||||
|
||||
// Draw up to 3 more pixels if there were any left
|
||||
xDist = (x2 - x1) & 3;
|
||||
while (xDist-- > 0)
|
||||
{
|
||||
visited[pixelPos++] = currentVisitedNumber;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues the pixel positions above and below two horizontal lines, excluding those
|
||||
* where the x positions of the lines intersect.
|
||||
*
|
||||
* @param pixelPos The pixel position at x == 0 of the second line
|
||||
* @param x1 The starting x position of the first line
|
||||
* @param x2 The ending x position of the first line
|
||||
* @param x3 The starting x position of the second line
|
||||
* @param x4 The ending x position of the second line
|
||||
*/
|
||||
private void outlineAroundHorizontalLine(
|
||||
int pixelPos, int x1, int x2, int x3, int x4)
|
||||
{
|
||||
if (x1 < clipX1)
|
||||
{
|
||||
x1 = clipX1;
|
||||
}
|
||||
if (x2 < clipX1)
|
||||
{
|
||||
x2 = clipX1;
|
||||
}
|
||||
if (x3 < clipX1)
|
||||
{
|
||||
x3 = clipX1;
|
||||
}
|
||||
if (x4 < clipX1)
|
||||
{
|
||||
x4 = clipX1;
|
||||
}
|
||||
|
||||
if (x1 > clipX2)
|
||||
{
|
||||
x1 = clipX2;
|
||||
}
|
||||
if (x2 > clipX2)
|
||||
{
|
||||
x2 = clipX2;
|
||||
}
|
||||
if (x3 > clipX2)
|
||||
{
|
||||
x3 = clipX2;
|
||||
}
|
||||
if (x4 > clipX2)
|
||||
{
|
||||
x4 = clipX2;
|
||||
}
|
||||
|
||||
if (x1 < x3)
|
||||
{
|
||||
ensureMinimumOutlineQueueSize(outlineArrayWidth, x3 - x1);
|
||||
for (int x = x1; x < x3; x++)
|
||||
{
|
||||
outlinePixels[outlineArrayWidth][outlinePixelsLengths[outlineArrayWidth]++] = pixelPos - imageWidth + x;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ensureMinimumOutlineQueueSize(outlineArrayWidth, x1 - x3);
|
||||
for (int x = x3; x < x1; x++)
|
||||
{
|
||||
outlinePixels[outlineArrayWidth][outlinePixelsLengths[outlineArrayWidth]++] = pixelPos + x;
|
||||
}
|
||||
}
|
||||
|
||||
if (x2 < x4)
|
||||
{
|
||||
ensureMinimumOutlineQueueSize(outlineArrayWidth, x4 - x2);
|
||||
for (int x = x2; x < x4; x++)
|
||||
{
|
||||
outlinePixels[outlineArrayWidth][outlinePixelsLengths[outlineArrayWidth]++] = pixelPos + x;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ensureMinimumOutlineQueueSize(outlineArrayWidth, x2 - x4);
|
||||
for (int x = x4; x < x2; x++)
|
||||
{
|
||||
outlinePixels[outlineArrayWidth][outlinePixelsLengths[outlineArrayWidth]++] = pixelPos - imageWidth + x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates rasterization of a triangle and adds every pixel outside the triangle
|
||||
* to the outline queue.
|
||||
*
|
||||
* @param x1 The x position of the first vertex in the triangle
|
||||
* @param y1 The y position of the first vertex in the triangle
|
||||
* @param x2 The x position of the second vertex in the triangle
|
||||
* @param y2 The y position of the second vertex in the triangle
|
||||
* @param x3 The x position of the third vertex in the triangle
|
||||
* @param y3 The y position of the third vertex in the triangle
|
||||
*/
|
||||
private void simulateTriangleRasterizationForOutline(
|
||||
int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
// Swap vertices so y1 <= y2 <= y3 using bubble sort
|
||||
if (y1 > y2)
|
||||
{
|
||||
int yp = y1;
|
||||
int xp = x1;
|
||||
y1 = y2;
|
||||
y2 = yp;
|
||||
x1 = x2;
|
||||
x2 = xp;
|
||||
}
|
||||
if (y2 > y3)
|
||||
{
|
||||
int yp = y2;
|
||||
int xp = x2;
|
||||
y2 = y3;
|
||||
y3 = yp;
|
||||
x2 = x3;
|
||||
x3 = xp;
|
||||
}
|
||||
if (y1 > y2)
|
||||
{
|
||||
int yp = y1;
|
||||
int xp = x1;
|
||||
y1 = y2;
|
||||
y2 = yp;
|
||||
x1 = x2;
|
||||
x2 = xp;
|
||||
}
|
||||
|
||||
if (y1 > clipY2)
|
||||
{
|
||||
// All points are outside clip boundaries
|
||||
return;
|
||||
}
|
||||
|
||||
int slope1 = 0;
|
||||
if (y1 != y2)
|
||||
{
|
||||
slope1 = (x2 - x1 << 14) / (y2 - y1);
|
||||
}
|
||||
|
||||
int slope2 = 0;
|
||||
if (y3 != y2)
|
||||
{
|
||||
slope2 = (x3 - x2 << 14) / (y3 - y2);
|
||||
}
|
||||
|
||||
int slope3 = 0;
|
||||
if (y1 != y3)
|
||||
{
|
||||
slope3 = (x1 - x3 << 14) / (y1 - y3);
|
||||
}
|
||||
|
||||
if (y2 > clipY2)
|
||||
{
|
||||
y2 = clipY2;
|
||||
}
|
||||
if (y3 > clipY2)
|
||||
{
|
||||
y3 = clipY2;
|
||||
}
|
||||
if (y1 == y3 || y3 < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
x1 <<= 14;
|
||||
x2 <<= 14;
|
||||
x3 = x1;
|
||||
|
||||
if (y1 < 0)
|
||||
{
|
||||
x3 -= y1 * slope3;
|
||||
x1 -= y1 * slope1;
|
||||
y1 = 0;
|
||||
}
|
||||
if (y2 < 0)
|
||||
{
|
||||
x2 -= slope2 * y2;
|
||||
y2 = 0;
|
||||
}
|
||||
|
||||
int pixelPos = y1 * imageWidth;
|
||||
int currX1;
|
||||
int currX2;
|
||||
if (y1 != y2 && slope3 < slope1 || y1 == y2 && slope3 > slope2)
|
||||
{
|
||||
int height1 = y2 - y1;
|
||||
int height2 = y3 - y2;
|
||||
|
||||
int prevX1;
|
||||
int prevX2;
|
||||
if (height1 <= 0)
|
||||
{
|
||||
prevX1 = x3 >> 14;
|
||||
prevX2 = x2 >> 14;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevX1 = x3 >> 14;
|
||||
prevX2 = x1 >> 14;
|
||||
}
|
||||
|
||||
outlineAroundHorizontalLine(pixelPos, prevX1, prevX2, prevX2, prevX2);
|
||||
|
||||
while (height1-- > 0)
|
||||
{
|
||||
currX1 = x3 >> 14;
|
||||
currX2 = x1 >> 14;
|
||||
outlineAroundHorizontalLine(pixelPos, currX1, currX2, prevX1, prevX2);
|
||||
simulateHorizontalLineRasterizationForOutline(pixelPos, currX1, currX2);
|
||||
x3 += slope3;
|
||||
x1 += slope1;
|
||||
pixelPos += imageWidth;
|
||||
prevX1 = currX1;
|
||||
prevX2 = currX2;
|
||||
}
|
||||
|
||||
while (height2-- > 0)
|
||||
{
|
||||
currX1 = x3 >> 14;
|
||||
currX2 = x2 >> 14;
|
||||
outlineAroundHorizontalLine(pixelPos, currX1, currX2, prevX1, prevX2);
|
||||
simulateHorizontalLineRasterizationForOutline(pixelPos, currX1, currX2);
|
||||
x3 += slope3;
|
||||
x2 += slope2;
|
||||
pixelPos += imageWidth;
|
||||
prevX1 = currX1;
|
||||
prevX2 = currX2;
|
||||
}
|
||||
|
||||
outlineAroundHorizontalLine(pixelPos, prevX1, prevX1, prevX1, prevX2);
|
||||
}
|
||||
else
|
||||
{
|
||||
int height1 = y2 - y1;
|
||||
int height2 = y3 - y2;
|
||||
|
||||
int prevX1;
|
||||
int prevX2;
|
||||
if (height1 <= 0)
|
||||
{
|
||||
prevX1 = x2 >> 14;
|
||||
prevX2 = x3 >> 14;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevX1 = x1 >> 14;
|
||||
prevX2 = x3 >> 14;
|
||||
}
|
||||
|
||||
outlineAroundHorizontalLine(pixelPos, prevX1, prevX2, prevX2, prevX2);
|
||||
|
||||
while (height1-- > 0)
|
||||
{
|
||||
currX1 = x1 >> 14;
|
||||
currX2 = x3 >> 14;
|
||||
outlineAroundHorizontalLine(pixelPos, currX1, currX2, prevX1, prevX2);
|
||||
simulateHorizontalLineRasterizationForOutline(pixelPos, currX1, currX2);
|
||||
x1 += slope1;
|
||||
x3 += slope3;
|
||||
pixelPos += imageWidth;
|
||||
prevX1 = currX1;
|
||||
prevX2 = currX2;
|
||||
}
|
||||
|
||||
while (height2-- > 0)
|
||||
{
|
||||
currX1 = x2 >> 14;
|
||||
currX2 = x3 >> 14;
|
||||
outlineAroundHorizontalLine(pixelPos, currX1, currX2, prevX1, prevX2);
|
||||
simulateHorizontalLineRasterizationForOutline(pixelPos, currX1, currX2);
|
||||
x3 += slope3;
|
||||
x2 += slope2;
|
||||
pixelPos += imageWidth;
|
||||
prevX1 = currX1;
|
||||
prevX2 = currX2;
|
||||
}
|
||||
|
||||
outlineAroundHorizontalLine(pixelPos, prevX1, prevX1, prevX1, prevX2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the vertices 3D points to the screen canvas 2D points
|
||||
*
|
||||
* @param localX The local x position of the vertices
|
||||
* @param localY The local y position of the vertices
|
||||
* @param localZ The local z position of the vertices
|
||||
* @param vertexOrientation The orientation of the vertices
|
||||
* @return Returns true if any of them are inside the clip area, otherwise false
|
||||
*/
|
||||
private boolean projectVertices(Model model,
|
||||
final int localX, final int localY, final int localZ, final int vertexOrientation)
|
||||
{
|
||||
final int cameraX = client.getCameraX();
|
||||
final int cameraY = client.getCameraY();
|
||||
final int cameraZ = client.getCameraZ();
|
||||
final int cameraYaw = client.getCameraYaw();
|
||||
final int cameraPitch = client.getCameraPitch();
|
||||
final int scale = client.getScale();
|
||||
final int orientationSin = Perspective.SINE[vertexOrientation];
|
||||
final int orientationCos = Perspective.COSINE[vertexOrientation];
|
||||
final int pitchSin = Perspective.SINE[cameraPitch];
|
||||
final int pitchCos = Perspective.COSINE[cameraPitch];
|
||||
final int yawSin = Perspective.SINE[cameraYaw];
|
||||
final int yawCos = Perspective.COSINE[cameraYaw];
|
||||
final int vertexCount = model.getVerticesCount();
|
||||
final int[] verticesX = model.getVerticesX();
|
||||
final int[] verticesY = model.getVerticesY();
|
||||
final int[] verticesZ = model.getVerticesZ();
|
||||
|
||||
boolean anyVisible = false;
|
||||
|
||||
// Make sure the arrays are big enough
|
||||
while (projectedVerticesX.length < vertexCount)
|
||||
{
|
||||
int newSize = nextPowerOfTwo(vertexCount);
|
||||
projectedVerticesX = new int[newSize];
|
||||
projectedVerticesY = new int[newSize];
|
||||
projectedVerticesRenderable = new boolean[newSize];
|
||||
}
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
int vx = verticesX[i];
|
||||
int vy = verticesZ[i];
|
||||
int vz = verticesY[i];
|
||||
int vh; // Value holder
|
||||
|
||||
// Rotate based on orientation
|
||||
vh = vx * orientationCos + vy * orientationSin >> 16;
|
||||
vy = vy * orientationCos - vx * orientationSin >> 16;
|
||||
vx = vh;
|
||||
|
||||
// Translate to local coords
|
||||
vx += localX;
|
||||
vy += localY;
|
||||
vz += localZ;
|
||||
|
||||
// Translate to camera
|
||||
vx -= cameraX;
|
||||
vy -= cameraY;
|
||||
vz -= cameraZ;
|
||||
|
||||
// Transform to canvas
|
||||
vh = vx * yawCos + vy * yawSin >> 16;
|
||||
vy = vy * yawCos - vx * yawSin >> 16;
|
||||
vx = vh;
|
||||
vh = vz * pitchCos - vy * pitchSin >> 16;
|
||||
vz = vz * pitchSin + vy * pitchCos >> 16;
|
||||
vy = vh;
|
||||
|
||||
if (vz >= 50)
|
||||
{
|
||||
projectedVerticesX[i] = (clipX1 + clipX2) / 2 + vx * scale / vz;
|
||||
projectedVerticesY[i] = (clipY1 + clipY2) / 2 + vy * scale / vz;
|
||||
|
||||
projectedVerticesRenderable[i] = true;
|
||||
anyVisible |=
|
||||
projectedVerticesX[i] >= clipX1 && projectedVerticesX[i] < clipX2 &&
|
||||
projectedVerticesY[i] >= clipY1 && projectedVerticesY[i] < clipY2;
|
||||
}
|
||||
else
|
||||
{
|
||||
projectedVerticesRenderable[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
return anyVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate rendering of the model and puts every pixel of the wireframe of
|
||||
* the non-culled and non-transparent faces into the outline pixel queue.
|
||||
*/
|
||||
private void simulateModelRasterizationForOutline(Model model)
|
||||
{
|
||||
final int triangleCount = model.getTrianglesCount();
|
||||
final int[] indices1 = model.getTrianglesX();
|
||||
final int[] indices2 = model.getTrianglesY();
|
||||
final int[] indices3 = model.getTrianglesZ();
|
||||
final byte[] triangleTransparencies = model.getTriangleTransparencies();
|
||||
|
||||
for (int i = 0; i < triangleCount; i++)
|
||||
{
|
||||
if (projectedVerticesRenderable[indices1[i]] &&
|
||||
projectedVerticesRenderable[indices2[i]] &&
|
||||
projectedVerticesRenderable[indices3[i]] &&
|
||||
// 254 and 255 counts as fully transparent
|
||||
(triangleTransparencies == null || (triangleTransparencies[i] & 255) < 254))
|
||||
{
|
||||
final int index1 = indices1[i];
|
||||
final int index2 = indices2[i];
|
||||
final int index3 = indices3[i];
|
||||
final int v1x = projectedVerticesX[index1];
|
||||
final int v1y = projectedVerticesY[index1];
|
||||
final int v2x = projectedVerticesX[index2];
|
||||
final int v2y = projectedVerticesY[index2];
|
||||
final int v3x = projectedVerticesX[index3];
|
||||
final int v3y = projectedVerticesY[index3];
|
||||
|
||||
if (!cullFace(v1x, v1y, v2x, v2y, v3x, v3y))
|
||||
{
|
||||
simulateTriangleRasterizationForOutline(
|
||||
v1x, v1y, v2x, v2y, v3x, v3y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an outline of the pixels in the outline queue to an image
|
||||
*
|
||||
* @param image The image to draw the outline to
|
||||
* @param outlineWidth The width of the outline
|
||||
* @param innerColor The color of the pixels of the outline closest to the model
|
||||
* @param outerColor The color of the pixels of the outline furthest away from the model
|
||||
*/
|
||||
private void renderOutline(BufferedImage image, int outlineWidth,
|
||||
Color innerColor, Color outerColor)
|
||||
{
|
||||
int[] imageData = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
List<PixelDistanceAlpha> ps = getPriorityList(outlineWidth);
|
||||
|
||||
for (PixelDistanceAlpha p : ps)
|
||||
{
|
||||
int color;
|
||||
int alpha;
|
||||
if (outlineWidth == 1)
|
||||
{
|
||||
color =
|
||||
((innerColor.getRed() + outerColor.getRed()) << 15) |
|
||||
((innerColor.getGreen() + outerColor.getGreen() << 7)) |
|
||||
((innerColor.getBlue() + outerColor.getBlue() >> 1));
|
||||
alpha = (innerColor.getAlpha() + outerColor.getAlpha()) >> 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int outerAlpha = p.getOuterAlpha();
|
||||
int innerAlpha = 255 - outerAlpha;
|
||||
int innerAlphaFraction = (innerAlpha * innerColor.getAlpha()) / 255;
|
||||
int outerAlphaFraction = (outerAlpha * outerColor.getAlpha()) / 255;
|
||||
alpha = innerAlphaFraction + outerAlphaFraction;
|
||||
if (alpha != 0)
|
||||
{
|
||||
color =
|
||||
((innerColor.getRed() * innerAlphaFraction +
|
||||
outerColor.getRed() * outerAlphaFraction) / alpha << 16) |
|
||||
((innerColor.getGreen() * innerAlphaFraction +
|
||||
outerColor.getGreen() * outerAlphaFraction) / alpha << 8) |
|
||||
((innerColor.getBlue() * innerAlphaFraction +
|
||||
outerColor.getBlue() * outerAlphaFraction) / alpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
color = 0;
|
||||
}
|
||||
}
|
||||
|
||||
final int distArrayPos = p.getDistArrayPos();
|
||||
final int nextDistArrayPosY = distArrayPos + outlineArrayWidth;
|
||||
final int nextDistArrayPosX = distArrayPos + 1;
|
||||
ensureMinimumOutlineQueueSize(nextDistArrayPosX, outlinePixelsLengths[distArrayPos] * 2);
|
||||
ensureMinimumOutlineQueueSize(nextDistArrayPosY, outlinePixelsLengths[distArrayPos] * 2);
|
||||
|
||||
// The following 3 branches do the same thing, but when the requirements are simple,
|
||||
// there are less checks needed which can give a performance boost.
|
||||
if (alpha == 255)
|
||||
{
|
||||
if (outlineWidth == 1)
|
||||
{
|
||||
for (int i2 = 0; i2 < outlinePixelsLengths[distArrayPos]; i2++)
|
||||
{
|
||||
int pixelPos = outlinePixels[distArrayPos][i2];
|
||||
int x = pixelPos % imageWidth;
|
||||
int y = pixelPos / imageWidth;
|
||||
if (x < clipX1 || x >= clipX2 ||
|
||||
y < clipY1 || y >= clipY2 ||
|
||||
visited[pixelPos] == currentVisitedNumber)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
imageData[pixelPos] = color;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i2 = 0; i2 < outlinePixelsLengths[distArrayPos]; i2++)
|
||||
{
|
||||
int pixelPos = outlinePixels[distArrayPos][i2];
|
||||
int x = pixelPos % imageWidth;
|
||||
int y = pixelPos / imageWidth;
|
||||
if (x < clipX1 || x >= clipX2 ||
|
||||
y < clipY1 || y >= clipY2 ||
|
||||
visited[pixelPos] == currentVisitedNumber)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
visited[pixelPos] = currentVisitedNumber;
|
||||
|
||||
imageData[pixelPos] = color;
|
||||
|
||||
if (pixelPos % imageWidth != 0)
|
||||
{
|
||||
outlinePixels[nextDistArrayPosX][outlinePixelsLengths[nextDistArrayPosX]++] = pixelPos - 1;
|
||||
}
|
||||
if ((pixelPos + 1) % imageWidth != 0)
|
||||
{
|
||||
outlinePixels[nextDistArrayPosX][outlinePixelsLengths[nextDistArrayPosX]++] = pixelPos + 1;
|
||||
}
|
||||
outlinePixels[nextDistArrayPosY][outlinePixelsLengths[nextDistArrayPosY]++] = pixelPos - imageWidth;
|
||||
outlinePixels[nextDistArrayPosY][outlinePixelsLengths[nextDistArrayPosY]++] = pixelPos + imageWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i2 = 0; i2 < outlinePixelsLengths[distArrayPos]; i2++)
|
||||
{
|
||||
int pixelPos = outlinePixels[distArrayPos][i2];
|
||||
int x = pixelPos % imageWidth;
|
||||
int y = pixelPos / imageWidth;
|
||||
if (x < clipX1 || x >= clipX2 ||
|
||||
y < clipY1 || y >= clipY2 ||
|
||||
visited[pixelPos] == currentVisitedNumber)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
visited[pixelPos] = currentVisitedNumber;
|
||||
|
||||
imageData[pixelPos] =
|
||||
((((color & 0xFF0000) * alpha + (imageData[pixelPos] & 0xFF0000) * (255 - alpha)) / 255) & 0xFF0000) +
|
||||
((((color & 0xFF00) * alpha + (imageData[pixelPos] & 0xFF00) * (255 - alpha)) / 255) & 0xFF00) +
|
||||
((((color & 0xFF) * alpha + (imageData[pixelPos] & 0xFF) * (255 - alpha)) / 255) & 0xFF);
|
||||
|
||||
if (pixelPos % imageWidth != 0)
|
||||
{
|
||||
outlinePixels[nextDistArrayPosX][outlinePixelsLengths[nextDistArrayPosX]++] = pixelPos - 1;
|
||||
}
|
||||
if ((pixelPos + 1) % imageWidth != 0)
|
||||
{
|
||||
outlinePixels[nextDistArrayPosX][outlinePixelsLengths[nextDistArrayPosX]++] = pixelPos + 1;
|
||||
}
|
||||
outlinePixels[nextDistArrayPosY][outlinePixelsLengths[nextDistArrayPosY]++] = pixelPos - imageWidth;
|
||||
outlinePixels[nextDistArrayPosY][outlinePixelsLengths[nextDistArrayPosY]++] = pixelPos + imageWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an outline around a model to an image
|
||||
*
|
||||
* @param localX The local x position of the model
|
||||
* @param localY The local y position of the model
|
||||
* @param localZ The local z position of the model
|
||||
* @param orientation The orientation of the model
|
||||
* @param outlineWidth The width of the outline
|
||||
* @param innerColor The color of the pixels of the outline closest to the model
|
||||
* @param outerColor The color of the pixels of the outline furthest away from the model
|
||||
*/
|
||||
private void drawModelOutline(Model model,
|
||||
int localX, int localY, int localZ, int orientation,
|
||||
int outlineWidth, Color innerColor, Color outerColor)
|
||||
{
|
||||
if (outlineWidth <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
isReset = false;
|
||||
usedSinceLastCheck = true;
|
||||
|
||||
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
|
||||
BufferedImage image = (BufferedImage) bufferProvider.getImage();
|
||||
|
||||
clipX1 = client.getViewportXOffset();
|
||||
clipY1 = client.getViewportYOffset();
|
||||
clipX2 = client.getViewportWidth() + clipX1;
|
||||
clipY2 = client.getViewportHeight() + clipY1;
|
||||
imageWidth = image.getWidth();
|
||||
imageHeight = image.getHeight();
|
||||
final int pixelAmount = imageWidth * imageHeight;
|
||||
|
||||
resetVisited(pixelAmount);
|
||||
resetOutline(outlineWidth);
|
||||
|
||||
if (!projectVertices(model,
|
||||
localX, localY, localZ, orientation))
|
||||
{
|
||||
// No vertex of the model is visible on the screen, so we can
|
||||
// assume there are no parts of the model to outline.
|
||||
return;
|
||||
}
|
||||
|
||||
simulateModelRasterizationForOutline(model);
|
||||
|
||||
renderOutline(image, outlineWidth, innerColor, outerColor);
|
||||
}
|
||||
|
||||
public void drawOutline(NPC npc, int outlineWidth, Color color)
|
||||
{
|
||||
drawOutline(npc, outlineWidth, color, color);
|
||||
}
|
||||
|
||||
public void drawOutline(NPC npc, int outlineWidth,
|
||||
Color innerColor, Color outerColor)
|
||||
{
|
||||
int size = 1;
|
||||
NPCComposition composition = npc.getTransformedComposition();
|
||||
if (composition != null)
|
||||
{
|
||||
size = composition.getSize();
|
||||
}
|
||||
|
||||
LocalPoint lp = npc.getLocalLocation();
|
||||
if (lp != null)
|
||||
{
|
||||
// NPCs z position are calculated based on the tile height of the northeastern tile
|
||||
final int northEastX = lp.getX() + Perspective.LOCAL_TILE_SIZE * (size - 1) / 2;
|
||||
final int northEastY = lp.getY() + Perspective.LOCAL_TILE_SIZE * (size - 1) / 2;
|
||||
final LocalPoint northEastLp = new LocalPoint(northEastX, northEastY);
|
||||
|
||||
drawModelOutline(npc.getModel(), lp.getX(), lp.getY(),
|
||||
Perspective.getTileHeight(client, northEastLp, client.getPlane()),
|
||||
npc.getOrientation(), outlineWidth, innerColor, outerColor);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawOutline(Player player, int outlineWidth, Color color)
|
||||
{
|
||||
drawOutline(player, outlineWidth, color, color);
|
||||
}
|
||||
|
||||
public void drawOutline(Player player, int outlineWidth,
|
||||
Color innerColor, Color outerColor)
|
||||
{
|
||||
LocalPoint lp = player.getLocalLocation();
|
||||
if (lp != null)
|
||||
{
|
||||
drawModelOutline(player.getModel(), lp.getX(), lp.getY(),
|
||||
Perspective.getTileHeight(client, lp, client.getPlane()),
|
||||
player.getOrientation(), outlineWidth, innerColor, outerColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Woox <https://github.com/wooxsolo>
|
||||
* 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.graphics;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
@RequiredArgsConstructor
|
||||
class PixelDistanceAlpha
|
||||
{
|
||||
private final int outerAlpha;
|
||||
private final int distArrayPos;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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.input;
|
||||
|
||||
public interface KeyListener extends java.awt.event.KeyListener
|
||||
{
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* 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.input;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class KeyManager
|
||||
{
|
||||
private final List<KeyListener> keyListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
public void registerKeyListener(KeyListener keyListener)
|
||||
{
|
||||
if (!keyListeners.contains(keyListener))
|
||||
{
|
||||
keyListeners.add(keyListener);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterKeyListener(KeyListener keyListener)
|
||||
{
|
||||
keyListeners.remove(keyListener);
|
||||
}
|
||||
|
||||
public void processKeyPressed(KeyEvent keyEvent)
|
||||
{
|
||||
for (KeyListener keyListener : keyListeners)
|
||||
{
|
||||
keyListener.keyPressed(keyEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public void processKeyReleased(KeyEvent keyEvent)
|
||||
{
|
||||
for (KeyListener keyListener : keyListeners)
|
||||
{
|
||||
keyListener.keyReleased(keyEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public void processKeyTyped(KeyEvent keyEvent)
|
||||
{
|
||||
for (KeyListener keyListener : keyListeners)
|
||||
{
|
||||
keyListener.keyTyped(keyEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.input;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
public abstract class MouseAdapter implements MouseListener
|
||||
{
|
||||
@Override
|
||||
public MouseEvent mouseClicked(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseReleased(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseDragged(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseEvent mouseMoved(MouseEvent mouseEvent)
|
||||
{
|
||||
return mouseEvent;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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.input;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
public interface MouseListener
|
||||
{
|
||||
MouseEvent mouseClicked(MouseEvent mouseEvent);
|
||||
|
||||
MouseEvent mousePressed(MouseEvent mouseEvent);
|
||||
|
||||
MouseEvent mouseReleased(MouseEvent mouseEvent);
|
||||
|
||||
MouseEvent mouseEntered(MouseEvent mouseEvent);
|
||||
|
||||
MouseEvent mouseExited(MouseEvent mouseEvent);
|
||||
|
||||
MouseEvent mouseDragged(MouseEvent mouseEvent);
|
||||
|
||||
MouseEvent mouseMoved(MouseEvent mouseEvent);
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* 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.input;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class MouseManager
|
||||
{
|
||||
private final List<MouseListener> mouseListeners = new CopyOnWriteArrayList<>();
|
||||
private final List<MouseWheelListener> mouseWheelListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
public void registerMouseListener(MouseListener mouseListener)
|
||||
{
|
||||
if (!mouseListeners.contains(mouseListener))
|
||||
{
|
||||
mouseListeners.add(mouseListener);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerMouseListener(int position, MouseListener mouseListener)
|
||||
{
|
||||
mouseListeners.add(position, mouseListener);
|
||||
}
|
||||
|
||||
public void unregisterMouseListener(MouseListener mouseListener)
|
||||
{
|
||||
mouseListeners.remove(mouseListener);
|
||||
}
|
||||
|
||||
public void registerMouseWheelListener(MouseWheelListener mouseWheelListener)
|
||||
{
|
||||
if (!mouseWheelListeners.contains(mouseWheelListener))
|
||||
{
|
||||
mouseWheelListeners.add(mouseWheelListener);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerMouseWheelListener(int position, MouseWheelListener mouseWheelListener)
|
||||
{
|
||||
mouseWheelListeners.add(position, mouseWheelListener);
|
||||
}
|
||||
|
||||
public void unregisterMouseWheelListener(MouseWheelListener mouseWheelListener)
|
||||
{
|
||||
mouseWheelListeners.remove(mouseWheelListener);
|
||||
}
|
||||
|
||||
public MouseEvent processMousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
for (MouseListener mouseListener : mouseListeners)
|
||||
{
|
||||
mouseEvent = mouseListener.mousePressed(mouseEvent);
|
||||
}
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
public MouseEvent processMouseReleased(MouseEvent mouseEvent)
|
||||
{
|
||||
for (MouseListener mouseListener : mouseListeners)
|
||||
{
|
||||
mouseEvent = mouseListener.mouseReleased(mouseEvent);
|
||||
}
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
public MouseEvent processMouseClicked(MouseEvent mouseEvent)
|
||||
{
|
||||
for (MouseListener mouseListener : mouseListeners)
|
||||
{
|
||||
mouseEvent = mouseListener.mouseClicked(mouseEvent);
|
||||
}
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
public MouseEvent processMouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
for (MouseListener mouseListener : mouseListeners)
|
||||
{
|
||||
mouseEvent = mouseListener.mouseEntered(mouseEvent);
|
||||
}
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
public MouseEvent processMouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
for (MouseListener mouseListener : mouseListeners)
|
||||
{
|
||||
mouseEvent = mouseListener.mouseExited(mouseEvent);
|
||||
}
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
public MouseEvent processMouseDragged(MouseEvent mouseEvent)
|
||||
{
|
||||
for (MouseListener mouseListener : mouseListeners)
|
||||
{
|
||||
mouseEvent = mouseListener.mouseDragged(mouseEvent);
|
||||
}
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
public MouseEvent processMouseMoved(MouseEvent mouseEvent)
|
||||
{
|
||||
for (MouseListener mouseListener : mouseListeners)
|
||||
{
|
||||
mouseEvent = mouseListener.mouseMoved(mouseEvent);
|
||||
}
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
public MouseWheelEvent processMouseWheelMoved(MouseWheelEvent mouseWheelEvent)
|
||||
{
|
||||
for (MouseWheelListener mouseWheelListener : mouseWheelListeners)
|
||||
{
|
||||
mouseWheelEvent = mouseWheelListener.mouseWheelMoved(mouseWheelEvent);
|
||||
}
|
||||
return mouseWheelEvent;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.input;
|
||||
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
|
||||
public interface MouseWheelListener
|
||||
{
|
||||
MouseWheelEvent mouseWheelMoved(MouseWheelEvent event);
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Lucas <https://github.com/Lucwousin>
|
||||
* 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.menus;
|
||||
|
||||
import joptsimple.internal.Strings;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.MenuEntry;
|
||||
import static net.runelite.client.menus.MenuManager.LEVEL_PATTERN;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public class ComparableEntry
|
||||
{
|
||||
@Getter
|
||||
private String option;
|
||||
|
||||
@Getter
|
||||
private String target;
|
||||
|
||||
@Getter
|
||||
private int id;
|
||||
|
||||
@Getter
|
||||
private int type;
|
||||
|
||||
@Getter
|
||||
private boolean strictOption;
|
||||
|
||||
@Getter
|
||||
private boolean strictTarget;
|
||||
|
||||
public ComparableEntry(String option, String target)
|
||||
{
|
||||
this(option, target, -1, -1, true, true);
|
||||
}
|
||||
|
||||
public ComparableEntry(String option, String target, boolean strictTarget)
|
||||
{
|
||||
this(option, target, -1, -1, true, strictTarget);
|
||||
}
|
||||
|
||||
public ComparableEntry(String option, String target, int id, int type, boolean strictOption, boolean strictTarget)
|
||||
{
|
||||
this.option = option;
|
||||
this.target = target;
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.strictOption = strictOption;
|
||||
this.strictTarget = strictTarget;
|
||||
}
|
||||
|
||||
boolean matches(MenuEntry entry)
|
||||
{
|
||||
String opt = Text.standardize(entry.getOption());
|
||||
|
||||
if (strictOption && !opt.equals(option) || !strictOption && !opt.contains(option))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strictTarget || !Strings.isNullOrEmpty(target))
|
||||
{
|
||||
String tgt = Text.standardize(LEVEL_PATTERN.matcher(entry.getTarget()).replaceAll(""));
|
||||
|
||||
if (strictTarget && !tgt.equals(target) || !strictTarget && !tgt.contains(target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (id != -1)
|
||||
{
|
||||
int id = entry.getIdentifier();
|
||||
|
||||
if (this.id != id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (type != -1)
|
||||
{
|
||||
int type = entry.getType();
|
||||
|
||||
if (this.type != type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,814 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Robin <robin.weymans@gmail.com>
|
||||
* Copyright (c) 2019, Lucas <https://github.com/Lucwousin>
|
||||
* 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.menus;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import joptsimple.internal.Strings;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.MenuAction;
|
||||
import net.runelite.api.MenuEntry;
|
||||
import net.runelite.api.NPCComposition;
|
||||
import net.runelite.api.ObjectComposition;
|
||||
import net.runelite.api.events.MenuEntryAdded;
|
||||
import net.runelite.api.events.MenuOptionClicked;
|
||||
import net.runelite.api.events.NpcActionChanged;
|
||||
import net.runelite.api.events.PlayerMenuOptionClicked;
|
||||
import net.runelite.api.events.PlayerMenuOptionsChanged;
|
||||
import net.runelite.api.events.WidgetMenuOptionClicked;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class MenuManager
|
||||
{
|
||||
/*
|
||||
* The index needs to be between 4 and 7,
|
||||
*/
|
||||
private static final int IDX_LOWER = 4;
|
||||
private static final int IDX_UPPER = 8;
|
||||
static final Pattern LEVEL_PATTERN = Pattern.compile("\\(level-[0-9]*\\)");
|
||||
|
||||
private static MenuEntry CANCEL()
|
||||
{
|
||||
MenuEntry cancel = new MenuEntry();
|
||||
cancel.setOption("Cancel");
|
||||
cancel.setTarget("");
|
||||
cancel.setIdentifier(0);
|
||||
cancel.setType(MenuAction.CANCEL.getId());
|
||||
cancel.setParam0(0);
|
||||
cancel.setParam1(0);
|
||||
|
||||
return cancel;
|
||||
}
|
||||
|
||||
private final Client client;
|
||||
private final EventBus eventBus;
|
||||
|
||||
//Maps the indexes that are being used to the menu option.
|
||||
private final Map<Integer, String> playerMenuIndexMap = new HashMap<>();
|
||||
//Used to manage custom non-player menu options
|
||||
private final Multimap<Integer, WidgetMenuOption> managedMenuOptions = HashMultimap.create();
|
||||
private final Set<String> npcMenuOptions = new HashSet<>();
|
||||
|
||||
private final Set<ComparableEntry> priorityEntries = new HashSet<>();
|
||||
private final Set<MenuEntry> currentPriorityEntries = new HashSet<>();
|
||||
|
||||
private final Map<ComparableEntry, ComparableEntry> swaps = new HashMap<>();
|
||||
private final Set<MenuEntry> originalTypes = new HashSet<>();
|
||||
private final Set<Integer> leftClickObjects = new HashSet<>();
|
||||
|
||||
@Inject
|
||||
private MenuManager(Client client, EventBus eventBus)
|
||||
{
|
||||
this.client = client;
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a CustomMenuOption to the list of managed menu options.
|
||||
*
|
||||
* @param customMenuOption The custom menu to add
|
||||
*/
|
||||
public void addManagedCustomMenu(WidgetMenuOption customMenuOption)
|
||||
{
|
||||
WidgetInfo widget = customMenuOption.getWidget();
|
||||
managedMenuOptions.put(widget.getId(), customMenuOption);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a CustomMenuOption from the list of managed menu options.
|
||||
*
|
||||
* @param customMenuOption The custom menu to add
|
||||
*/
|
||||
public void removeManagedCustomMenu(WidgetMenuOption customMenuOption)
|
||||
{
|
||||
WidgetInfo widget = customMenuOption.getWidget();
|
||||
managedMenuOptions.remove(widget.getId(), customMenuOption);
|
||||
}
|
||||
|
||||
private boolean menuContainsCustomMenu(WidgetMenuOption customMenuOption)
|
||||
{
|
||||
for (MenuEntry menuEntry : client.getMenuEntries())
|
||||
{
|
||||
String option = menuEntry.getOption();
|
||||
String target = menuEntry.getTarget();
|
||||
|
||||
if (option.equals(customMenuOption.getMenuOption()) && target.equals(customMenuOption.getMenuTarget()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMenuEntryAdded(MenuEntryAdded event)
|
||||
{
|
||||
int widgetId = event.getActionParam1();
|
||||
Collection<WidgetMenuOption> options = managedMenuOptions.get(widgetId);
|
||||
MenuEntry[] menuEntries = client.getMenuEntries();
|
||||
|
||||
if (menuEntries.length == 1)
|
||||
{
|
||||
// Menu entries reset, so priority entries should reset as well
|
||||
currentPriorityEntries.clear();
|
||||
|
||||
originalTypes.clear();
|
||||
}
|
||||
|
||||
for (WidgetMenuOption currentMenu : options)
|
||||
{
|
||||
if (!menuContainsCustomMenu(currentMenu))//Don't add if we have already added it to this widget
|
||||
{
|
||||
menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1);
|
||||
|
||||
MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry();
|
||||
menuEntry.setOption(currentMenu.getMenuOption());
|
||||
menuEntry.setParam1(widgetId);
|
||||
menuEntry.setTarget(currentMenu.getMenuTarget());
|
||||
menuEntry.setType(MenuAction.RUNELITE.getId());
|
||||
|
||||
client.setMenuEntries(menuEntries);
|
||||
}
|
||||
}
|
||||
|
||||
final MenuEntry newestEntry = menuEntries[menuEntries.length - 1];
|
||||
|
||||
boolean isPrio = false;
|
||||
for (ComparableEntry p : priorityEntries)
|
||||
{
|
||||
if (p.matches(newestEntry))
|
||||
{
|
||||
isPrio = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the last entry was a priority entry, keep track of it
|
||||
if (isPrio)
|
||||
{
|
||||
currentPriorityEntries.add(newestEntry);
|
||||
}
|
||||
|
||||
// Make a copy of the menu entries, cause you can't remove from Arrays.asList()
|
||||
List<MenuEntry> copy = new ArrayList<>(Arrays.asList(menuEntries));
|
||||
|
||||
// If there are entries we want to prioritize, we have to remove the rest
|
||||
if (!currentPriorityEntries.isEmpty())
|
||||
{
|
||||
copy.retainAll(currentPriorityEntries);
|
||||
|
||||
copy.add(0, CANCEL());
|
||||
}
|
||||
|
||||
// Find the current entry in the swaps map
|
||||
ComparableEntry swapEntry = null;
|
||||
for (ComparableEntry e : swaps.keySet())
|
||||
{
|
||||
if (e.matches(newestEntry))
|
||||
{
|
||||
swapEntry = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (swapEntry != null)
|
||||
{
|
||||
ComparableEntry swapTarget = swaps.get(swapEntry);
|
||||
|
||||
// Find the target for the swap in current menu entries
|
||||
MenuEntry foundSwap = null;
|
||||
for (MenuEntry entry : Lists.reverse(copy))
|
||||
{
|
||||
if (swapTarget.matches(entry))
|
||||
{
|
||||
foundSwap = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundSwap != null)
|
||||
{
|
||||
// This is the menu entry added last's type
|
||||
final int otherType = foundSwap.getType();
|
||||
|
||||
// MenuActions with an id of over 1000 get shifted to the back of the menu entry array
|
||||
// They have different id's in the packet buffer though, so we got to modify them back on click
|
||||
// I couldn't get this to work with objects, so we're using modified objectcomposition for that
|
||||
final boolean shouldModifyType = otherType == MenuAction.EXAMINE_ITEM_BANK_EQ.getId();
|
||||
|
||||
if (shouldModifyType)
|
||||
{
|
||||
foundSwap.setType(MenuAction.WIDGET_DEFAULT.getId());
|
||||
originalTypes.add(foundSwap);
|
||||
}
|
||||
|
||||
// Swap
|
||||
int index = copy.indexOf(foundSwap);
|
||||
int newIndex = copy.indexOf(newestEntry);
|
||||
|
||||
copy.set(index, newestEntry);
|
||||
copy.set(newIndex, foundSwap);
|
||||
}
|
||||
}
|
||||
|
||||
client.setMenuEntries(copy.toArray(new MenuEntry[0]));
|
||||
}
|
||||
|
||||
public void addPlayerMenuItem(String menuText)
|
||||
{
|
||||
Preconditions.checkNotNull(menuText);
|
||||
|
||||
int playerMenuIndex = findEmptyPlayerMenuIndex();
|
||||
if (playerMenuIndex == IDX_UPPER)
|
||||
{
|
||||
return; // no more slots
|
||||
}
|
||||
|
||||
addPlayerMenuItem(playerMenuIndex, menuText);
|
||||
}
|
||||
|
||||
public void removePlayerMenuItem(String menuText)
|
||||
{
|
||||
Preconditions.checkNotNull(menuText);
|
||||
for (Map.Entry<Integer, String> entry : playerMenuIndexMap.entrySet())
|
||||
{
|
||||
if (entry.getValue().equalsIgnoreCase(menuText))
|
||||
{
|
||||
removePlayerMenuItem(entry.getKey());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean toggleLeftClick(String menuText, int objectID, boolean reset)
|
||||
{
|
||||
Preconditions.checkNotNull(menuText);
|
||||
|
||||
if (client == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectComposition oc = client.getObjectDefinition(objectID);
|
||||
|
||||
if (oc == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectComposition impostor = oc.getImpostorIds() != null ? oc.getImpostor() : null;
|
||||
|
||||
if (impostor != null)
|
||||
{
|
||||
if (toggleLeftClick(menuText, impostor.getId(), reset))
|
||||
{
|
||||
// Sorry about this
|
||||
leftClickObjects.remove(impostor.getId());
|
||||
|
||||
if (reset)
|
||||
{
|
||||
leftClickObjects.remove(objectID);
|
||||
}
|
||||
else
|
||||
{
|
||||
leftClickObjects.add(objectID);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
String[] options = oc.getActions();
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean hasOption5 = !Strings.isNullOrEmpty(options[options.length - 1]);
|
||||
boolean hasOption1 = !Strings.isNullOrEmpty(options[0]);
|
||||
|
||||
if (hasOption5 || hasOption1)
|
||||
{
|
||||
String option1 = options[0];
|
||||
String option5 = options[options.length - 1];
|
||||
|
||||
if (reset && !hasOption1 // Won't have to reset anything cause
|
||||
|| reset && !menuText.equalsIgnoreCase(option1) // theres nothing to reset
|
||||
|| hasOption5 && !menuText.equalsIgnoreCase(option5))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
options[0] = option5;
|
||||
options[options.length - 1] = option1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reset)
|
||||
{
|
||||
leftClickObjects.remove(objectID);
|
||||
}
|
||||
else
|
||||
{
|
||||
leftClickObjects.add(objectID);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPlayerMenuOptionsChanged(PlayerMenuOptionsChanged event)
|
||||
{
|
||||
int idx = event.getIndex();
|
||||
|
||||
String menuText = playerMenuIndexMap.get(idx);
|
||||
if (menuText == null)
|
||||
{
|
||||
return; // not our menu
|
||||
}
|
||||
|
||||
// find new index for this option
|
||||
int newIdx = findEmptyPlayerMenuIndex();
|
||||
if (newIdx == IDX_UPPER)
|
||||
{
|
||||
log.debug("Client has updated player menu index {} where option {} was, and there are no more free slots available", idx, menuText);
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Client has updated player menu index {} where option {} was, moving to index {}", idx, menuText, newIdx);
|
||||
|
||||
playerMenuIndexMap.remove(idx);
|
||||
addPlayerMenuItem(newIdx, menuText);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onNpcActionChanged(NpcActionChanged event)
|
||||
{
|
||||
NPCComposition composition = event.getNpcComposition();
|
||||
for (String npcOption : npcMenuOptions)
|
||||
{
|
||||
addNpcOption(composition, npcOption);
|
||||
}
|
||||
}
|
||||
|
||||
private void addNpcOption(NPCComposition composition, String npcOption)
|
||||
{
|
||||
String[] actions = composition.getActions();
|
||||
int unused = -1;
|
||||
for (int i = 0; i < actions.length; ++i)
|
||||
{
|
||||
if (actions[i] == null && unused == -1)
|
||||
{
|
||||
unused = i;
|
||||
}
|
||||
else if (actions[i] != null && actions[i].equals(npcOption))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unused == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
actions[unused] = npcOption;
|
||||
}
|
||||
|
||||
private void removeNpcOption(NPCComposition composition, String npcOption)
|
||||
{
|
||||
String[] actions = composition.getActions();
|
||||
|
||||
if (composition.getActions() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < actions.length; ++i)
|
||||
{
|
||||
if (actions[i] != null && actions[i].equals(npcOption))
|
||||
{
|
||||
actions[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMenuOptionClicked(MenuOptionClicked event)
|
||||
{
|
||||
if (!event.getMenuTarget().equals("do not edit") &&
|
||||
!originalTypes.isEmpty() &&
|
||||
event.getMenuAction() == MenuAction.WIDGET_DEFAULT)
|
||||
{
|
||||
for (MenuEntry e : originalTypes)
|
||||
{
|
||||
// Honestly, I was about to write a huge ass rant about
|
||||
// how I hate whoever wrote the menuoptionclicked class
|
||||
// but I decided that that'd be un-nice to them, and they
|
||||
// probably spent over 24 hours writing it. Not because
|
||||
// it was that difficult to write, of course, but because
|
||||
// they must have the fucking iq of a retarded, under developed,
|
||||
// braindead, basically good-for-nothing, idiotic chimp.
|
||||
//
|
||||
// Just kidding, of course, that would be too big of an
|
||||
// insult towards those poor chimps. It's not their fault
|
||||
// some dumbass is the way they are, right? Why should they
|
||||
// feel bad for something they can't do anything about?
|
||||
//
|
||||
// Whoever wrote that class though, should actually feel
|
||||
// 100% terrible. If they aren't depressed, I really wish
|
||||
// they become depressed very, very soon. What the fuck
|
||||
// were they even thinking.
|
||||
if (event.getMenuAction().getId() != e.getType()
|
||||
|| event.getId() != e.getIdentifier()
|
||||
|| !event.getMenuOption().equals(e.getOption()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//todo once bytecodes work again, re-enable
|
||||
/* event.consume();
|
||||
|
||||
client.invokeMenuAction(
|
||||
event.getActionParam(),
|
||||
event.getWidgetId(),
|
||||
MenuAction.EXAMINE_ITEM_BANK_EQ.getId(),
|
||||
event.getId(),
|
||||
event.getMenuOption(),
|
||||
"do not edit",
|
||||
client.getMouseCanvasPosition().getX(),
|
||||
client.getMouseCanvasPosition().getY()
|
||||
);*/
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!event.getMenuTarget().equals("do not edit") &&
|
||||
!leftClickObjects.isEmpty() &&
|
||||
event.getMenuAction() == MenuAction.GAME_OBJECT_FIRST_OPTION &&
|
||||
(
|
||||
leftClickObjects.contains(event.getId())
|
||||
||
|
||||
client.getObjectDefinition(event.getId()) != null &&
|
||||
client.getObjectDefinition(event.getId()).getImpostorIds() != null &&
|
||||
client.getObjectDefinition(event.getId()).getImpostor() != null &&
|
||||
client.getObjectDefinition(event.getId()).getImpostor().getId() == event.getId()))
|
||||
{
|
||||
//todo once bytecodes work again, re-enable
|
||||
/* event.consume();
|
||||
|
||||
client.invokeMenuAction(
|
||||
event.getActionParam(),
|
||||
event.getWidgetId(),
|
||||
MenuAction.GAME_OBJECT_FIFTH_OPTION.getId(),
|
||||
event.getId(),
|
||||
event.getMenuOption(),
|
||||
"do not edit",
|
||||
client.getMouseCanvasPosition().getX(),
|
||||
client.getMouseCanvasPosition().getY()
|
||||
);*/
|
||||
}
|
||||
|
||||
if (event.getMenuAction() != MenuAction.RUNELITE)
|
||||
{
|
||||
return; // not a player menu
|
||||
}
|
||||
|
||||
int widgetId = event.getWidgetId();
|
||||
Collection<WidgetMenuOption> options = managedMenuOptions.get(widgetId);
|
||||
|
||||
for (WidgetMenuOption curMenuOption : options)
|
||||
{
|
||||
if (curMenuOption.getMenuTarget().equals(event.getMenuTarget())
|
||||
&& curMenuOption.getMenuOption().equals(event.getMenuOption()))
|
||||
{
|
||||
WidgetMenuOptionClicked customMenu = new WidgetMenuOptionClicked();
|
||||
customMenu.setMenuOption(event.getMenuOption());
|
||||
customMenu.setMenuTarget(event.getMenuTarget());
|
||||
customMenu.setWidget(curMenuOption.getWidget());
|
||||
eventBus.post(customMenu);
|
||||
return; // don't continue because it's not a player option
|
||||
}
|
||||
}
|
||||
|
||||
String target = event.getMenuTarget();
|
||||
|
||||
// removes tags and level from player names for example:
|
||||
// <col=ffffff>username<col=40ff00> (level-42) or <col=ffffff><img=2>username</col>
|
||||
String username = Text.removeTags(target).split("[(]")[0].trim();
|
||||
|
||||
PlayerMenuOptionClicked playerMenuOptionClicked = new PlayerMenuOptionClicked();
|
||||
playerMenuOptionClicked.setMenuOption(event.getMenuOption());
|
||||
playerMenuOptionClicked.setMenuTarget(username);
|
||||
|
||||
eventBus.post(playerMenuOptionClicked);
|
||||
}
|
||||
|
||||
private void addPlayerMenuItem(int playerOptionIndex, String menuText)
|
||||
{
|
||||
client.getPlayerOptions()[playerOptionIndex] = menuText;
|
||||
client.getPlayerOptionsPriorities()[playerOptionIndex] = true;
|
||||
client.getPlayerMenuTypes()[playerOptionIndex] = MenuAction.RUNELITE.getId();
|
||||
|
||||
playerMenuIndexMap.put(playerOptionIndex, menuText);
|
||||
}
|
||||
|
||||
private void removePlayerMenuItem(int playerOptionIndex)
|
||||
{
|
||||
client.getPlayerOptions()[playerOptionIndex] = null;
|
||||
playerMenuIndexMap.remove(playerOptionIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next empty player menu slot index
|
||||
*/
|
||||
private int findEmptyPlayerMenuIndex()
|
||||
{
|
||||
int index = IDX_LOWER;
|
||||
|
||||
String[] playerOptions = client.getPlayerOptions();
|
||||
while (index < IDX_UPPER && playerOptions[index] != null)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the set of menu entries which when present, will remove all entries except for this one
|
||||
*/
|
||||
public void addPriorityEntry(String option, String target)
|
||||
{
|
||||
option = Text.standardize(option);
|
||||
target = Text.standardize(target);
|
||||
|
||||
ComparableEntry entry = new ComparableEntry(option, target);
|
||||
|
||||
priorityEntries.add(entry);
|
||||
}
|
||||
|
||||
public void removePriorityEntry(String option, String target)
|
||||
{
|
||||
option = Text.standardize(option);
|
||||
target = Text.standardize(target);
|
||||
|
||||
ComparableEntry entry = new ComparableEntry(option, target);
|
||||
|
||||
Set<ComparableEntry> toRemove = new HashSet<>();
|
||||
for (ComparableEntry priorityEntry : priorityEntries)
|
||||
{
|
||||
if (entry.equals(priorityEntry))
|
||||
{
|
||||
toRemove.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
for (ComparableEntry e : toRemove)
|
||||
{
|
||||
priorityEntries.remove(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds to the set of menu entries which when present, will remove all entries except for this one
|
||||
* This method will add one with strict option, but not-strict target (contains for target, equals for option)
|
||||
*/
|
||||
public void addPriorityEntry(String option)
|
||||
{
|
||||
option = Text.standardize(option);
|
||||
|
||||
ComparableEntry entry = new ComparableEntry(option, "", false);
|
||||
|
||||
priorityEntries.add(entry);
|
||||
}
|
||||
|
||||
public void removePriorityEntry(String option)
|
||||
{
|
||||
option = Text.standardize(option);
|
||||
|
||||
ComparableEntry entry = new ComparableEntry(option, "", false);
|
||||
|
||||
Set<ComparableEntry> toRemove = new HashSet<>();
|
||||
for (ComparableEntry priorityEntry : priorityEntries)
|
||||
{
|
||||
if (entry.equals(priorityEntry))
|
||||
{
|
||||
toRemove.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
for (ComparableEntry e : toRemove)
|
||||
{
|
||||
priorityEntries.remove(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the map of swaps. Strict options, not strict target but target1=target2
|
||||
*/
|
||||
public void addSwap(String option, String target, String option2)
|
||||
{
|
||||
addSwap(option, target, option2, target, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the map of swaps.
|
||||
*/
|
||||
public void addSwap(String option, String target, String option2, String target2, boolean strictOption, boolean strictTarget)
|
||||
{
|
||||
option = Text.standardize(option);
|
||||
target = Text.standardize(target);
|
||||
|
||||
option2 = Text.standardize(option2);
|
||||
target2 = Text.standardize(target2);
|
||||
|
||||
ComparableEntry swapFrom = new ComparableEntry(option, target, -1, -1, strictOption, strictTarget);
|
||||
ComparableEntry swapTo = new ComparableEntry(option2, target2, -1, -1, strictOption, strictTarget);
|
||||
|
||||
if (swapTo.equals(swapFrom))
|
||||
{
|
||||
log.warn("You shouldn't try swapping an entry for itself");
|
||||
return;
|
||||
}
|
||||
|
||||
swaps.put(swapFrom, swapTo);
|
||||
}
|
||||
|
||||
|
||||
public void removeSwap(String option, String target, String option2, String target2, boolean strictOption, boolean strictTarget)
|
||||
{
|
||||
option = Text.standardize(option);
|
||||
target = Text.standardize(target);
|
||||
|
||||
option2 = Text.standardize(option2);
|
||||
target2 = Text.standardize(target2);
|
||||
|
||||
ComparableEntry swapFrom = new ComparableEntry(option, target, -1, -1, strictOption, strictTarget);
|
||||
ComparableEntry swapTo = new ComparableEntry(option2, target2, -1, -1, strictOption, strictTarget);
|
||||
|
||||
removeSwap(swapFrom, swapTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the map of swaps. - Strict option + target
|
||||
*/
|
||||
public void addSwap(String option, String target, String option2, String target2)
|
||||
{
|
||||
addSwap(option, target, option2, target2, false, false);
|
||||
}
|
||||
|
||||
public void removeSwap(String option, String target, String option2, String target2)
|
||||
{
|
||||
removeSwap(option, target, option2, target2, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the map of swaps - Pre-baked Abstract entry
|
||||
*/
|
||||
public void addSwap(ComparableEntry swapFrom, ComparableEntry swapTo)
|
||||
{
|
||||
if (swapTo.equals(swapFrom))
|
||||
{
|
||||
log.warn("You shouldn't try swapping an entry for itself");
|
||||
return;
|
||||
}
|
||||
|
||||
swaps.put(swapFrom, swapTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the map of swaps - Non-strict option/target, but with type & id
|
||||
* ID's of -1 are ignored in matches()!
|
||||
*/
|
||||
public void addSwap(String option, String target, int id, int type, String option2, String target2, int id2, int type2)
|
||||
{
|
||||
option = Text.standardize(option);
|
||||
target = Text.standardize(target);
|
||||
|
||||
option2 = Text.standardize(option2);
|
||||
target2 = Text.standardize(target2);
|
||||
|
||||
ComparableEntry swapFrom = new ComparableEntry(option, target, id, type, false, false);
|
||||
ComparableEntry swapTo = new ComparableEntry(option2, target2, id2, type2, false, false);
|
||||
|
||||
if (swapTo.equals(swapFrom))
|
||||
{
|
||||
log.warn("You shouldn't try swapping an entry for itself");
|
||||
return;
|
||||
}
|
||||
|
||||
swaps.put(swapFrom, swapTo);
|
||||
}
|
||||
|
||||
public void removeSwap(String option, String target, int id, int type, String option2, String target2, int id2, int type2)
|
||||
{
|
||||
option = Text.standardize(option);
|
||||
target = Text.standardize(target);
|
||||
|
||||
option2 = Text.standardize(option2);
|
||||
target2 = Text.standardize(target2);
|
||||
|
||||
ComparableEntry swapFrom = new ComparableEntry(option, target, id, type, false, false);
|
||||
ComparableEntry swapTo = new ComparableEntry(option2, target2, id2, type2, false, false);
|
||||
|
||||
Set<ComparableEntry> toRemove = new HashSet<>();
|
||||
for (Map.Entry<ComparableEntry, ComparableEntry> e : swaps.entrySet())
|
||||
{
|
||||
if (e.getKey().equals(swapFrom) && e.getValue().equals(swapTo))
|
||||
{
|
||||
toRemove.add(e.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
for (ComparableEntry entry : toRemove)
|
||||
{
|
||||
swaps.remove(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSwap(ComparableEntry swapFrom, ComparableEntry swapTo)
|
||||
{
|
||||
Set<ComparableEntry> toRemove = new HashSet<>();
|
||||
for (Map.Entry<ComparableEntry, ComparableEntry> e : swaps.entrySet())
|
||||
{
|
||||
if (e.getKey().equals(swapFrom) && e.getValue().equals(swapTo))
|
||||
{
|
||||
toRemove.add(e.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
for (ComparableEntry entry : toRemove)
|
||||
{
|
||||
swaps.remove(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all swaps with target
|
||||
*/
|
||||
public void removeSwaps(String withTarget)
|
||||
{
|
||||
withTarget = Text.standardize(withTarget);
|
||||
|
||||
Set<ComparableEntry> toRemove = new HashSet<>();
|
||||
|
||||
for (ComparableEntry e : swaps.keySet())
|
||||
{
|
||||
if (e.getTarget().equals(withTarget))
|
||||
{
|
||||
toRemove.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
for (ComparableEntry entry : toRemove)
|
||||
{
|
||||
swaps.remove(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Robin <robin.weymans@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.menus;
|
||||
|
||||
import java.awt.Color;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.ui.JagexColors;
|
||||
import net.runelite.client.util.ColorUtil;
|
||||
|
||||
public final class WidgetMenuOption
|
||||
{
|
||||
/**
|
||||
* The left hand text to be displayed on the menu option. Ex. the menuOption of "Drop Bones" is "Drop"
|
||||
*/
|
||||
private String menuOption;
|
||||
/**
|
||||
* The right hand text to be displayed on the menu option Ex. the menuTarget of "Drop Bones" is "Bones"
|
||||
*/
|
||||
private String menuTarget;
|
||||
/**
|
||||
* The color that the menuTarget should be. Defaults to the brownish color that most menu options have.
|
||||
*/
|
||||
private Color color = JagexColors.MENU_TARGET;
|
||||
|
||||
/**
|
||||
* The widget to add the option to
|
||||
*/
|
||||
private final WidgetInfo widget;
|
||||
|
||||
/**
|
||||
* Creates a menu to be added to right click menus. The menu will only be added if match is found within the menu options
|
||||
*
|
||||
* @param menuOption Option text of this right click option
|
||||
* @param menuTarget Target text of this right click option
|
||||
* @param widget The widget to attach this option to
|
||||
*/
|
||||
public WidgetMenuOption(String menuOption, String menuTarget, WidgetInfo widget)
|
||||
{
|
||||
this.menuOption = menuOption;
|
||||
setMenuTarget(menuTarget);
|
||||
this.widget = widget;
|
||||
}
|
||||
|
||||
public void setMenuOption(String option)
|
||||
{
|
||||
menuOption = option;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target of the menu option. Color code will be added on to target
|
||||
*
|
||||
* @param target The target text without color code.
|
||||
*/
|
||||
public void setMenuTarget(String target)
|
||||
{
|
||||
menuTarget = ColorUtil.wrapWithColorTag(target, color);
|
||||
}
|
||||
|
||||
public String getMenuOption()
|
||||
{
|
||||
return menuOption;
|
||||
}
|
||||
|
||||
public String getMenuTarget()
|
||||
{
|
||||
return menuTarget;
|
||||
}
|
||||
|
||||
public WidgetInfo getWidget()
|
||||
{
|
||||
return widget;
|
||||
}
|
||||
|
||||
public Color getColor()
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(Color col)
|
||||
{
|
||||
color = col;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins;
|
||||
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import java.io.File;
|
||||
|
||||
public abstract class Plugin implements Module
|
||||
{
|
||||
protected Injector injector;
|
||||
|
||||
public File file;
|
||||
public PluginClassLoader loader;
|
||||
|
||||
@Override
|
||||
public void configure(Binder binder)
|
||||
{
|
||||
}
|
||||
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public final Injector getInjector()
|
||||
{
|
||||
return injector;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* A classloader for external plugins
|
||||
*
|
||||
* @author Adam
|
||||
*/
|
||||
public class PluginClassLoader extends URLClassLoader
|
||||
{
|
||||
private final ClassLoader parent;
|
||||
|
||||
public PluginClassLoader(File plugin, ClassLoader parent) throws MalformedURLException
|
||||
{
|
||||
super(
|
||||
new URL[]
|
||||
{
|
||||
plugin.toURI().toURL()
|
||||
},
|
||||
null // null or else class path scanning includes everything from the main class loader
|
||||
);
|
||||
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
try
|
||||
{
|
||||
return super.loadClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException ex)
|
||||
{
|
||||
// fall back to main class loader
|
||||
return parent.loadClass(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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.plugins;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
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.TYPE)
|
||||
@Documented
|
||||
public @interface PluginDependencies
|
||||
{
|
||||
PluginDependency[] value();
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.plugins;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Repeatable(PluginDependencies.class)
|
||||
public @interface PluginDependency
|
||||
{
|
||||
Class<? extends Plugin> value();
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
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.TYPE)
|
||||
@Documented
|
||||
public @interface PluginDescriptor
|
||||
{
|
||||
String name();
|
||||
|
||||
/**
|
||||
* A short, one-line summary of the plugin.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* A list of plugin keywords, used (together with the name) when searching for plugins.
|
||||
* Each tag should not contain any spaces, and should be fully lowercase.
|
||||
*/
|
||||
String[] tags() default {};
|
||||
|
||||
boolean enabledByDefault() default true;
|
||||
|
||||
/**
|
||||
* Whether or not plugin is hidden from configuration panel
|
||||
*/
|
||||
boolean hidden() default false;
|
||||
|
||||
boolean developerPlugin() default false;
|
||||
|
||||
boolean loadWhenOutdated() default false;
|
||||
|
||||
PluginType type() default PluginType.GENERAL_USE;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins;
|
||||
|
||||
public class PluginInstantiationException extends Exception
|
||||
{
|
||||
public PluginInstantiationException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public PluginInstantiationException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user