From 70a097b1ad4da1c44c085f9f0006b818add0f90a Mon Sep 17 00:00:00 2001 From: Kyleeld <48519776+Kyleeld@users.noreply.github.com> Date: Sat, 18 May 2019 22:09:32 +0100 Subject: [PATCH 1/4] press enter to chat - no wasd shit press enter to chat - no wasd shit --- .../entertochat/EnterToChatListener.java | 135 ++++++++++++ .../entertochat/EnterToChatPlugin.java | 206 ++++++++++++++++++ .../plugins/wasdcamera/WASDCameraPlugin.java | 4 + 3 files changed, 345 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/entertochat/EnterToChatListener.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/entertochat/EnterToChatPlugin.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/entertochat/EnterToChatListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/entertochat/EnterToChatListener.java new file mode 100644 index 0000000000..3dabc56600 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/entertochat/EnterToChatListener.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018, Adam + * Copyright (c) 2018, Abexlry + * 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.entertochat; + +import com.google.common.base.Strings; +import java.awt.event.KeyEvent; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.VarClientStr; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.input.KeyListener; +import net.runelite.client.input.MouseAdapter; + +class EnterToChatListener extends MouseAdapter implements KeyListener +{ + @Inject + private EnterToChatPlugin plugin; + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + private final Map modified = new HashMap<>(); + + @Override + public void keyTyped(KeyEvent e) + { + } + + @Override + public void keyPressed(KeyEvent e) + { + if (client.getGameState() != GameState.LOGGED_IN || !plugin.chatboxFocused()) + { + return; + } + + if (!plugin.isTyping()) + { + switch (e.getKeyCode()) + { + case KeyEvent.VK_ENTER: + case KeyEvent.VK_SLASH: + case KeyEvent.VK_COLON: + // refocus chatbox + plugin.setTyping(true); + clientThread.invoke(() -> + { + plugin.unlockChat(); + }); + break; + } + } + else + { + switch (e.getKeyCode()) + { + case KeyEvent.VK_ENTER: + plugin.setTyping(false); + clientThread.invoke(() -> + { + plugin.lockChat(); + }); + break; + case KeyEvent.VK_ESCAPE: + plugin.setTyping(false); + clientThread.invoke(() -> + { + client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, ""); + plugin.lockChat(); + }); + break; + case KeyEvent.VK_BACK_SPACE: + if (Strings.isNullOrEmpty(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT))) + { + plugin.setTyping(false); + clientThread.invoke(() -> plugin.lockChat()); + } + } + } + } + + @Override + public void keyReleased(KeyEvent e) + { + if (client.getGameState() != GameState.LOGGED_IN) + { + return; + } + + if (plugin.chatboxFocused() && !plugin.isTyping()) + { + modified.remove(e.getKeyCode()); + + } + else + { + // press d + enter + release d - causes the right arrow to never be released + Integer m = modified.get(e.getKeyCode()); + if (m != null) + { + modified.remove(e.getKeyCode()); + e.setKeyCode(m); + } + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/entertochat/EnterToChatPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/entertochat/EnterToChatPlugin.java new file mode 100644 index 0000000000..6436b6802a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/entertochat/EnterToChatPlugin.java @@ -0,0 +1,206 @@ +/*' + * Copyright (c) 2018, Adam + * Copyright (c) 2018, Abexlry + * 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.entertochat; + +import java.awt.Color; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.IconID; +import net.runelite.api.VarClientInt; +import net.runelite.api.VarClientStr; +import net.runelite.api.Varbits; +import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.input.KeyManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.ui.JagexColors; +import net.runelite.client.util.ColorUtil; + +@PluginDescriptor( + name = "Press Enter to Chat", + description = "'Press Enter to Chat'", + tags = {"enter", "chat"}, + enabledByDefault = false, + type = PluginType.UTILITY +) +public class EnterToChatPlugin extends Plugin +{ + private static final String PRESS_ENTER_TO_CHAT = "Press Enter to Chat..."; + private static final String SCRIPT_EVENT_SET_CHATBOX_INPUT = "setChatboxInput"; + private static final String SCRIPT_EVENT_BLOCK_CHAT_INPUT = "blockChatInput"; + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private ConfigManager configManager; + + @Inject + private KeyManager keyManager; + + @Inject + private EnterToChatListener inputListener; + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private boolean typing; + + @Override + protected void startUp() throws Exception + { + configManager.setConfiguration("runelite", "wasdcameraplugin", false); + typing = false; + keyManager.registerKeyListener(inputListener); + + clientThread.invoke(() -> + { + if (client.getGameState() == GameState.LOGGED_IN) + { + lockChat(); + } + }); + } + + @Override + protected void shutDown() throws Exception + { + clientThread.invoke(() -> + { + if (client.getGameState() == GameState.LOGGED_IN) + { + unlockChat(); + } + }); + + keyManager.unregisterKeyListener(inputListener); + } + + + boolean chatboxFocused() + { + Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); + if (chatboxParent == null || chatboxParent.getOnKeyListener() == null) + { + return false; + } + + // the search box on the world map can be focused, and chat input goes there, even + // though the chatbox still has its key listener. + Widget worldMapSearch = client.getWidget(WidgetInfo.WORLD_MAP_SEARCH); + return worldMapSearch == null || client.getVar(VarClientInt.WORLD_MAP_SEARCH_FOCUSED) != 1; + + } + + @Subscribe + public void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent) + { + switch (scriptCallbackEvent.getEventName()) + { + case SCRIPT_EVENT_SET_CHATBOX_INPUT: + Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); + if (chatboxInput != null) + { + if (chatboxFocused() && !typing) + { + chatboxInput.setText(PRESS_ENTER_TO_CHAT); + } + } + break; + case SCRIPT_EVENT_BLOCK_CHAT_INPUT: + if (!typing) + { + int[] intStack = client.getIntStack(); + int intStackSize = client.getIntStackSize(); + intStack[intStackSize - 1] = 1; + } + break; + } + } + + void lockChat() + { + Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); + if (chatboxParent != null && chatboxParent.getOnKeyListener() != null) + { + Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); + if (chatboxInput != null) + { + chatboxInput.setText(PRESS_ENTER_TO_CHAT); + } + } + } + + void unlockChat() + { + Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); + if (chatboxParent != null) + { + Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); + if (chatboxInput != null) + { + if (client.getGameState() == GameState.LOGGED_IN) + { + final boolean isChatboxTransparent = client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1; + final Color textColor = isChatboxTransparent ? JagexColors.CHAT_TYPED_TEXT_TRANSPARENT_BACKGROUND : JagexColors.CHAT_TYPED_TEXT_OPAQUE_BACKGROUND; + chatboxInput.setText(getPlayerNameWithIcon() + ": " + ColorUtil.wrapWithColorTag(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT) + "*", textColor)); + } + } + } + } + + private String getPlayerNameWithIcon() + { + IconID icon; + switch (client.getAccountType()) + { + case IRONMAN: + icon = IconID.IRONMAN; + break; + case ULTIMATE_IRONMAN: + icon = IconID.ULTIMATE_IRONMAN; + break; + case HARDCORE_IRONMAN: + icon = IconID.HARDCORE_IRONMAN; + break; + default: + return client.getLocalPlayer().getName(); + } + return icon + client.getLocalPlayer().getName(); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wasdcamera/WASDCameraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wasdcamera/WASDCameraPlugin.java index a60a389674..ac59c414d6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wasdcamera/WASDCameraPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wasdcamera/WASDCameraPlugin.java @@ -67,6 +67,9 @@ public class WASDCameraPlugin extends Plugin @Inject private ClientThread clientThread; + @Inject + private ConfigManager configManager; + @Inject private KeyManager keyManager; @@ -80,6 +83,7 @@ public class WASDCameraPlugin extends Plugin @Override protected void startUp() throws Exception { + configManager.setConfiguration("runelite", "entertochatplugin", false); typing = false; keyManager.registerKeyListener(inputListener); From 1a7cc1eeaa71a113bf97d452a7b43a44c64c3d1b Mon Sep 17 00:00:00 2001 From: sdburns1998 <49877861+sdburns1998@users.noreply.github.com> Date: Mon, 20 May 2019 18:29:05 +0200 Subject: [PATCH 2/4] Jslider (#325) * JSlider changes * Check style ConfigPanel --- .../client/plugins/cannon/CannonConfig.java | 4 ++++ .../client/plugins/config/ConfigPanel.java | 16 ++++++++++++---- .../EquipmentInspectorConfig.java | 7 ++++++- .../runelite/client/plugins/fps/FpsConfig.java | 5 +++++ .../runelite/client/plugins/zoom/ZoomConfig.java | 4 ++-- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java index 15f50725e6..c832ded86b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.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.Range; @ConfigGroup("cannon") public interface CannonConfig extends Config @@ -84,6 +85,9 @@ public interface CannonConfig extends Config return true; } + @Range( + max = 29 + ) @ConfigItem( keyName = "ammoAmount", name = "Ammo left", 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 276be04829..7874ad29b9 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 @@ -75,8 +75,8 @@ import net.runelite.client.config.Config; import net.runelite.client.config.ConfigDescriptor; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; -import net.runelite.client.config.ConfigItemsGroup; import net.runelite.client.config.ConfigItemDescriptor; +import net.runelite.client.config.ConfigItemsGroup; import net.runelite.client.config.ConfigManager; import net.runelite.client.config.Keybind; import net.runelite.client.config.ModifierlessKeybind; @@ -430,11 +430,13 @@ public class ConfigPanel extends PluginPanel JLabel headerLabel = new JLabel(header); headerLabel.setForeground(Color.ORANGE); - headerLabel.setPreferredSize(new Dimension(PANEL_WIDTH, (int)headerLabel.getPreferredSize().getHeight())); + headerLabel.setPreferredSize(new Dimension(PANEL_WIDTH, (int) headerLabel.getPreferredSize().getHeight())); String sCollapsed = configManager.getConfiguration(cd.getGroup().value(), cig.getGroup() + "_collapse"); if (sCollapsed != null) + { collapsed = Boolean.parseBoolean(sCollapsed); + } JButton collapse = new JButton(collapsed ? "+" : "-"); collapse.setPreferredSize(new Dimension(20, 20)); @@ -451,7 +453,9 @@ public class ConfigPanel extends PluginPanel } if (collapsed) + { continue; + } for (ConfigItemDescriptor cid : cig.getItems()) { @@ -465,7 +469,7 @@ public class ConfigPanel extends PluginPanel item.setMinimumSize(new Dimension(PANEL_WIDTH, 0)); name = cid.getItem().name(); JLabel configEntryName = new JLabel(name); - configEntryName.setPreferredSize(new Dimension(PANEL_WIDTH, (int)configEntryName.getPreferredSize().getHeight())); + configEntryName.setPreferredSize(new Dimension(PANEL_WIDTH, (int) configEntryName.getPreferredSize().getHeight())); configEntryName.setForeground(Color.WHITE); configEntryName.setToolTipText("" + name + ":
" + cid.getItem().description() + ""); item.add(configEntryName, BorderLayout.CENTER); @@ -499,13 +503,15 @@ public class ConfigPanel extends PluginPanel { JSlider slider = new JSlider(min, max, value); configEntryName.setText(name.concat(": ").concat(String.valueOf(slider.getValue()))); - slider.setPreferredSize(new Dimension(topPanel.getPreferredSize().width, slider.getHeight())); + slider.setPreferredSize(new Dimension(100, 25)); String finalName = name; slider.addChangeListener((l) -> { configEntryName.setText(finalName.concat(": ").concat(String.valueOf(slider.getValue()))); if (!slider.getValueIsAdjusting()) + { changeConfiguration(listItem, config, slider, cd, cid); + } } ); item.add(slider, BorderLayout.EAST); @@ -726,7 +732,9 @@ public class ConfigPanel extends PluginPanel boolean collapse = true; if (sCollapsed != null) + { collapse = !Boolean.parseBoolean(sCollapsed); + } configManager.setConfiguration(cd.getGroup().value(), cig.getGroup() + "_collapse", collapse); openGroupConfigPanel(listItem, config, cd); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/equipmentinspector/EquipmentInspectorConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/equipmentinspector/EquipmentInspectorConfig.java index c88eec0f71..a43592e5d7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/equipmentinspector/EquipmentInspectorConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/equipmentinspector/EquipmentInspectorConfig.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.equipmentinspector; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Range; @ConfigGroup("grounditems") public interface EquipmentInspectorConfig extends Config @@ -42,9 +43,13 @@ public interface EquipmentInspectorConfig extends Config return true; } + @Range( + min = 1, + max = 4 + ) @ConfigItem( keyName = "protecteditems", - name = "# of protected items", + name = "protected items", description = "Limit 4", position = 2 ) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsConfig.java index 0627f90354..5f737124ed 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsConfig.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.fps; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Range; @ConfigGroup(FpsPlugin.CONFIG_GROUP_KEY) public interface FpsConfig extends Config @@ -42,6 +43,10 @@ public interface FpsConfig extends Config return FpsLimitMode.NEVER; } + @Range( + min = 10, + max = 50 + ) @ConfigItem( keyName = "maxFps", name = "FPS target", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomConfig.java index 825378cd57..d3fb50007b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomConfig.java @@ -13,7 +13,7 @@ public interface ZoomConfig extends Config @ConfigItem( keyName = "inner", - name = "Expand inner zoom limit", + name = "Inner limit", description = "Configures whether or not the inner zoom limit is reduced", position = 1 ) @@ -28,7 +28,7 @@ public interface ZoomConfig extends Config ) @ConfigItem( keyName = "outerLimit", - name = "Expand outer zoom limit", + name = "Outer limit", description = "Configures how much the outer zoom limit is adjusted", position = 2 ) From bb55defb5055f709f059e318b11bbfa3b438472c Mon Sep 17 00:00:00 2001 From: sdburns1998 <49877861+sdburns1998@users.noreply.github.com> Date: Mon, 20 May 2019 18:29:46 +0200 Subject: [PATCH 3/4] Ground items (#323) * retrieve ItemLayer height in render rather than on spawn * Ground item timers * Loot notifications --- .../plugins/grounditems/GroundItem.java | 5 ++ .../grounditems/GroundItemsConfig.java | 80 ++++++++++++++--- .../grounditems/GroundItemsOverlay.java | 84 ++++++++++++++++++ .../grounditems/GroundItemsPlugin.java | 85 ++++++++++++++++++- .../grounditems/config/TimerDisplayMode.java | 45 ++++++++++ 5 files changed, 284 insertions(+), 15 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/TimerDisplayMode.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java index 883d3e9df2..ce66dd8a8f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.grounditems; +import java.time.Instant; import lombok.Builder; import lombok.Data; import lombok.Value; @@ -45,6 +46,10 @@ class GroundItem private int offset; private boolean tradeable; private boolean isMine; + private int durationMillis; + private boolean isAlwaysPrivate; + private boolean isOwnedByPlayer; + private Instant droppedInstant; int getHaPrice() { 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 c722b202f0..ffacca5af2 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 @@ -32,6 +32,7 @@ import net.runelite.client.config.ConfigItem; import net.runelite.client.plugins.grounditems.config.ItemHighlightMode; import net.runelite.client.plugins.grounditems.config.MenuHighlightMode; import net.runelite.client.plugins.grounditems.config.PriceDisplayMode; +import net.runelite.client.plugins.grounditems.config.TimerDisplayMode; import net.runelite.client.plugins.grounditems.config.ValueCalculationMode; @ConfigGroup("grounditems") @@ -260,11 +261,22 @@ public interface GroundItemsConfig extends Config return 20000; } + @ConfigItem( + keyName = "notifyLowValueDrops", + name = "Notify for low value drops", + description = "Configures whether or not to notify for drops of low value", + position = 19 + ) + default boolean notifyLowValueDrops() + { + return false; + } + @ConfigItem( keyName = "mediumValueColor", name = "Medium value items color", description = "Configures the color for medium value items", - position = 19 + position = 20 ) default Color mediumValueColor() { @@ -275,18 +287,29 @@ public interface GroundItemsConfig extends Config keyName = "mediumValuePrice", name = "Medium value price", description = "Configures the start price for medium value items", - position = 20 + position = 21 ) default int mediumValuePrice() { return 100000; } + @ConfigItem( + keyName = "notifyMediumValueDrops", + name = "Notify for medium value drops", + description = "Configures whether or not to notify for drops of medium value", + position = 22 + ) + default boolean notifyMediumValueDrops() + { + return false; + } + @ConfigItem( keyName = "highValueColor", name = "High value items color", description = "Configures the color for high value items", - position = 21 + position = 23 ) default Color highValueColor() { @@ -297,18 +320,29 @@ public interface GroundItemsConfig extends Config keyName = "highValuePrice", name = "High value price", description = "Configures the start price for high value items", - position = 22 + position = 24 ) default int highValuePrice() { return 1000000; } + @ConfigItem( + keyName = "notifyHighValueDrops", + name = "Notify for high value drops", + description = "Configures whether or not to notify for drops of high value", + position = 25 + ) + default boolean notifyHighValueDrops() + { + return false; + } + @ConfigItem( keyName = "insaneValueColor", name = "Insane value items color", description = "Configures the color for insane value items", - position = 23 + position = 26 ) default Color insaneValueColor() { @@ -319,18 +353,29 @@ public interface GroundItemsConfig extends Config keyName = "insaneValuePrice", name = "Insane value price", description = "Configures the start price for insane value items", - position = 24 + position = 27 ) default int insaneValuePrice() { return 10000000; } + @ConfigItem( + keyName = "notifyInsaneValueDrops", + name = "Notify for insane value drops", + description = "Configures whether or not to notify for drops of insane value", + position = 28 + ) + default boolean notifyInsaneValueDrops() + { + return false; + } + @ConfigItem( keyName = "onlyShowLoot", name = "Only show loot", description = "Only shows drops from NPCs and players", - position = 25 + position = 29 ) default boolean onlyShowLoot() { @@ -341,7 +386,7 @@ public interface GroundItemsConfig extends Config keyName = "doubleTapDelay", name = "Delay for double-tap ALT to hide", description = "Decrease this number if you accidentally hide ground items often. (0 = Disabled)", - position = 26 + position = 30 ) default int doubleTapDelay() { @@ -352,7 +397,7 @@ public interface GroundItemsConfig extends Config keyName = "collapseEntries", name = "Collapse ground item menu entries", description = "Collapses ground item menu entries together and appends count", - position = 27 + position = 31 ) default boolean collapseEntries() { @@ -360,10 +405,10 @@ public interface GroundItemsConfig extends Config } @ConfigItem( - position = 27, keyName = "removeIgnored", name = "Hide Ignored", - description = "Remove take option for items that are on the hidden items list." + description = "Remove take option for items that are on the hidden items list.", + position = 32 ) default boolean removeIgnored() { @@ -374,10 +419,21 @@ public interface GroundItemsConfig extends Config keyName = "toggleOutline", name = "Text Outline", description = "Use an outline around text instead of a text shadow", - position = 29 + position = 33 ) default boolean toggleOutline() { return false; } + + @ConfigItem( + keyName = "showGroundItemDuration", + name = "Show time remaining", + description = "Turn on a countdown timer to show how long an item will remain on the ground", + position = 34 + ) + default TimerDisplayMode showGroundItemDuration() + { + return TimerDisplayMode.HOTKEY_PRESSED; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java index 4d7e2601cd..024d9455b1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -31,6 +31,8 @@ import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.Rectangle; +import java.time.Duration; +import java.time.Instant; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collection; @@ -41,15 +43,18 @@ import net.runelite.api.Client; import net.runelite.api.Perspective; import net.runelite.api.Player; import net.runelite.api.Point; +import net.runelite.api.Tile; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.MENU; import net.runelite.client.plugins.grounditems.config.PriceDisplayMode; +import net.runelite.client.plugins.grounditems.config.TimerDisplayMode; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.BackgroundComponent; +import net.runelite.client.ui.overlay.components.ProgressPieComponent; import net.runelite.client.ui.overlay.components.TextComponent; import net.runelite.client.util.StackFormatter; @@ -67,12 +72,20 @@ public class GroundItemsOverlay extends Overlay // Size of the hidden/highlight boxes private static final int RECTANGLE_SIZE = 8; + private static final int TIMER_OVERLAY_DIAMETER = 10; + private static final int PUBLIC_ITEM_DURATION_MILLIS = 60000; + private static final float WARNING_THRESHOLD = 0.25f; + private static final Color PUBLIC_TIMER_COLOR = Color.YELLOW; + private static final Color PRIVATE_TIMER_COLOR = Color.GREEN; + private static final Color PUBLIC_WARNING_TIMER_COLOR = Color.RED; + private final Client client; private final GroundItemsPlugin plugin; private final GroundItemsConfig config; private final StringBuilder itemStringBuilder = new StringBuilder(); private final BackgroundComponent backgroundComponent = new BackgroundComponent(); private final TextComponent textComponent = new TextComponent(); + private final ProgressPieComponent progressPieComponent = new ProgressPieComponent(); private final Map offsetMap = new HashMap<>(); @Inject @@ -259,6 +272,13 @@ public class GroundItemsOverlay extends Overlay final String itemString = itemStringBuilder.toString(); itemStringBuilder.setLength(0); + if (item.getHeight() == -1) + { + final Tile[][][] sceneTiles = client.getScene().getTiles(); + final Tile itemTile = sceneTiles[client.getPlane()][groundPoint.getSceneX()][groundPoint.getSceneY()]; + item.setHeight(itemTile.getItemLayer().getHeight()); + } + final Point textPoint = Perspective.getCanvasTextLocation(client, graphics, groundPoint, @@ -333,6 +353,12 @@ public class GroundItemsOverlay extends Overlay drawRectangle(graphics, itemHighlightBox, topItem && mouseInHighlightBox ? Color.GREEN : color, highlighted != null, false); } + if (config.showGroundItemDuration() == TimerDisplayMode.ALWAYS + || (config.showGroundItemDuration() == TimerDisplayMode.HOTKEY_PRESSED && plugin.isHotKeyPressed())) + { + drawTimerOverlay(graphics, new java.awt.Point(textX, textY), item); + } + if (config.toggleOutline()) { graphics.setColor(Color.BLACK); @@ -388,4 +414,62 @@ public class GroundItemsOverlay extends Overlay } + private void drawTimerOverlay(Graphics2D graphics, java.awt.Point location, GroundItem item) + { + progressPieComponent.setDiameter(TIMER_OVERLAY_DIAMETER); + + int x = (int) location.getX() - TIMER_OVERLAY_DIAMETER; + int y = (int) location.getY() - TIMER_OVERLAY_DIAMETER / 2; + + progressPieComponent.setPosition(new Point(x, y)); + + double millisOnGround = Duration.between(item.getDroppedInstant(), Instant.now()).toMillis(); + boolean isPubliclyVisible = !item.isAlwaysPrivate() && millisOnGround > item.getDurationMillis(); + double timeLeftRelative; + Color fillColor; + + if (isPubliclyVisible || !item.isOwnedByPlayer()) + { + if (item.isOwnedByPlayer()) + { + timeLeftRelative = getTimeLeftRelative(millisOnGround - PUBLIC_ITEM_DURATION_MILLIS, PUBLIC_ITEM_DURATION_MILLIS); + + } + else + { + timeLeftRelative = getTimeLeftRelative(millisOnGround, PUBLIC_ITEM_DURATION_MILLIS); + } + + if (timeLeftRelative < WARNING_THRESHOLD) + { + fillColor = PUBLIC_WARNING_TIMER_COLOR; + } + else + { + fillColor = PUBLIC_TIMER_COLOR; + } + } + else + { + timeLeftRelative = getTimeLeftRelative(millisOnGround, item.getDurationMillis()); + fillColor = PRIVATE_TIMER_COLOR; + + } + + // don't draw timer for any permanently spawned items or broken edge cases + if (timeLeftRelative > 1 || timeLeftRelative < 0) + { + return; + } + + progressPieComponent.setFill(fillColor); + progressPieComponent.setBorderColor(fillColor); + progressPieComponent.setProgress(timeLeftRelative); + progressPieComponent.render(graphics); + } + + private double getTimeLeftRelative(double millisOnGround, int duration) + { + return (duration - millisOnGround) / duration; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java index 35ee979085..3b8a06ec13 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java @@ -31,6 +31,7 @@ import com.google.inject.Provides; import java.awt.Color; import java.awt.Rectangle; import static java.lang.Boolean.TRUE; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -99,6 +100,15 @@ public class GroundItemsPlugin extends Plugin private static final float HIGH_ALCHEMY_CONSTANT = 0.6f; // ItemID for coins private static final int COINS = ItemID.COINS_995; + + // items stay on the ground for 30 mins in an instance + private static final int INSTANCE_DURATION_MILLIS = 45 * 60 * 1000; + //untradeables stay on the ground for 150 seconds (http://oldschoolrunescape.wikia.com/wiki/Item#Dropping_and_Destroying) + private static final int UNTRADEABLE_DURATION_MILLIS = 150 * 1000; + //items stay on the ground for 1 hour after death + private static final int DEATH_DURATION_MILLIS = 60 * 60 * 1000; + private static final int NORMAL_DURATION_MILLIS = 60 * 1000; + // Ground item menu options private static final int FIRST_OPTION = MenuAction.GROUND_ITEM_FIRST_OPTION.getId(); private static final int SECOND_OPTION = MenuAction.GROUND_ITEM_SECOND_OPTION.getId(); @@ -280,8 +290,19 @@ public class GroundItemsPlugin extends Plugin @Subscribe public void onNpcLootReceived(NpcLootReceived npcLootReceived) { + npcLootReceived.getItems().forEach(item -> + { + GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), npcLootReceived.getNpc().getWorldLocation()); + if (collectedGroundItems.containsKey(groundItemKey)) + { + collectedGroundItems.get(groundItemKey).setOwnedByPlayer(true); + } + } + ); + Collection items = npcLootReceived.getItems(); lootReceived(items); + lootNotifier(items); } @Subscribe @@ -289,6 +310,47 @@ public class GroundItemsPlugin extends Plugin { Collection items = playerLootReceived.getItems(); lootReceived(items); + lootNotifier(items); + } + + private void lootNotifier(Collection items) + { + ItemComposition composition; + for (ItemStack is : items) + { + composition = itemManager.getItemComposition(is.getId()); + Color itemColor = getHighlighted(composition.getName(), itemManager.getItemPrice(is.getId()) * is.getQuantity(), Math.round(composition.getPrice() * HIGH_ALCHEMY_CONSTANT) * is.getQuantity()); + if (itemColor != null) + { + if (config.notifyHighlightedDrops() && itemColor.equals(config.highlightedColor())) + { + sendLootNotification(composition.getName(), "highlighted"); + } + else if (config.notifyLowValueDrops() && itemColor.equals(config.lowValueColor())) + { + sendLootNotification(composition.getName(), "low value"); + } + else if (config.notifyMediumValueDrops() && itemColor.equals(config.mediumValueColor())) + { + sendLootNotification(composition.getName(), "medium value"); + } + else if (config.notifyHighValueDrops() && itemColor.equals(config.highValueColor())) + { + sendLootNotification(composition.getName(), "high value"); + } + else if (config.notifyInsaneValueDrops() && itemColor.equals(config.insaneValueColor())) + { + sendLootNotification(composition.getName(), "insane value"); + } + } + } + } + + private void sendLootNotification(String itemName, String message) + { + String notification = "[" + client.getLocalPlayer().getName() + "] " + + "Received a " + message + " item: " + itemName; + notifier.notify(notification); } @Subscribe @@ -370,6 +432,21 @@ public class GroundItemsPlugin extends Plugin final ItemComposition itemComposition = itemManager.getItemComposition(itemId); final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemId; final int alchPrice = Math.round(itemComposition.getPrice() * HIGH_ALCHEMY_CONSTANT); + int durationMillis; + if (client.isInInstancedRegion()) + { + durationMillis = INSTANCE_DURATION_MILLIS; + } + else if (!itemComposition.isTradeable() && realItemId != COINS) + { + durationMillis = UNTRADEABLE_DURATION_MILLIS; + } + else + { + durationMillis = NORMAL_DURATION_MILLIS; + } + + WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); final GroundItem groundItem = GroundItem.builder() .id(itemId) @@ -378,8 +455,12 @@ public class GroundItemsPlugin extends Plugin .quantity(item.getQuantity()) .name(itemComposition.getName()) .haPrice(alchPrice) - .height(tile.getItemLayer().getHeight()) + .height(-1) .tradeable(itemComposition.isTradeable()) + .droppedInstant(Instant.now()) + .durationMillis(durationMillis) + .isAlwaysPrivate(client.isInInstancedRegion() || (!itemComposition.isTradeable() && realItemId != COINS)) + .isOwnedByPlayer(tile.getWorldLocation().equals(playerLocation)) .build(); @@ -539,8 +620,6 @@ public class GroundItemsPlugin extends Plugin { return entries; } - - } void updateList(String item, boolean hiddenList) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/TimerDisplayMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/TimerDisplayMode.java new file mode 100644 index 0000000000..3a6773078e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/TimerDisplayMode.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Matthew Smith + * 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.grounditems.config; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum TimerDisplayMode +{ + ALWAYS("Always"), + HOTKEY_PRESSED("When Hotkey Pressed"), + NEVER("Never"); + + private final String name; + + @Override + public String toString() + { + return name; + } +} \ No newline at end of file From 331594668e310474e10fe64f950f7e1ee47eff91 Mon Sep 17 00:00:00 2001 From: sdburns1998 <49877861+sdburns1998@users.noreply.github.com> Date: Mon, 20 May 2019 18:30:25 +0200 Subject: [PATCH 4/4] Check for NPE - ItemCharges (#324) --- .../plugins/itemcharges/ItemChargePlugin.java | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java index 94c5862bc2..9e165e639a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java @@ -39,6 +39,7 @@ import net.runelite.api.InventoryID; import net.runelite.api.Item; import net.runelite.api.ItemContainer; import net.runelite.api.ItemID; +import static net.runelite.api.ItemID.RING_OF_RECOIL; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameTick; @@ -57,8 +58,6 @@ import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.util.Text; -import static net.runelite.api.ItemID.RING_OF_RECOIL; - @PluginDescriptor( name = "Item Charges", description = "Show number of item charges remaining", @@ -411,26 +410,34 @@ public class ItemChargePlugin extends Plugin } } - ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); - ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); - ringOfRecoilAvailable = false; - ringOfRecoilEquipped = false; + ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); + ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + ringOfRecoilAvailable = false; + ringOfRecoilEquipped = false; - Item ring = equipment.getItems()[net.runelite.api.EquipmentInventorySlot.RING.getSlotIdx()]; - if (ring.getId() == RING_OF_RECOIL) + Item ring = null; + if (equipment != null) + { + ring = equipment.getItems()[EquipmentInventorySlot.RING.getSlotIdx()]; + } + if (ring != null && ring.getId() == RING_OF_RECOIL) + { + ringOfRecoilEquipped = true; + ringOfRecoilAvailable = true; + } + Item[] items = new Item[0]; + if (inventory != null) + { + items = inventory.getItems(); + } + for (Item item : items) + { + if (item.getId() == RING_OF_RECOIL) { - ringOfRecoilEquipped = true; ringOfRecoilAvailable = true; + break; } - Item[] items = inventory.getItems(); - for (Item item : items) - { - if (item.getId() == RING_OF_RECOIL) - { - ringOfRecoilAvailable = true; - break; - } - } + } Widget dialog1 = client.getWidget(WidgetInfo.DIALOG_SPRITE_TEXT); Widget dialog2 = client.getWidget(WidgetInfo.DIALOG2_SPRITE_TEXT);