From b34d59a8f59e6d4f314cdc8c1a123b7ab6a467b7 Mon Sep 17 00:00:00 2001 From: Ron Young Date: Thu, 3 Oct 2019 23:18:37 -0500 Subject: [PATCH 01/16] plugins: add reset configuration method on plugin --- .../src/main/java/net/runelite/client/plugins/Plugin.java | 4 ++++ .../net/runelite/client/plugins/config/ConfigPanel.java | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java index be5efa9081..2dbdf009d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java @@ -45,6 +45,10 @@ public abstract class Plugin implements Module { } + public void resetConfiguration() + { + } + public final Injector getInjector() { return injector; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java index 01989d39d9..fdd2da07f4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java @@ -71,6 +71,7 @@ import net.runelite.client.events.ExternalPluginsChanged; import net.runelite.client.events.PluginChanged; import net.runelite.client.externalplugins.ExternalPluginManager; import net.runelite.client.externalplugins.ExternalPluginManifest; +import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginManager; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.DynamicGridLayout; @@ -433,6 +434,13 @@ class ConfigPanel extends PluginPanel { configManager.setDefaultConfiguration(pluginConfig.getConfig(), true); + // Reset non-config panel keys + Plugin plugin = pluginConfig.getPlugin(); + if (plugin != null) + { + plugin.resetConfiguration(); + } + rebuild(); } }); From 04ec36a120a0ff02de3e52348ed067907f8b02b9 Mon Sep 17 00:00:00 2001 From: Ron Young Date: Thu, 3 Oct 2019 23:23:44 -0500 Subject: [PATCH 02/16] banktags: reset tagtabs and banktags when reset button is clicked --- .../plugins/banktags/BankTagsPlugin.java | 34 ++++++++++++++++++- .../client/plugins/banktags/TagManager.java | 2 +- .../plugins/banktags/tabs/TabManager.java | 3 +- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java index d8352497d6..e0a795e1aa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java @@ -26,6 +26,7 @@ */ package net.runelite.client.plugins.banktags; +import com.google.common.collect.Lists; import com.google.inject.Provides; import java.awt.event.KeyEvent; import java.awt.event.MouseWheelEvent; @@ -89,6 +90,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis public static final String TAG_SEARCH = "tag:"; private static final String EDIT_TAGS_MENU_OPTION = "Edit-tags"; public static final String ICON_SEARCH = "icon_"; + public static final String TAG_TABS_CONFIG = "tagtabs"; public static final String VAR_TAG_SUFFIX = "*"; private static final String SEARCH_BANK_INPUT_TEXT = @@ -142,6 +144,36 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis return configManager.getConfig(BankTagsConfig.class); } + @Override + public void resetConfiguration() + { + List extraKeys = Lists.newArrayList( + CONFIG_GROUP + "." + TagManager.ITEM_KEY_PREFIX, + CONFIG_GROUP + "." + ICON_SEARCH, + CONFIG_GROUP + "." + TAG_TABS_CONFIG + ); + + for (String prefix : extraKeys) + { + List keys = configManager.getConfigurationKeys(prefix); + for (String key : keys) + { + String[] str = key.split("\\.", 2); + if (str.length == 2) + { + configManager.unsetConfiguration(str[0], str[1]); + } + } + } + + clientThread.invokeLater(() -> + { + tabInterface.destroy(); + tabInterface.init(); + }); + } + + @Override public void startUp() { @@ -376,7 +408,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis @Subscribe public void onConfigChanged(ConfigChanged configChanged) { - if (configChanged.getGroup().equals("banktags") && configChanged.getKey().equals("useTabs")) + if (configChanged.getGroup().equals(CONFIG_GROUP) && configChanged.getKey().equals("useTabs")) { if (config.tabs()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/TagManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/TagManager.java index d880064ff8..fe697034d0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/TagManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/TagManager.java @@ -50,7 +50,7 @@ import net.runelite.client.util.Text; @Singleton public class TagManager { - private static final String ITEM_KEY_PREFIX = "item_"; + static final String ITEM_KEY_PREFIX = "item_"; private final ConfigManager configManager; private final ItemManager itemManager; private final ClueScrollService clueScrollService; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabManager.java index e1995a5095..a3f2b06948 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabManager.java @@ -38,14 +38,13 @@ import net.runelite.api.ItemID; import net.runelite.client.config.ConfigManager; import static net.runelite.client.plugins.banktags.BankTagsPlugin.CONFIG_GROUP; import static net.runelite.client.plugins.banktags.BankTagsPlugin.ICON_SEARCH; +import static net.runelite.client.plugins.banktags.BankTagsPlugin.TAG_TABS_CONFIG; import net.runelite.client.util.Text; import org.apache.commons.lang3.math.NumberUtils; @Singleton class TabManager { - private static final String TAG_TABS_CONFIG = "tagtabs"; - @Getter private final List tabs = new ArrayList<>(); private final ConfigManager configManager; From 00fb20e750adb02bf58fa8a35b4f7bbfd1df9e5a Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Sun, 26 Jan 2020 19:42:25 +0000 Subject: [PATCH 03/16] config: add support for integer config items to have units --- .../client/config/ConfigItemDescriptor.java | 1 + .../runelite/client/config/ConfigManager.java | 3 +- .../net/runelite/client/config/Units.java | 49 +++++++++++++++++++ .../client/plugins/config/ConfigPanel.java | 12 +++++ 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/config/Units.java diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigItemDescriptor.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigItemDescriptor.java index c60d66f21a..852d9fa873 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigItemDescriptor.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigItemDescriptor.java @@ -33,4 +33,5 @@ public class ConfigItemDescriptor private final Class type; private final Range range; private final Alpha alpha; + private final Units units; } diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java index 0feb957b20..fdc2475ef0 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java @@ -455,7 +455,8 @@ public class ConfigManager m.getDeclaredAnnotation(ConfigItem.class), m.getReturnType(), m.getDeclaredAnnotation(Range.class), - m.getDeclaredAnnotation(Alpha.class) + m.getDeclaredAnnotation(Alpha.class), + m.getDeclaredAnnotation(Units.class) )) .sorted((a, b) -> ComparisonChain.start() .compare(a.getItem().position(), b.getItem().position()) diff --git a/runelite-client/src/main/java/net/runelite/client/config/Units.java b/runelite-client/src/main/java/net/runelite/client/config/Units.java new file mode 100644 index 0000000000..45d54df164 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/config/Units.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, Hydrox6 + * 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, defines what units are shown to the side of the box. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface Units +{ + String MILLISECONDS = "ms"; + String MINUTES = " mins"; + String PERCENT = "%"; + String PIXELS = "px"; + String SECONDS = "s"; + String TICKS = " ticks"; + + String value(); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java index 01989d39d9..de72de5161 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java @@ -36,6 +36,7 @@ import java.awt.event.ItemEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; +import java.text.DecimalFormat; import javax.inject.Inject; import javax.swing.BorderFactory; import javax.swing.ImageIcon; @@ -66,6 +67,7 @@ import net.runelite.client.config.ConfigManager; import net.runelite.client.config.Keybind; import net.runelite.client.config.ModifierlessKeybind; import net.runelite.client.config.Range; +import net.runelite.client.config.Units; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ExternalPluginsChanged; import net.runelite.client.events.PluginChanged; @@ -256,6 +258,16 @@ class ConfigPanel extends PluginPanel spinnerTextField.setColumns(SPINNER_FIELD_WIDTH); spinner.addChangeListener(ce -> changeConfiguration(spinner, cd, cid)); + Units units = cid.getUnits(); + if (units != null) + { + DecimalFormat df = ((JSpinner.NumberEditor) spinner.getEditor()).getFormat(); + df.setPositiveSuffix(units.value()); + df.setNegativeSuffix(units.value()); + // Force update the spinner to have it add the units initially + spinnerTextField.setValue(value); + } + item.add(spinner, BorderLayout.EAST); } From bed56b9a49c4232c1b0c7f96914f8624c31784e4 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Tue, 28 Jan 2020 21:00:22 +0000 Subject: [PATCH 04/16] plugins: add units to configs --- .../java/net/runelite/client/config/RuneLiteConfig.java | 3 ++- .../net/runelite/client/plugins/agility/AgilityConfig.java | 4 +++- .../net/runelite/client/plugins/cooking/CookingConfig.java | 4 +++- .../net/runelite/client/plugins/discord/DiscordConfig.java | 4 +++- .../client/plugins/experiencedrop/XpDropConfig.java | 2 ++ .../net/runelite/client/plugins/fishing/FishingConfig.java | 4 +++- .../client/plugins/grounditems/GroundItemsConfig.java | 2 ++ .../client/plugins/idlenotifier/IdleNotifierConfig.java | 6 +++++- .../client/plugins/motherlode/MotherlodeConfig.java | 4 +++- .../client/plugins/regenmeter/RegenMeterConfig.java | 4 +++- .../net/runelite/client/plugins/slayer/SlayerConfig.java | 4 +++- .../runelite/client/plugins/smelting/SmeltingConfig.java | 4 +++- .../client/plugins/stretchedmode/StretchedModeConfig.java | 4 +++- .../client/plugins/timetracking/TimeTrackingConfig.java | 4 +++- .../client/plugins/wintertodt/WintertodtConfig.java | 2 ++ .../client/plugins/woodcutting/WoodcuttingConfig.java | 4 +++- .../runelite/client/plugins/xpglobes/XpGlobesConfig.java | 4 ++++ .../runelite/client/plugins/xptracker/XpTrackerConfig.java | 2 ++ 18 files changed, 52 insertions(+), 13 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java index 839b8eff30..42198a248e 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java @@ -268,10 +268,11 @@ public interface RuneLiteConfig extends Config @ConfigItem( keyName = "infoBoxSize", - name = "Infobox size (px)", + name = "Infobox size", description = "Configures the size of each infobox in pixels", position = 42 ) + @Units(Units.PIXELS) default int infoBoxSize() { return 35; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java index ea608764ae..9c3fca73ad 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java @@ -28,6 +28,7 @@ import java.awt.Color; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("agility") public interface AgilityConfig extends Config @@ -56,10 +57,11 @@ public interface AgilityConfig extends Config @ConfigItem( keyName = "lapTimeout", - name = "Hide Lap Count (minutes)", + name = "Hide Lap Count", description = "Time until the lap counter hides/resets", position = 2 ) + @Units(Units.MINUTES) default int lapTimeout() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cooking/CookingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/cooking/CookingConfig.java index 2a12ac1ede..a1281a8e89 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cooking/CookingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cooking/CookingConfig.java @@ -28,6 +28,7 @@ package net.runelite.client.plugins.cooking; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("cooking") public interface CookingConfig extends Config @@ -35,9 +36,10 @@ public interface CookingConfig extends Config @ConfigItem( position = 1, keyName = "statTimeout", - name = "Reset stats (minutes)", + name = "Reset stats", description = "Configures the time until the session resets and the overlay is hidden (0 = Disable feature)" ) + @Units(Units.MINUTES) default int statTimeout() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordConfig.java index de79193a43..682d8c472c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordConfig.java @@ -27,16 +27,18 @@ package net.runelite.client.plugins.discord; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("discord") public interface DiscordConfig extends Config { @ConfigItem( keyName = "actionTimeout", - name = "Action timeout (minutes)", + name = "Action timeout", description = "Configures after how long of not updating status will be reset (in minutes)", position = 1 ) + @Units(Units.MINUTES) default int actionTimeout() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropConfig.java index ec1f1acc45..568a656ae2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropConfig.java @@ -28,6 +28,7 @@ import java.awt.Color; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("xpdrop") public interface XpDropConfig extends Config @@ -82,6 +83,7 @@ public interface XpDropConfig extends Config description = "Configures how many ticks should pass between fake XP drops, 0 to disable", position = 4 ) + @Units(Units.TICKS) default int fakeXpDropDelay() { return 0; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java index 5ccee0e752..4c9153f42a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java @@ -28,6 +28,7 @@ import java.awt.Color; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("fishing") public interface FishingConfig extends Config @@ -112,9 +113,10 @@ public interface FishingConfig extends Config @ConfigItem( position = 7, keyName = "statTimeout", - name = "Reset stats (minutes)", + name = "Reset stats", description = "The time until fishing session data is reset in minutes." ) + @Units(Units.MINUTES) default int statTimeout() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java index 41cc1afa7f..f8752f0d6b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java @@ -29,6 +29,7 @@ import java.awt.Color; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; import net.runelite.client.plugins.grounditems.config.ItemHighlightMode; import net.runelite.client.plugins.grounditems.config.MenuHighlightMode; import net.runelite.client.plugins.grounditems.config.PriceDisplayMode; @@ -343,6 +344,7 @@ public interface GroundItemsConfig extends Config description = "Decrease this number if you accidentally hide ground items often. (0 = Disabled)", position = 26 ) + @Units(Units.MILLISECONDS) default int doubleTapDelay() { return 250; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java index 200d00da4f..564cbb609b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.idlenotifier; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("idlenotifier") public interface IdleNotifierConfig extends Config @@ -77,10 +78,11 @@ public interface IdleNotifierConfig extends Config @ConfigItem( keyName = "timeout", - name = "Idle Notification Delay (ms)", + name = "Idle Notification Delay", description = "The notification delay after the player is idle", position = 5 ) + @Units(Units.MILLISECONDS) default int getIdleNotificationDelay() { return 5000; @@ -114,6 +116,7 @@ public interface IdleNotifierConfig extends Config position = 8, description = "The amount of remaining oxygen to send a notification at. A value of 0 will disable notification." ) + @Units(Units.PERCENT) default int getOxygenThreshold() { return 0; @@ -125,6 +128,7 @@ public interface IdleNotifierConfig extends Config position = 9, description = "The amount of spec energy reached to send a notification at. A value of 0 will disable notification." ) + @Units(Units.PERCENT) default int getSpecEnergyThreshold() { return 0; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeConfig.java index 10d41810e4..a32ec18c0f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeConfig.java @@ -28,6 +28,7 @@ package net.runelite.client.plugins.motherlode; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("motherlode") public interface MotherlodeConfig extends Config @@ -54,9 +55,10 @@ public interface MotherlodeConfig extends Config @ConfigItem( keyName = "statTimeout", - name = "Reset stats (minutes)", + name = "Reset stats", description = "Configures the time until statistics are reset" ) + @Units(Units.MINUTES) default int statTimeout() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/regenmeter/RegenMeterConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/regenmeter/RegenMeterConfig.java index 2e8b577381..a206557fcb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/regenmeter/RegenMeterConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/regenmeter/RegenMeterConfig.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.regenmeter; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("regenmeter") public interface RegenMeterConfig extends Config @@ -60,9 +61,10 @@ public interface RegenMeterConfig extends Config @ConfigItem( keyName = "notifyBeforeHpRegenDuration", - name = "Hitpoint Regen Notification (seconds)", + name = "Hitpoint Regen Notification", description = "Notify approximately when your next hitpoint is about to regen. A value of 0 will disable notification." ) + @Units(Units.SECONDS) default int getNotifyBeforeHpRegenSeconds() { return 0; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java index 47aa58a1ab..3abe33b392 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java @@ -29,6 +29,7 @@ import java.awt.Color; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("slayer") public interface SlayerConfig extends Config @@ -69,9 +70,10 @@ public interface SlayerConfig extends Config @ConfigItem( position = 4, keyName = "statTimeout", - name = "InfoBox Expiry (minutes)", + name = "InfoBox Expiry", description = "Set the time until the InfoBox expires" ) + @Units(Units.MINUTES) default int statTimeout() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/smelting/SmeltingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/smelting/SmeltingConfig.java index 9671f29e1a..8a0004a06e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/smelting/SmeltingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/smelting/SmeltingConfig.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.smelting; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("smelting") public interface SmeltingConfig extends Config @@ -34,9 +35,10 @@ public interface SmeltingConfig extends Config @ConfigItem( position = 1, keyName = "statTimeout", - name = "Reset stats (minutes)", + name = "Reset stats", description = "The time it takes for the current smelting session to be reset" ) + @Units(Units.MINUTES) default int statTimeout() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/StretchedModeConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/StretchedModeConfig.java index fc79768cf2..3e3433d33b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/StretchedModeConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/StretchedModeConfig.java @@ -28,6 +28,7 @@ package net.runelite.client.plugins.stretchedmode; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("stretchedmode") public interface StretchedModeConfig extends Config @@ -64,9 +65,10 @@ public interface StretchedModeConfig extends Config @ConfigItem( keyName = "scalingFactor", - name = "Resizable Scaling (%)", + name = "Resizable Scaling", description = "In resizable mode, the game is reduced in size this much before it's stretched." ) + @Units(Units.PERCENT) default int scalingFactor() { return 50; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingConfig.java index 056217673f..099c7a8f70 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingConfig.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.timetracking; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("timetracking") public interface TimeTrackingConfig extends Config @@ -72,10 +73,11 @@ public interface TimeTrackingConfig extends Config @ConfigItem( keyName = "defaultTimerMinutes", - name = "Default Time (Minutes)", + name = "Default Time", description = "The default time for the timer in minutes", position = 4 ) + @Units(Units.MINUTES) default int defaultTimerMinutes() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtConfig.java index 6b1adb7e9d..65a26893bc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtConfig.java @@ -30,6 +30,7 @@ import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; import net.runelite.client.config.Range; +import net.runelite.client.config.Units; import net.runelite.client.plugins.wintertodt.config.WintertodtNotifyMode; @ConfigGroup("wintertodt") @@ -66,6 +67,7 @@ public interface WintertodtConfig extends Config @Range( max = 60 ) + @Units(Units.SECONDS) default int roundNotification() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java index 7f992744c6..9385d4d9da 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.woodcutting; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("woodcutting") public interface WoodcuttingConfig extends Config @@ -34,9 +35,10 @@ public interface WoodcuttingConfig extends Config @ConfigItem( position = 1, keyName = "statTimeout", - name = "Reset stats (minutes)", + name = "Reset stats", description = "Configures the time until statistic is reset. Also configures when tree indicator is hidden" ) + @Units(Units.MINUTES) default int statTimeout() { return 5; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesConfig.java index 8e5f08b03b..dd5773044a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesConfig.java @@ -29,6 +29,7 @@ import net.runelite.client.config.Alpha; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("xpglobes") public interface XpGlobesConfig extends Config @@ -141,6 +142,7 @@ public interface XpGlobesConfig extends Config description = "Change the stroke width of the progress arc", position = 9 ) + @Units(Units.PIXELS) default int progressArcStrokeWidth() { return 2; @@ -152,6 +154,7 @@ public interface XpGlobesConfig extends Config description = "Change the size of the xp orbs", position = 10 ) + @Units(Units.PIXELS) default int xpOrbSize() { return 40; @@ -163,6 +166,7 @@ public interface XpGlobesConfig extends Config description = "Change the duration the xp orbs are visible", position = 11 ) + @Units(Units.SECONDS) default int xpOrbDuration() { return 10; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerConfig.java index 9f4cedef32..7a4ccf8406 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerConfig.java @@ -28,6 +28,7 @@ import lombok.AllArgsConstructor; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("xpTracker") public interface XpTrackerConfig extends Config @@ -87,6 +88,7 @@ public interface XpTrackerConfig extends Config name = "Auto pause after", description = "Configures how many minutes passes before pausing a skill while in game and there's no XP, 0 means disabled" ) + @Units(Units.MINUTES) default int pauseSkillAfter() { return 0; From 1bab5a50b8754e16854453ab1a28fb693e92ab9c Mon Sep 17 00:00:00 2001 From: Ron Young Date: Wed, 29 Jan 2020 10:52:19 -0600 Subject: [PATCH 05/16] widgetid: fix LMS INFO --- .../src/main/java/net/runelite/api/widgets/WidgetID.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index 1795e4d6c8..3734bbb509 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -857,7 +857,7 @@ public class WidgetID static class Lms { - static final int INFO = 2; + static final int INFO = 3; } static class LmsKDA From 273ebdeebf7f5c63a5fe43aef7f199926d3d4e79 Mon Sep 17 00:00:00 2001 From: Henry Darnell Date: Fri, 31 Jan 2020 20:00:11 -0600 Subject: [PATCH 06/16] Add ability and config to swap Lookup and Search in wiki plugin (#10690) --- .../client/plugins/wiki/WikiConfig.java | 44 ++++++++++ .../client/plugins/wiki/WikiPlugin.java | 81 +++++++++++++------ 2 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiConfig.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiConfig.java new file mode 100644 index 0000000000..5462023f14 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiConfig.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, Henry Darnell + * 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.wiki; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup(WikiPlugin.CONFIG_GROUP_KEY) +public interface WikiConfig extends Config +{ + @ConfigItem( + keyName = "leftClickSearch", + name = "Left Click Search", + description = "Swap left-click on the Wiki button to Search", + position = 1 + ) + default boolean leftClickSearch() + { + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java index 9458d5077f..f1646c3503 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.wiki; +import com.google.inject.Provides; import java.util.Arrays; import java.util.stream.Stream; import javax.inject.Inject; @@ -49,7 +50,9 @@ import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.widgets.WidgetPositionMode; import net.runelite.api.widgets.WidgetType; import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.game.ItemManager; import net.runelite.client.game.SpriteManager; import net.runelite.client.game.chatbox.ChatboxPanelManager; @@ -85,6 +88,9 @@ public class WikiPlugin extends Plugin @Inject private SpriteManager spriteManager; + @Inject + private WikiConfig config; + @Inject private ClientThread clientThread; @@ -104,6 +110,14 @@ public class WikiPlugin extends Plugin private boolean wikiSelected = false; + static final String CONFIG_GROUP_KEY = "wiki"; + + @Provides + WikiConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(WikiConfig.class); + } + @Override public void startUp() { @@ -113,29 +127,32 @@ public class WikiPlugin extends Plugin @Override public void shutDown() { - clientThread.invokeLater(() -> + clientThread.invokeLater(this::removeWidgets); + } + + private void removeWidgets() + { + + Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS); + if (minimapOrbs == null) { - Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS); - if (minimapOrbs == null) - { - return; - } - Widget[] children = minimapOrbs.getChildren(); - if (children == null || children.length < 1) - { - return; - } - children[0] = null; + return; + } + Widget[] children = minimapOrbs.getChildren(); + if (children == null || children.length < 1) + { + return; + } + children[0] = null; - Widget vanilla = client.getWidget(WidgetInfo.MINIMAP_WIKI_BANNER); - if (vanilla != null) - { - vanilla.setHidden(false); - } + Widget vanilla = client.getWidget(WidgetInfo.MINIMAP_WIKI_BANNER); + if (vanilla != null) + { + vanilla.setHidden(false); + } - onDeselect(); - client.setSpellSelected(false); - }); + onDeselect(); + client.setSpellSelected(false); } @Subscribe @@ -180,16 +197,17 @@ public class WikiPlugin extends Plugin icon.setSpriteId(SpriteID.WIKI_SELECTED); client.setAllWidgetsAreOpTargetable(true); }); - icon.setAction(5, "Search"); // Start at option 5 so the target op is ontop + + final int searchIndex = config.leftClickSearch() ? 4 : 5; + icon.setAction(searchIndex, "Search"); icon.setOnOpListener((JavaScriptCallback) ev -> { - switch (ev.getOp()) + if (ev.getOp() == searchIndex + 1) { - case 6: - openSearchInput(); - break; + openSearchInput(); } }); + // This doesn't always run because we cancel the menuop icon.setOnTargetLeaveListener((JavaScriptCallback) ev -> onDeselect()); icon.revalidate(); @@ -204,6 +222,19 @@ public class WikiPlugin extends Plugin } } + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals(CONFIG_GROUP_KEY)) + { + clientThread.invokeLater(() -> + { + removeWidgets(); + addWidgets(); + }); + } + } + private void onDeselect() { client.setAllWidgetsAreOpTargetable(false); From d8d6ed34c91fe776a16ed98888fadd2bfa216f74 Mon Sep 17 00:00:00 2001 From: Crypthead Date: Sat, 25 Jan 2020 02:08:35 +0100 Subject: [PATCH 07/16] client: add configuration for tooltip position --- .../client/config/RuneLiteConfig.java | 11 +++++ .../client/config/TooltipPositionType.java | 44 +++++++++++++++++++ .../ui/overlay/tooltip/TooltipOverlay.java | 16 ++++--- 3 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/config/TooltipPositionType.java diff --git a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java index 839b8eff30..0b4d964d34 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java @@ -244,6 +244,17 @@ public interface RuneLiteConfig extends Config return true; } + @ConfigItem( + keyName = "tooltipPosition", + name = "Tooltip Position", + description = "Configures whether to show the tooltip above or under the cursor", + position = 35 + ) + default TooltipPositionType tooltipPosition() + { + return TooltipPositionType.UNDER_CURSOR; + } + @ConfigItem( keyName = "infoBoxVertical", name = "Display infoboxes vertically", diff --git a/runelite-client/src/main/java/net/runelite/client/config/TooltipPositionType.java b/runelite-client/src/main/java/net/runelite/client/config/TooltipPositionType.java new file mode 100644 index 0000000000..6fb81fd72c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/config/TooltipPositionType.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, Crypthead + * 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.RequiredArgsConstructor; +import lombok.Getter; + +@Getter +@RequiredArgsConstructor +public enum TooltipPositionType +{ + ABOVE_CURSOR("Above cursor"), + UNDER_CURSOR("Under cursor"); + + private final String type; + + @Override + public String toString() + { + return type; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java index da1600450e..f269a797b5 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java @@ -32,6 +32,8 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.Client; +import net.runelite.client.config.RuneLiteConfig; +import net.runelite.client.config.TooltipPositionType; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; @@ -41,16 +43,19 @@ import net.runelite.client.ui.overlay.components.TooltipComponent; @Singleton public class TooltipOverlay extends Overlay { - private static final int OFFSET = 24; + private static final int UNDER_OFFSET = 24; + private static final int ABOVE_OFFSET = -20; private static final int PADDING = 2; private final TooltipManager tooltipManager; private final Client client; + private final RuneLiteConfig runeLiteConfig; @Inject - private TooltipOverlay(Client client, TooltipManager tooltipManager) + private TooltipOverlay(Client client, TooltipManager tooltipManager, final RuneLiteConfig runeLiteConfig) { this.client = client; this.tooltipManager = tooltipManager; + this.runeLiteConfig = runeLiteConfig; setPosition(OverlayPosition.TOOLTIP); setPriority(OverlayPriority.HIGHEST); setLayer(OverlayLayer.ALWAYS_ON_TOP); @@ -81,7 +86,8 @@ public class TooltipOverlay extends Overlay { final Rectangle clientCanvasBounds = new Rectangle(client.getRealDimensions()); final net.runelite.api.Point mouseCanvasPosition = client.getMouseCanvasPosition(); - final Point mousePosition = new Point(mouseCanvasPosition.getX(), mouseCanvasPosition.getY() + OFFSET); + final int offset = runeLiteConfig.tooltipPosition() == TooltipPositionType.UNDER_CURSOR ? UNDER_OFFSET : ABOVE_OFFSET; + final Point mousePosition = new Point(mouseCanvasPosition.getX(), mouseCanvasPosition.getY() + offset); final Rectangle bounds = new Rectangle(getBounds()); bounds.setLocation(mousePosition); @@ -94,7 +100,7 @@ public class TooltipOverlay extends Overlay if (boundsY > clientY) { - graphics.translate(0, -bounds.height - OFFSET); + graphics.translate(0, -bounds.height - offset); } if (boundsX > clientX) @@ -113,7 +119,7 @@ public class TooltipOverlay extends Overlay if (newBounds.contains(mousePosition)) { - mousePosition.move(mouseCanvasPosition.getX(), mouseCanvasPosition.getY() + OFFSET + newBounds.height); + mousePosition.move(mouseCanvasPosition.getX(), mouseCanvasPosition.getY() + offset + newBounds.height); } tooltipComponent.setPosition(mousePosition); From 61074935adba360d231231995f90883b78a7376a Mon Sep 17 00:00:00 2001 From: Alexsuperfly Date: Sun, 7 Apr 2019 10:03:23 -0400 Subject: [PATCH 08/16] idle notifier: add fishing animations --- .../plugins/idlenotifier/IdleNotifierPlugin.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java index 8d4efcdac6..9b323d13d9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java @@ -181,6 +181,18 @@ public class IdleNotifierPlugin extends Plugin /* Fishing */ case FISHING_CRUSHING_INFERNAL_EELS: case FISHING_CUTTING_SACRED_EELS: + case FISHING_BIG_NET: + case FISHING_NET: + case FISHING_POLE_CAST: + case FISHING_CAGE: + case FISHING_HARPOON: + case FISHING_BARBTAIL_HARPOON: + case FISHING_DRAGON_HARPOON: + case FISHING_INFERNAL_HARPOON: + case FISHING_CRYSTAL_HARPOON: + case FISHING_OILY_ROD: + case FISHING_KARAMBWAN: + case FISHING_BAREHAND: /* Mining(Normal) */ case MINING_BRONZE_PICKAXE: case MINING_IRON_PICKAXE: From 3f1120d23aaec675e923416d13da91c07ecd1a66 Mon Sep 17 00:00:00 2001 From: Alexsuperfly Date: Fri, 31 Jan 2020 12:10:24 -0500 Subject: [PATCH 09/16] idle notifier: prevent double notifications for anim and interact --- .../idlenotifier/IdleNotifierPlugin.java | 10 +++++ .../idlenotifier/IdleNotifierPluginTest.java | 37 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java index 9b323d13d9..637c9e442a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java @@ -561,6 +561,11 @@ public class IdleNotifierPlugin extends Plugin { lastInteract = null; lastInteracting = null; + + // prevent animation notifications from firing too + lastAnimation = IDLE; + lastAnimating = null; + return true; } } @@ -648,6 +653,11 @@ public class IdleNotifierPlugin extends Plugin { lastAnimation = IDLE; lastAnimating = null; + + // prevent interaction notifications from firing too + lastInteract = null; + lastInteracting = null; + return true; } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java index 0d4114e215..a722f6a447 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java @@ -48,8 +48,10 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import org.mockito.Mock; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -83,6 +85,9 @@ public class IdleNotifierPluginTest @Mock private NPC randomEvent; + @Mock + private NPC fishingSpot; + @Mock private Player player; @@ -103,6 +108,13 @@ public class IdleNotifierPluginTest when(randomEventComp.getActions()).thenReturn(randomEventActions); when(randomEvent.getComposition()).thenReturn(randomEventComp); + // Mock Fishing Spot + final String[] fishingSpotActions = new String[] { "Use-rod", "Examine" }; + final NPCComposition fishingSpotComp = mock(NPCComposition.class); + when(fishingSpotComp.getActions()).thenReturn(fishingSpotActions); + when(fishingSpot.getComposition()).thenReturn(fishingSpotComp); + when(fishingSpot.getName()).thenReturn("Fishing spot"); + // Mock player when(player.getName()).thenReturn(PLAYER_NAME); when(player.getAnimation()).thenReturn(AnimationID.IDLE); @@ -258,6 +270,31 @@ public class IdleNotifierPluginTest verify(notifier, times(1)).notify(any()); } + @Test + public void testSendOneNotificationForAnimationAndInteract() + { + when(player.getInteracting()).thenReturn(fishingSpot); + when(player.getAnimation()).thenReturn(AnimationID.FISHING_POLE_CAST); + + AnimationChanged animationChanged = new AnimationChanged(); + animationChanged.setActor(player); + + plugin.onInteractingChanged(new InteractingChanged(player, fishingSpot)); + plugin.onAnimationChanged(animationChanged); + plugin.onGameTick(new GameTick()); + + verify(notifier, never()).notify(anyString()); + + when(player.getAnimation()).thenReturn(AnimationID.IDLE); + lenient().when(player.getInteracting()).thenReturn(null); + + plugin.onAnimationChanged(animationChanged); + plugin.onInteractingChanged(new InteractingChanged(player, null)); + plugin.onGameTick(new GameTick()); + + verify(notifier).notify("[" + PLAYER_NAME + "] is now idle!"); + } + @Test public void testSpecRegen() { From d1ac14a7a2be771aa2a7f08ff5b387f9be2cae73 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 2 Feb 2020 14:52:19 -0500 Subject: [PATCH 10/16] wintertodt: fix interrupt notification firing when already idle --- .../runelite/client/plugins/wintertodt/WintertodtPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java index ee1eedbf1f..b89ef609aa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java @@ -305,8 +305,8 @@ public class WintertodtPlugin extends Plugin chatMessageManager.update(messageNode); client.refreshChat(); - // all actions except woodcutting are interrupted from damage - if (currentActivity != WintertodtActivity.WOODCUTTING) + // all actions except woodcutting and idle are interrupted from damage + if (currentActivity != WintertodtActivity.WOODCUTTING && currentActivity != WintertodtActivity.IDLE) { wasInterrupted = true; } From 437a1a22867d324ad1cb491bfa66a877af655272 Mon Sep 17 00:00:00 2001 From: Alexsuperfly Date: Tue, 26 Nov 2019 19:59:28 -0500 Subject: [PATCH 11/16] move capturing of screenshots to ImageCapture utility Extracts the logic for caturing/saving/uploading images from the screenshot plugin to a separate utility named ImageCapture. The Imgur class were made inner classes of ImageCapture since the only location they see use is there. ImageUploadStyle and TransferableBufferedImage were also moved to ulities to allow ImageCapture and other plugins to use them. --- .../runelite/client/RuneLiteProperties.java | 6 + .../plugins/screenshot/ScreenshotConfig.java | 5 +- .../plugins/screenshot/ScreenshotPlugin.java | 172 +----------- .../screenshot/imgur/ImageUploadRequest.java | 44 ---- .../screenshot/imgur/ImageUploadResponse.java | 40 --- .../runelite/client/util/ImageCapture.java | 244 ++++++++++++++++++ .../ImageUploadStyle.java} | 4 +- .../TransferableBufferedImage.java | 2 +- .../net/runelite/client/runelite.properties | 3 +- 9 files changed, 271 insertions(+), 249 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/screenshot/imgur/ImageUploadRequest.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/screenshot/imgur/ImageUploadResponse.java create mode 100644 runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java rename runelite-client/src/main/java/net/runelite/client/{plugins/screenshot/UploadStyle.java => util/ImageUploadStyle.java} (95%) rename runelite-client/src/main/java/net/runelite/client/{plugins/screenshot => util}/TransferableBufferedImage.java (97%) diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java index 6408be3522..83e30cbfc7 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java @@ -48,6 +48,7 @@ public class RuneLiteProperties private static final String JAV_CONFIG_BACKUP = "runelite.jav_config_backup"; private static final String PLUGINHUB_BASE = "runelite.pluginhub.url"; private static final String PLUGINHUB_VERSION = "runelite.pluginhub.version"; + private static final String IMGUR_CLIENT_ID = "runelite.imgur.client.id"; private static final Properties properties = new Properties(); @@ -139,4 +140,9 @@ public class RuneLiteProperties String version = System.getProperty(PLUGINHUB_VERSION, properties.getProperty(PLUGINHUB_VERSION)); return HttpUrl.parse(properties.get(PLUGINHUB_BASE) + "/" + version); } + + public static String getImgurClientId() + { + return properties.getProperty(IMGUR_CLIENT_ID); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java index 2158de75e3..314af4ab07 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java @@ -28,6 +28,7 @@ import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; import net.runelite.client.config.Keybind; +import net.runelite.client.util.ImageUploadStyle; @ConfigGroup("screenshot") public interface ScreenshotConfig extends Config @@ -115,9 +116,9 @@ public interface ScreenshotConfig extends Config description = "Configures whether or not screenshots are uploaded to Imgur, or placed on your clipboard", position = 7 ) - default UploadStyle uploadScreenshot() + default ImageUploadStyle uploadScreenshot() { - return UploadStyle.NEITHER; + return ImageUploadStyle.NEITHER; } @ConfigItem( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java index 2867e4d9f6..e5bdce4414 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java @@ -31,26 +31,14 @@ import com.google.inject.Provides; import java.awt.Desktop; import java.awt.Graphics; import java.awt.Image; -import java.awt.Toolkit; -import java.awt.TrayIcon; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; import java.awt.image.BufferedImage; -import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.time.LocalDate; -import java.util.Date; -import java.util.EnumSet; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.imageio.ImageIO; import javax.inject.Inject; import javax.swing.SwingUtilities; import lombok.AccessLevel; @@ -62,7 +50,6 @@ import net.runelite.api.GameState; import net.runelite.api.Player; import net.runelite.api.Point; import net.runelite.api.SpriteID; -import net.runelite.api.WorldType; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameTick; import net.runelite.api.events.PlayerDeath; @@ -86,24 +73,15 @@ import net.runelite.client.game.SpriteManager; import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.screenshot.imgur.ImageUploadRequest; -import net.runelite.client.plugins.screenshot.imgur.ImageUploadResponse; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.ClientUI; import net.runelite.client.ui.DrawManager; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.util.HotkeyListener; +import net.runelite.client.util.ImageCapture; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; -import net.runelite.http.api.RuneLiteAPI; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; @PluginDescriptor( name = "Screenshot", @@ -113,12 +91,6 @@ import okhttp3.Response; @Slf4j public class ScreenshotPlugin extends Plugin { - private static final String IMGUR_CLIENT_ID = "30d71e5f6860809"; - private static final HttpUrl IMGUR_IMAGE_UPLOAD_URL = HttpUrl.parse("https://api.imgur.com/3/image"); - private static final MediaType JSON = MediaType.parse("application/json"); - - private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); - private static final Pattern NUMBER_PATTERN = Pattern.compile("([0-9]+)"); private static final Pattern LEVEL_UP_PATTERN = Pattern.compile(".*Your ([a-zA-Z]+) (?:level is|are)? now (\\d+)\\."); private static final Pattern BOSSKILL_MESSAGE_PATTERN = Pattern.compile("Your (.+) kill count is: (\\d+)."); @@ -129,14 +101,6 @@ public class ScreenshotPlugin extends Plugin "You feel something weird sneaking into your backpack", "You have a funny feeling like you would have been followed"); - static String format(Date date) - { - synchronized (TIME_FORMAT) - { - return TIME_FORMAT.format(date); - } - } - private String clueType; private Integer clueNumber; @@ -183,6 +147,9 @@ public class ScreenshotPlugin extends Plugin @Inject private SpriteManager spriteManager; + @Inject + private ImageCapture imageCapture; + @Getter(AccessLevel.PACKAGE) private BufferedImage reportButton; @@ -193,7 +160,7 @@ public class ScreenshotPlugin extends Plugin @Override public void hotkeyPressed() { - takeScreenshot(format(new Date())); + takeScreenshot(""); } }; @@ -216,7 +183,7 @@ public class ScreenshotPlugin extends Plugin .tab(false) .tooltip("Take screenshot") .icon(iconImage) - .onClick(() -> takeScreenshot(format(new Date()))) + .onClick(() -> takeScreenshot("")) .popup(ImmutableMap .builder() .put("Open screenshot folder...", () -> @@ -284,11 +251,11 @@ public class ScreenshotPlugin extends Plugin Player player = playerDeath.getPlayer(); if (player == client.getLocalPlayer() && config.screenshotPlayerDeath()) { - takeScreenshot("Death " + format(new Date())); + takeScreenshot("Death"); } else if ((player.isClanMember() || player.isFriend()) && config.screenshotFriendDeath() && player.getCanvasTilePoly() != null) { - takeScreenshot("Death " + player.getName() + " " + format(new Date())); + takeScreenshot("Death " + player.getName()); } } @@ -299,7 +266,7 @@ public class ScreenshotPlugin extends Plugin { final Player player = playerLootReceived.getPlayer(); final String name = player.getName(); - String fileName = "Kill " + name + " " + format(new Date()); + String fileName = "Kill " + name; takeScreenshot(fileName); } } @@ -367,7 +334,7 @@ public class ScreenshotPlugin extends Plugin if (config.screenshotPet() && PET_MESSAGES.stream().anyMatch(chatMessage::contains)) { - String fileName = "Pet " + format(new Date()); + String fileName = "Pet"; takeScreenshot(fileName); } @@ -389,7 +356,7 @@ public class ScreenshotPlugin extends Plugin if (m.matches()) { String valuableDropName = m.group(1); - String fileName = "Valuable drop " + valuableDropName + " " + format(new Date()); + String fileName = "Valuable drop " + valuableDropName; takeScreenshot(fileName); } } @@ -400,7 +367,7 @@ public class ScreenshotPlugin extends Plugin if (m.matches()) { String untradeableDropName = m.group(1); - String fileName = "Untradeable drop " + untradeableDropName + " " + format(new Date()); + String fileName = "Untradeable drop " + untradeableDropName; takeScreenshot(fileName); } } @@ -615,120 +582,7 @@ public class ScreenshotPlugin extends Plugin // Draw the game onto the screenshot graphics.drawImage(image, gameOffsetX, gameOffsetY, null); - - File playerFolder; - if (client.getLocalPlayer() != null && client.getLocalPlayer().getName() != null) - { - final EnumSet worldTypes = client.getWorldType(); - - String playerDir = client.getLocalPlayer().getName(); - if (worldTypes.contains(WorldType.DEADMAN)) - { - playerDir += "-Deadman"; - } - else if (worldTypes.contains(WorldType.LEAGUE)) - { - playerDir += "-League"; - } - playerFolder = new File(SCREENSHOT_DIR, playerDir); - } - else - { - playerFolder = SCREENSHOT_DIR; - } - - playerFolder.mkdirs(); - - try - { - File screenshotFile = new File(playerFolder, fileName + ".png"); - - // To make sure that screenshots don't get overwritten, check if file exists, - // and if it does create file with same name and suffix. - int i = 1; - while (screenshotFile.exists()) - { - screenshotFile = new File(playerFolder, fileName + String.format("(%d)", i++) + ".png"); - } - - ImageIO.write(screenshot, "PNG", screenshotFile); - UploadStyle uploadStyle = config.uploadScreenshot(); - - if (uploadStyle == UploadStyle.IMGUR) - { - uploadScreenshot(screenshotFile); - } - else if (uploadStyle == UploadStyle.CLIPBOARD) - { - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - TransferableBufferedImage transferableBufferedImage = new TransferableBufferedImage(screenshot); - clipboard.setContents(transferableBufferedImage, null); - - if (config.notifyWhenTaken()) - { - notifier.notify("A screenshot was saved and inserted into your clipboard!", TrayIcon.MessageType.INFO); - } - } - else if (config.notifyWhenTaken()) - { - notifier.notify("A screenshot was saved to " + screenshotFile, TrayIcon.MessageType.INFO); - } - } - catch (IOException ex) - { - log.warn("error writing screenshot", ex); - } - } - - /** - * Uploads a screenshot to the Imgur image-hosting service, - * and copies the image link to the clipboard. - * - * @param screenshotFile Image file to upload. - * @throws IOException Thrown if the file cannot be read. - */ - private void uploadScreenshot(File screenshotFile) throws IOException - { - String json = RuneLiteAPI.GSON.toJson(new ImageUploadRequest(screenshotFile)); - - Request request = new Request.Builder() - .url(IMGUR_IMAGE_UPLOAD_URL) - .addHeader("Authorization", "Client-ID " + IMGUR_CLIENT_ID) - .post(RequestBody.create(JSON, json)) - .build(); - - RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() - { - @Override - public void onFailure(Call call, IOException ex) - { - log.warn("error uploading screenshot", ex); - } - - @Override - public void onResponse(Call call, Response response) throws IOException - { - try (InputStream in = response.body().byteStream()) - { - ImageUploadResponse imageUploadResponse = RuneLiteAPI.GSON - .fromJson(new InputStreamReader(in), ImageUploadResponse.class); - - if (imageUploadResponse.isSuccess()) - { - String link = imageUploadResponse.getData().getLink(); - - StringSelection selection = new StringSelection(link); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(selection, selection); - - if (config.notifyWhenTaken()) - { - notifier.notify("A screenshot was uploaded and inserted into your clipboard!", TrayIcon.MessageType.INFO); - } - } - } - } - }); + imageCapture.takeScreenshot(screenshot, fileName, config.notifyWhenTaken(), config.uploadScreenshot()); } @VisibleForTesting diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/imgur/ImageUploadRequest.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/imgur/ImageUploadRequest.java deleted file mode 100644 index 28c8d4f2f3..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/imgur/ImageUploadRequest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.screenshot.imgur; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Base64; -import lombok.Data; - -@Data -public class ImageUploadRequest -{ - private final String image; - private final String type; - - public ImageUploadRequest(File imageFile) throws IOException - { - this.image = Base64.getEncoder().encodeToString(Files.readAllBytes(imageFile.toPath())); - this.type = "base64"; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/imgur/ImageUploadResponse.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/imgur/ImageUploadResponse.java deleted file mode 100644 index 820ed2aded..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/imgur/ImageUploadResponse.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.screenshot.imgur; - -import lombok.Data; - -@Data -public class ImageUploadResponse -{ - private Data data; - private boolean success; - - @lombok.Data - public static class Data - { - private String link; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java b/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java new file mode 100644 index 0000000000..0331d6a50e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2018, Lotto + * Copyright (c) 2019, Alexsuperfly + * 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.util; + +import java.awt.Toolkit; +import java.awt.TrayIcon; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Base64; +import java.util.Date; +import java.util.EnumSet; +import javax.imageio.ImageIO; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.WorldType; +import net.runelite.client.Notifier; +import static net.runelite.client.RuneLite.SCREENSHOT_DIR; +import net.runelite.client.RuneLiteProperties; +import net.runelite.http.api.RuneLiteAPI; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +@Slf4j +@Singleton +public class ImageCapture +{ + private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); + private static final HttpUrl IMGUR_IMAGE_UPLOAD_URL = HttpUrl.parse("https://api.imgur.com/3/image"); + private static final MediaType JSON = MediaType.parse("application/json"); + + @Inject + private Client client; + + @Inject + private Notifier notifier; + + /** + * Saves a screenshot of the client window to the screenshot folder as a PNG, + * and optionally uploads it to an image-hosting service. + * + * @param screenshot BufferedImage to capture. + * @param fileName Filename to use, without file extension. + * @param notify Send a notification to the system tray when the image is captured. + * @param imageUploadStyle which method to use to upload the screenshot (Imgur or directly to clipboard). + */ + public void takeScreenshot(BufferedImage screenshot, String fileName, boolean notify, ImageUploadStyle imageUploadStyle) + { + if (client.getGameState() == GameState.LOGIN_SCREEN) + { + // Prevent the screenshot from being captured + log.info("Login screenshot prevented"); + return; + } + + File playerFolder; + if (client.getLocalPlayer() != null && client.getLocalPlayer().getName() != null) + { + final EnumSet worldTypes = client.getWorldType(); + + String playerDir = client.getLocalPlayer().getName(); + if (worldTypes.contains(WorldType.DEADMAN)) + { + playerDir += "-Deadman"; + } + else if (worldTypes.contains(WorldType.LEAGUE)) + { + playerDir += "-League"; + } + playerFolder = new File(SCREENSHOT_DIR, playerDir); + } + else + { + playerFolder = SCREENSHOT_DIR; + } + + playerFolder.mkdirs(); + + fileName += " " + format(new Date()); + + try + { + File screenshotFile = new File(playerFolder, fileName + ".png"); + + // To make sure that screenshots don't get overwritten, check if file exists, + // and if it does create file with same name and suffix. + int i = 1; + while (screenshotFile.exists()) + { + screenshotFile = new File(playerFolder, fileName + String.format("(%d)", i++) + ".png"); + } + + ImageIO.write(screenshot, "PNG", screenshotFile); + + if (imageUploadStyle == ImageUploadStyle.IMGUR) + { + uploadScreenshot(screenshotFile, notify); + } + else if (imageUploadStyle == ImageUploadStyle.CLIPBOARD) + { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + TransferableBufferedImage transferableBufferedImage = new TransferableBufferedImage(screenshot); + clipboard.setContents(transferableBufferedImage, null); + + if (notify) + { + notifier.notify("A screenshot was saved and inserted into your clipboard!", TrayIcon.MessageType.INFO); + } + } + else if (notify) + { + notifier.notify("A screenshot was saved to " + screenshotFile, TrayIcon.MessageType.INFO); + } + } + catch (IOException ex) + { + log.warn("error writing screenshot", ex); + } + } + + /** + * Uploads a screenshot to the Imgur image-hosting service, + * and copies the image link to the clipboard. + * + * @param screenshotFile Image file to upload. + * @throws IOException Thrown if the file cannot be read. + */ + private void uploadScreenshot(File screenshotFile, boolean notify) throws IOException + { + String json = RuneLiteAPI.GSON.toJson(new ImageUploadRequest(screenshotFile)); + + Request request = new Request.Builder() + .url(IMGUR_IMAGE_UPLOAD_URL) + .addHeader("Authorization", "Client-ID " + RuneLiteProperties.getImgurClientId()) + .post(RequestBody.create(JSON, json)) + .build(); + + RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() + { + @Override + public void onFailure(Call call, IOException ex) + { + log.warn("error uploading screenshot", ex); + } + + @Override + public void onResponse(Call call, Response response) throws IOException + { + try (InputStream in = response.body().byteStream()) + { + ImageUploadResponse imageUploadResponse = RuneLiteAPI.GSON + .fromJson(new InputStreamReader(in), ImageUploadResponse.class); + + if (imageUploadResponse.isSuccess()) + { + String link = imageUploadResponse.getData().getLink(); + + StringSelection selection = new StringSelection(link); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(selection, selection); + + if (notify) + { + notifier.notify("A screenshot was uploaded and inserted into your clipboard!", TrayIcon.MessageType.INFO); + } + } + } + } + }); + } + + private static String format(Date date) + { + synchronized (TIME_FORMAT) + { + return TIME_FORMAT.format(date); + } + } + + @Data + private static class ImageUploadResponse + { + private Data data; + private boolean success; + + @lombok.Data + private static class Data + { + private String link; + } + } + + @Data + private static class ImageUploadRequest + { + private final String image; + private final String type; + + ImageUploadRequest(File imageFile) throws IOException + { + this.image = Base64.getEncoder().encodeToString(Files.readAllBytes(imageFile.toPath())); + this.type = "base64"; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/UploadStyle.java b/runelite-client/src/main/java/net/runelite/client/util/ImageUploadStyle.java similarity index 95% rename from runelite-client/src/main/java/net/runelite/client/plugins/screenshot/UploadStyle.java rename to runelite-client/src/main/java/net/runelite/client/util/ImageUploadStyle.java index fd0594e7ba..95c75536a4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/UploadStyle.java +++ b/runelite-client/src/main/java/net/runelite/client/util/ImageUploadStyle.java @@ -23,9 +23,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.client.plugins.screenshot; +package net.runelite.client.util; -public enum UploadStyle +public enum ImageUploadStyle { NEITHER, IMGUR, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/TransferableBufferedImage.java b/runelite-client/src/main/java/net/runelite/client/util/TransferableBufferedImage.java similarity index 97% rename from runelite-client/src/main/java/net/runelite/client/plugins/screenshot/TransferableBufferedImage.java rename to runelite-client/src/main/java/net/runelite/client/util/TransferableBufferedImage.java index 27b4ddd154..f87e52564b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/TransferableBufferedImage.java +++ b/runelite-client/src/main/java/net/runelite/client/util/TransferableBufferedImage.java @@ -24,7 +24,7 @@ * 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.screenshot; +package net.runelite.client.util; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; diff --git a/runelite-client/src/main/resources/net/runelite/client/runelite.properties b/runelite-client/src/main/resources/net/runelite/client/runelite.properties index e6ad242cdf..801f0cc406 100644 --- a/runelite-client/src/main/resources/net/runelite/client/runelite.properties +++ b/runelite-client/src/main/resources/net/runelite/client/runelite.properties @@ -12,4 +12,5 @@ runelite.dnschange.link=https://1.1.1.1/dns/ runelite.jav_config=http://oldschool.runescape.com/jav_config.ws runelite.jav_config_backup=http://static.runelite.net/jav_config.ws runelite.pluginhub.url=https://repo.runelite.net/plugins -runelite.pluginhub.version=${project.version} \ No newline at end of file +runelite.pluginhub.version=${project.version} +runelite.imgur.client.id=30d71e5f6860809 \ No newline at end of file From bbdf76a0b64c4a7dbcd36747d09806bbb088600e Mon Sep 17 00:00:00 2001 From: Alexsuperfly Date: Tue, 26 Nov 2019 20:20:43 -0500 Subject: [PATCH 12/16] Raids: Add clan chat and world to scouting overlay --- .../client/plugins/raids/RaidsConfig.java | 23 ++++++++++++----- .../client/plugins/raids/RaidsOverlay.java | 25 +++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java index 9d6fd5d8c3..24e4794ffa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java @@ -88,6 +88,17 @@ public interface RaidsConfig extends Config @ConfigItem( position = 5, + keyName = "ccDisplay", + name = "CC and World in scout overlay", + description = "Display current Clan Chat and World in scouting overlay" + ) + default boolean ccDisplay() + { + return false; + } + + @ConfigItem( + position = 6, keyName = "whitelistedRooms", name = "Whitelisted rooms", description = "Display whitelisted rooms in green on the overlay. Separate with comma (full name)" @@ -98,7 +109,7 @@ public interface RaidsConfig extends Config } @ConfigItem( - position = 6, + position = 7, keyName = "blacklistedRooms", name = "Blacklisted rooms", description = "Display blacklisted rooms in red on the overlay. Separate with comma (full name)" @@ -109,7 +120,7 @@ public interface RaidsConfig extends Config } @ConfigItem( - position = 7, + position = 8, keyName = "enableRotationWhitelist", name = "Enable rotation whitelist", description = "Enable the rotation whitelist" @@ -120,7 +131,7 @@ public interface RaidsConfig extends Config } @ConfigItem( - position = 8, + position = 9, keyName = "whitelistedRotations", name = "Whitelisted rotations", description = "Warn when boss rotation doesn't match a whitelisted one. Add rotations like: tekton, muttadiles, guardians - each rotation on its own line" @@ -131,7 +142,7 @@ public interface RaidsConfig extends Config } @ConfigItem( - position = 9, + position = 10, keyName = "enableLayoutWhitelist", name = "Enable layout whitelist", description = "Enable the layout whitelist" @@ -142,7 +153,7 @@ public interface RaidsConfig extends Config } @ConfigItem( - position = 10, + position = 11, keyName = "whitelistedLayouts", name = "Whitelisted layouts", description = "Warn when layout doesn't match a whitelisted one. Add layouts like CFSCPPCSCF separated with comma" @@ -153,7 +164,7 @@ public interface RaidsConfig extends Config } @ConfigItem( - position = 11, + position = 12, keyName = "layoutMessage", name = "Send raid layout message when entering raid", description = "Sends game message with raid layout on entering new raid" diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java index d9fd379f5c..ea45cad829 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java @@ -26,9 +26,11 @@ package net.runelite.client.plugins.raids; import java.awt.Color; import java.awt.Dimension; +import java.awt.FontMetrics; import java.awt.Graphics2D; import javax.inject.Inject; import lombok.Setter; +import net.runelite.api.ClanMemberManager; import net.runelite.api.Client; import static net.runelite.api.MenuAction.RUNELITE_OVERLAY; import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; @@ -38,6 +40,7 @@ import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.ComponentConstants; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; @@ -101,6 +104,28 @@ public class RaidsOverlay extends Overlay .color(color) .build()); + if (config.ccDisplay()) + { + color = Color.RED; + ClanMemberManager clanMemberManager = client.getClanMemberManager(); + FontMetrics metrics = graphics.getFontMetrics(); + String worldString = "W" + client.getWorld(); + String clanOwner = "Join a CC"; + if (clanMemberManager != null) + { + clanOwner = clanMemberManager.getClanOwner(); + color = Color.ORANGE; + } + + panelComponent.setPreferredSize(new Dimension(Math.max(ComponentConstants.STANDARD_WIDTH, metrics.stringWidth(worldString) + metrics.stringWidth(clanOwner) + 14), 0)); + panelComponent.getChildren().add(LineComponent.builder() + .left(worldString) + .right(clanOwner) + .leftColor(Color.ORANGE) + .rightColor(color) + .build()); + } + for (Room layoutRoom : plugin.getRaid().getLayout().getRooms()) { int position = layoutRoom.getPosition(); From ecbfd9caa9759d701fd6530b629286270b08266b Mon Sep 17 00:00:00 2001 From: Alexsuperfly Date: Tue, 26 Nov 2019 20:44:36 -0500 Subject: [PATCH 13/16] Raids: Enable screenshotting of scouting overlay --- .../client/plugins/raids/RaidsConfig.java | 26 +++++++- .../client/plugins/raids/RaidsOverlay.java | 4 ++ .../client/plugins/raids/RaidsPlugin.java | 61 ++++++++++++++++++- .../client/plugins/raids/RaidsPluginTest.java | 10 +++ 4 files changed, 97 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java index 24e4794ffa..ee124e3520 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java @@ -27,6 +27,8 @@ package net.runelite.client.plugins.raids; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Keybind; +import net.runelite.client.util.ImageUploadStyle; @ConfigGroup("raids") public interface RaidsConfig extends Config @@ -175,7 +177,7 @@ public interface RaidsConfig extends Config } @ConfigItem( - position = 12, + position = 13, keyName = "showLootValue", name = "Show Loot Value", description = "Shows the value of your loot at the end of a raid" @@ -184,4 +186,26 @@ public interface RaidsConfig extends Config { return true; } + + @ConfigItem( + position = 14, + keyName = "screenshotHotkey", + name = "Scouter screenshot hotkey", + description = "Hotkey used to screenshot the scouting overlay" + ) + default Keybind screenshotHotkey() + { + return Keybind.NOT_SET; + } + + @ConfigItem( + position = 15, + keyName = "uploadScreenshot", + name = "Upload scouting screenshot", + description = "Uploads the scouting screenshot to Imgur or the clipboard" + ) + default ImageUploadStyle uploadScreenshot() + { + return ImageUploadStyle.CLIPBOARD; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java index ea45cad829..3ff46b528d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java @@ -29,6 +29,7 @@ import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics2D; import javax.inject.Inject; +import lombok.Getter; import lombok.Setter; import net.runelite.api.ClanMemberManager; import net.runelite.api.Client; @@ -49,12 +50,14 @@ public class RaidsOverlay extends Overlay { private static final int OLM_PLANE = 0; static final String BROADCAST_ACTION = "Broadcast layout"; + static final String SCREENSHOT_ACTION = "Screenshot"; private Client client; private RaidsPlugin plugin; private RaidsConfig config; private final PanelComponent panelComponent = new PanelComponent(); + @Getter @Setter private boolean scoutOverlayShown = false; @@ -69,6 +72,7 @@ public class RaidsOverlay extends Overlay this.config = config; getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Raids overlay")); getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY, BROADCAST_ACTION, "Raids overlay")); + getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY, SCREENSHOT_ACTION, "Raids overlay")); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java index 1c581a3f26..6ca27d0980 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java @@ -28,6 +28,10 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.inject.Binder; import com.google.inject.Provides; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; import java.io.IOException; import java.text.DecimalFormat; import java.time.Instant; @@ -69,12 +73,14 @@ import net.runelite.client.chat.ChatMessageBuilder; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.QueuedMessage; import net.runelite.client.config.ConfigManager; +import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ChatInput; import net.runelite.client.events.ConfigChanged; import net.runelite.client.events.OverlayMenuClicked; import net.runelite.client.game.ItemManager; import net.runelite.client.game.SpriteManager; +import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.raids.solver.Layout; @@ -82,6 +88,8 @@ import net.runelite.client.plugins.raids.solver.LayoutSolver; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.util.QuantityFormatter; +import net.runelite.client.util.HotkeyListener; +import net.runelite.client.util.ImageCapture; import net.runelite.client.util.Text; import static net.runelite.client.util.Text.sanitize; import net.runelite.client.ws.PartyMember; @@ -108,6 +116,9 @@ public class RaidsPlugin extends Plugin private static final String LAYOUT_COMMAND = "!layout"; private static final int MAX_LAYOUT_LEN = 300; + @Inject + private RuneLiteConfig runeLiteConfig; + @Inject private ChatMessageManager chatMessageManager; @@ -153,6 +164,12 @@ public class RaidsPlugin extends Plugin @Inject private ItemManager itemManager; + @Inject + private KeyManager keyManager; + + @Inject + private ImageCapture imageCapture; + @Getter private final Set roomWhitelist = new HashSet(); @@ -195,6 +212,7 @@ public class RaidsPlugin extends Plugin updateLists(); clientThread.invokeLater(() -> checkRaidPresence(true)); chatCommandManager.registerCommandAsync(LAYOUT_COMMAND, this::lookupRaid, this::submitRaid); + keyManager.registerKeyListener(screenshotHotkeyListener); } @Override @@ -207,6 +225,7 @@ public class RaidsPlugin extends Plugin raid = null; timer = null; chestOpened = false; + keyManager.unregisterKeyListener(screenshotHotkeyListener); } @Subscribe @@ -334,12 +353,20 @@ public class RaidsPlugin extends Plugin @Subscribe public void onOverlayMenuClicked(final OverlayMenuClicked event) { - if (event.getEntry().getMenuAction() == MenuAction.RUNELITE_OVERLAY && - event.getEntry().getOption().equals(RaidsOverlay.BROADCAST_ACTION) && - event.getOverlay() == overlay) + if (!(event.getEntry().getMenuAction() == MenuAction.RUNELITE_OVERLAY + && event.getOverlay() == overlay)) + { + return; + } + + if (event.getEntry().getOption().equals(RaidsOverlay.BROADCAST_ACTION)) { sendRaidLayoutMessage(); } + else if (event.getEntry().getOption().equals(RaidsOverlay.SCREENSHOT_ACTION)) + { + screenshotScoutOverlay(); + } } private void checkRaidPresence(boolean force) @@ -752,4 +779,32 @@ public class RaidsPlugin extends Plugin return true; } + + private final HotkeyListener screenshotHotkeyListener = new HotkeyListener(() -> config.screenshotHotkey()) + { + @Override + public void hotkeyPressed() + { + screenshotScoutOverlay(); + } + }; + + private void screenshotScoutOverlay() + { + if (!overlay.isScoutOverlayShown()) + { + return; + } + + Rectangle overlayDimensions = overlay.getBounds(); + BufferedImage overlayImage = new BufferedImage(overlayDimensions.width, overlayDimensions.height, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphic = overlayImage.createGraphics(); + graphic.setFont(runeLiteConfig.interfaceFontType().getFont()); + graphic.setColor(Color.BLACK); + graphic.fillRect(0, 0, overlayDimensions.width, overlayDimensions.height); + overlay.render(graphic); + + imageCapture.takeScreenshot(overlayImage, "CoX_scout-", false, config.uploadScreenshot()); + graphic.dispose(); + } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java index 23c71795c0..01af2080f5 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java @@ -44,6 +44,8 @@ import net.runelite.client.game.ItemManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import net.runelite.client.Notifier; +import net.runelite.client.util.ImageCapture; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -81,6 +83,14 @@ public class RaidsPluginTest @Bind ChatMessageManager chatMessageManager; + @Mock + @Bind + ImageCapture imageCapture; + + @Mock + @Bind + Notifier notifier; + @Mock @Bind RaidsConfig raidsConfig; From 8c5197c6feca4ff7f2da287a991cdc504d70838c Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 1 Feb 2020 14:54:51 -0500 Subject: [PATCH 14/16] cache: update sequence definition --- .../cache/definitions/SequenceDefinition.java | 14 +++++++------- .../cache/definitions/loaders/SequenceLoader.java | 14 +++++--------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/cache/src/main/java/net/runelite/cache/definitions/SequenceDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/SequenceDefinition.java index 3f280f31c2..d596b66a90 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/SequenceDefinition.java +++ b/cache/src/main/java/net/runelite/cache/definitions/SequenceDefinition.java @@ -31,17 +31,17 @@ public class SequenceDefinition { private final int id; public int[] frameIDs; // top 16 bits are FrameDefinition ids - public int[] field3048; + public int[] chatFrameIds; public int[] frameLenghts; - public int rightHandItem = -1; + public int[] frameSounds; + public int frameStep = -1; public int[] interleaveLeave; public boolean stretches = false; public int forcedPriority = 5; - public int maxLoops = 99; - public int[] field3056; - public int precedenceAnimating = -1; public int leftHandItem = -1; - public int replyMode = 2; - public int frameStep = -1; + public int rightHandItem = -1; + public int maxLoops = 99; + public int precedenceAnimating = -1; public int priority = -1; + public int replyMode = 2; } diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/SequenceLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/SequenceLoader.java index 987cbd4204..a5676270c6 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/loaders/SequenceLoader.java +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/SequenceLoader.java @@ -26,13 +26,9 @@ package net.runelite.cache.definitions.loaders; import net.runelite.cache.definitions.SequenceDefinition; import net.runelite.cache.io.InputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class SequenceLoader { - private static final Logger logger = LoggerFactory.getLogger(SequenceLoader.class); - public SequenceDefinition load(int id, byte[] b) { SequenceDefinition def = new SequenceDefinition(id); @@ -129,26 +125,26 @@ public class SequenceLoader else if (opcode == 12) { var3 = stream.readUnsignedByte(); - def.field3048 = new int[var3]; + def.chatFrameIds = new int[var3]; for (var4 = 0; var4 < var3; ++var4) { - def.field3048[var4] = stream.readUnsignedShort(); + def.chatFrameIds[var4] = stream.readUnsignedShort(); } for (var4 = 0; var4 < var3; ++var4) { - def.field3048[var4] += stream.readUnsignedShort() << 16; + def.chatFrameIds[var4] += stream.readUnsignedShort() << 16; } } else if (opcode == 13) { var3 = stream.readUnsignedByte(); - def.field3056 = new int[var3]; + def.frameSounds = new int[var3]; for (var4 = 0; var4 < var3; ++var4) { - def.field3056[var4] = stream.read24BitInt(); + def.frameSounds[var4] = stream.read24BitInt(); } } From 9a103f8ccd4928c6da8679ace7e02f1f9f874a63 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 2 Feb 2020 18:49:16 -0500 Subject: [PATCH 15/16] widget item: clip overlay to parent bounds --- .../client/ui/overlay/WidgetItemOverlay.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java index 5e707064b4..c234a0d4dd 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java @@ -26,6 +26,7 @@ package net.runelite.client.ui.overlay; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.Rectangle; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -70,6 +71,8 @@ public abstract class WidgetItemOverlay extends Overlay public Dimension render(Graphics2D graphics) { final List itemWidgets = overlayManager.getItemWidgets(); + final Rectangle originalClipBounds = graphics.getClipBounds(); + Widget curClipParent = null; for (WidgetItem widgetItem : itemWidgets) { Widget widget = widgetItem.getWidget(); @@ -83,6 +86,29 @@ public abstract class WidgetItemOverlay extends Overlay continue; } + Widget parent = widget.getParent(); + Rectangle parentBounds = parent.getBounds(); + Rectangle itemCanvasBounds = widgetItem.getCanvasBounds(); + + boolean shouldClip; + shouldClip = itemCanvasBounds.y < parentBounds.y && itemCanvasBounds.y + itemCanvasBounds.height >= parentBounds.y; + shouldClip |= itemCanvasBounds.y < parentBounds.y + parentBounds.height && itemCanvasBounds.y + itemCanvasBounds.height >= parentBounds.y + parentBounds.height; + shouldClip |= itemCanvasBounds.x < parentBounds.x && (itemCanvasBounds.x + itemCanvasBounds.width) >= parentBounds.x; + shouldClip |= itemCanvasBounds.x < parentBounds.x + parentBounds.width && itemCanvasBounds.x + itemCanvasBounds.width >= parentBounds.x + parentBounds.width; + if (shouldClip) + { + if (curClipParent != parent) + { + graphics.setClip(parentBounds); + curClipParent = parent; + } + } + else if (curClipParent != null && curClipParent != parent) + { + graphics.setClip(originalClipBounds); + curClipParent = null; + } + renderItemOverlay(graphics, widgetItem.getId(), widgetItem); } return null; From 5216b03090595a568debc735ae1f58ecc1491541 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 3 Feb 2020 21:26:50 -0500 Subject: [PATCH 16/16] screenmarkers: prevent null marker creation This is happening and I can't see why. Avoid creating and loading null markers. --- .../plugins/screenmarkers/ScreenMarkerOverlay.java | 3 ++- .../plugins/screenmarkers/ScreenMarkerPlugin.java | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerOverlay.java index 08857c532e..8635378738 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerOverlay.java @@ -29,6 +29,7 @@ import java.awt.BasicStroke; import java.awt.Dimension; import java.awt.Graphics2D; import lombok.Getter; +import lombok.NonNull; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; @@ -40,7 +41,7 @@ public class ScreenMarkerOverlay extends Overlay private final ScreenMarker marker; private final ScreenMarkerRenderable screenMarkerRenderable; - ScreenMarkerOverlay(ScreenMarker marker) + ScreenMarkerOverlay(@NonNull ScreenMarker marker) { this.marker = marker; this.screenMarkerRenderable = new ScreenMarkerRenderable(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java index 798bd61aae..9ca3c9c46d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java @@ -36,14 +36,15 @@ import java.awt.image.BufferedImage; import java.time.Instant; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; import lombok.AccessLevel; import lombok.Getter; -import net.runelite.client.events.ConfigChanged; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.input.MouseManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -184,9 +185,10 @@ public class ScreenMarkerPlugin extends Plugin public void finishCreation(boolean aborted) { - if (!aborted) + ScreenMarker marker = currentMarker; + if (!aborted && marker != null) { - final ScreenMarkerOverlay screenMarkerOverlay = new ScreenMarkerOverlay(currentMarker); + final ScreenMarkerOverlay screenMarkerOverlay = new ScreenMarkerOverlay(marker); screenMarkerOverlay.setPreferredLocation(overlay.getBounds().getLocation()); screenMarkerOverlay.setPreferredSize(overlay.getBounds().getSize()); @@ -254,6 +256,6 @@ public class ScreenMarkerPlugin extends Plugin { }.getType()); - return screenMarkerData.stream().map(ScreenMarkerOverlay::new); + return screenMarkerData.stream().filter(Objects::nonNull).map(ScreenMarkerOverlay::new); } }