From 3c59e4bcf0cb2e98720a5ce058c24fbf8309f636 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 28 May 2021 14:54:29 -0400 Subject: [PATCH 01/13] Strip tags when doing friends chat lookups The previous friend chat manager would do this when loading a name into the cache, but now that the cache is gone, we need to do it prior to the lookup --- .../runelite/client/plugins/chatchannel/ChatChannelPlugin.java | 2 +- .../plugins/playerindicators/PlayerIndicatorsService.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java index ed9613da66..8eefd23fba 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java @@ -786,7 +786,7 @@ public class ChatChannelPlugin extends Plugin private void insertRankIcon(final ChatMessage message) { - final FriendsChatRank rank = getRank(message.getName()); + final FriendsChatRank rank = getRank(Text.removeTags(message.getName())); if (rank != null && rank != FriendsChatRank.UNRANKED) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsService.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsService.java index e39e4bd79d..381c808623 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsService.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsService.java @@ -38,6 +38,7 @@ import net.runelite.api.clan.ClanChannelMember; import net.runelite.api.clan.ClanRank; import net.runelite.api.clan.ClanSettings; import net.runelite.api.clan.ClanTitle; +import net.runelite.client.util.Text; @Singleton public class PlayerIndicatorsService @@ -130,7 +131,7 @@ public class PlayerIndicatorsService return FriendsChatRank.UNRANKED; } - FriendsChatMember friendsChatMember = friendsChatManager.findByName(player.getName()); + FriendsChatMember friendsChatMember = friendsChatManager.findByName(Text.removeTags(player.getName())); return friendsChatMember != null ? friendsChatMember.getRank() : FriendsChatRank.UNRANKED; } } From c7d4a10a4a432ae997eaf2557a95d01a685f17eb Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 28 May 2021 21:55:36 -0400 Subject: [PATCH 02/13] api: add clan channel changed event --- .../api/events/ClanChannelChanged.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 runelite-api/src/main/java/net/runelite/api/events/ClanChannelChanged.java diff --git a/runelite-api/src/main/java/net/runelite/api/events/ClanChannelChanged.java b/runelite-api/src/main/java/net/runelite/api/events/ClanChannelChanged.java new file mode 100644 index 0000000000..57abd91dbb --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/events/ClanChannelChanged.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021, Adam + * 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.api.events; + +import javax.annotation.Nullable; +import lombok.Value; +import net.runelite.api.clan.ClanChannel; + +/** + * An event fired when the local player joins or leaves a clan channel. + */ +@Value +public class ClanChannelChanged +{ + /** + * The clan channel + */ + @Nullable + private final ClanChannel clanChannel; + /** + * Whether or not this was the guest clan channel + */ + private boolean guest; +} From d98adda7c2ce4dca6da3c7d3de103f3a50b08cd6 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 28 May 2021 21:51:24 -0400 Subject: [PATCH 03/13] team capes: rename to team Move friends list indicator from chatchannel to team plugin --- .../chatchannel/ChatChannelConfig.java | 12 - .../chatchannel/ChatChannelPlugin.java | 116 ------ .../MembersIndicator.java | 26 +- .../{teamcapes => team}/TeamCapesOverlay.java | 10 +- .../TeamConfig.java} | 50 ++- .../client/plugins/team/TeamPlugin.java | 329 ++++++++++++++++++ .../plugins/teamcapes/TeamCapesPlugin.java | 151 -------- 7 files changed, 386 insertions(+), 308 deletions(-) rename runelite-client/src/main/java/net/runelite/client/plugins/{chatchannel => team}/MembersIndicator.java (75%) rename runelite-client/src/main/java/net/runelite/client/plugins/{teamcapes => team}/TeamCapesOverlay.java (93%) rename runelite-client/src/main/java/net/runelite/client/plugins/{teamcapes/TeamCapesConfig.java => team/TeamConfig.java} (62%) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/team/TeamPlugin.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesPlugin.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelConfig.java index d8b4fede63..2897b73955 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelConfig.java @@ -92,18 +92,6 @@ public interface ChatChannelConfig extends Config return true; } - @ConfigItem( - keyName = "clanCounter", - name = "Members Counter", - description = "Show the amount of friends chat members near you.", - position = 3, - section = friendsChatSection - ) - default boolean showCounter() - { - return false; - } - @ConfigItem( keyName = "chatsData", name = "", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java index 8eefd23fba..951b3368cc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java @@ -32,7 +32,6 @@ import com.google.common.collect.Lists; import com.google.common.util.concurrent.Runnables; import com.google.inject.Provides; import java.awt.Color; -import java.awt.image.BufferedImage; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; @@ -53,9 +52,7 @@ import net.runelite.api.GameState; import net.runelite.api.Ignore; import net.runelite.api.MessageNode; import net.runelite.api.NameableContainer; -import net.runelite.api.Player; import net.runelite.api.ScriptID; -import net.runelite.api.SpriteID; import net.runelite.api.VarClientStr; import net.runelite.api.Varbits; import net.runelite.api.clan.ClanChannel; @@ -71,8 +68,6 @@ import net.runelite.api.events.FriendsChatMemberJoined; import net.runelite.api.events.FriendsChatMemberLeft; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; -import net.runelite.api.events.PlayerDespawned; -import net.runelite.api.events.PlayerSpawned; import net.runelite.api.events.ScriptCallbackEvent; import net.runelite.api.events.ScriptPostFired; import net.runelite.api.events.VarClientStrChanged; @@ -88,7 +83,6 @@ import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; import net.runelite.client.game.ChatIconManager; -import net.runelite.client.game.SpriteManager; import net.runelite.client.game.chatbox.ChatboxPanelManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -96,7 +90,6 @@ import static net.runelite.client.ui.JagexColors.CHAT_FC_NAME_OPAQUE_BACKGROUND; import static net.runelite.client.ui.JagexColors.CHAT_FC_NAME_TRANSPARENT_BACKGROUND; import static net.runelite.client.ui.JagexColors.CHAT_FC_TEXT_OPAQUE_BACKGROUND; import static net.runelite.client.ui.JagexColors.CHAT_FC_TEXT_TRANSPARENT_BACKGROUND; -import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.util.Text; @PluginDescriptor( @@ -119,12 +112,6 @@ public class ChatChannelPlugin extends Plugin @Inject private ChatChannelConfig config; - @Inject - private InfoBoxManager infoBoxManager; - - @Inject - private SpriteManager spriteManager; - @Inject private ClientThread clientThread; @@ -138,8 +125,6 @@ public class ChatChannelPlugin extends Plugin private ChatMessageManager chatMessageManager; private List chats; - private final List members = new ArrayList<>(); - private MembersIndicator membersIndicator; /** * queue of temporary messages added to the client */ @@ -186,8 +171,6 @@ public class ChatChannelPlugin extends Plugin { chats = null; clientThread.invoke(() -> colorIgnoredPlayers(Color.WHITE)); - members.clear(); - resetCounter(); rebuildFriendsChat(); inputMode = null; } @@ -202,15 +185,6 @@ public class ChatChannelPlugin extends Plugin rebuildFriendsChat(); } - if (config.showCounter()) - { - clientThread.invoke(this::addCounter); - } - else - { - resetCounter(); - } - Color ignoreColor = config.showIgnores() ? config.showIgnoresColor() : Color.WHITE; clientThread.invoke(() -> colorIgnoredPlayers(ignoreColor)); } @@ -221,22 +195,6 @@ public class ChatChannelPlugin extends Plugin { final FriendsChatMember member = event.getMember(); - if (member.getWorld() == client.getWorld()) - { - final Player local = client.getLocalPlayer(); - final String memberName = Text.toJagexName(member.getName()); - - for (final Player player : client.getPlayers()) - { - if (player != null && player != local && memberName.equals(Text.toJagexName(player.getName()))) - { - members.add(player); - addCounter(); - break; - } - } - } - // members getting initialized isn't relevant if (joinedTick == client.getTickCount()) { @@ -258,27 +216,6 @@ public class ChatChannelPlugin extends Plugin { final FriendsChatMember member = event.getMember(); - if (member.getWorld() == client.getWorld()) - { - final String memberName = Text.toJagexName(member.getName()); - final Iterator each = members.iterator(); - - while (each.hasNext()) - { - if (memberName.equals(Text.toJagexName(each.next().getName()))) - { - each.remove(); - - if (members.isEmpty()) - { - resetCounter(); - } - - break; - } - } - } - if (!config.showJoinLeave() || member.getRank().getValue() < config.joinLeaveRank().getValue()) { @@ -625,35 +562,10 @@ public class ChatChannelPlugin extends Plugin if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.CONNECTION_LOST || gameState == GameState.HOPPING) { - members.clear(); - resetCounter(); - joinMessages.clear(); } } - @Subscribe - public void onPlayerSpawned(PlayerSpawned event) - { - final Player local = client.getLocalPlayer(); - final Player player = event.getPlayer(); - - if (player != local && player.isFriendsChatMember()) - { - members.add(player); - addCounter(); - } - } - - @Subscribe - public void onPlayerDespawned(PlayerDespawned event) - { - if (members.remove(event.getPlayer()) && members.isEmpty()) - { - resetCounter(); - } - } - @Subscribe public void onFriendsChatChanged(FriendsChatChanged event) { @@ -661,11 +573,6 @@ public class ChatChannelPlugin extends Plugin { joinedTick = client.getTickCount(); } - else - { - members.clear(); - resetCounter(); - } activityBuffer.clear(); } @@ -779,11 +686,6 @@ public class ChatChannelPlugin extends Plugin } } - int getMembersSize() - { - return members.size(); - } - private void insertRankIcon(final ChatMessage message) { final FriendsChatRank rank = getRank(Text.removeTags(message.getName())); @@ -879,24 +781,6 @@ public class ChatChannelPlugin extends Plugin config.chatsData(Text.toCSV(chats)); } - private void resetCounter() - { - infoBoxManager.removeInfoBox(membersIndicator); - membersIndicator = null; - } - - private void addCounter() - { - if (!config.showCounter() || membersIndicator != null || members.isEmpty()) - { - return; - } - - final BufferedImage image = spriteManager.getSprite(SpriteID.TAB_FRIENDS_CHAT, 0); - membersIndicator = new MembersIndicator(image, this); - infoBoxManager.addInfoBox(membersIndicator); - } - private void confirmKickPlayer(final String kickPlayerName) { chatboxPanelManager.openTextMenuInput("Attempting to kick: " + kickPlayerName) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/MembersIndicator.java b/runelite-client/src/main/java/net/runelite/client/plugins/team/MembersIndicator.java similarity index 75% rename from runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/MembersIndicator.java rename to runelite-client/src/main/java/net/runelite/client/plugins/team/MembersIndicator.java index a8d2b87775..2f7563716b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/MembersIndicator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/team/MembersIndicator.java @@ -22,32 +22,18 @@ * (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.chatchannel; +package net.runelite.client.plugins.team; import java.awt.Color; import java.awt.image.BufferedImage; -import net.runelite.client.ui.overlay.infobox.Counter; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.ui.overlay.infobox.InfoBox; -class MembersIndicator extends Counter +abstract class MembersIndicator extends InfoBox { - private final ChatChannelPlugin plugin; - - MembersIndicator(BufferedImage image, ChatChannelPlugin plugin) + MembersIndicator(BufferedImage image, Plugin plugin) { - super(image, plugin, plugin.getMembersSize()); - this.plugin = plugin; - } - - @Override - public int getCount() - { - return plugin.getMembersSize(); - } - - @Override - public String getTooltip() - { - return plugin.getMembersSize() + " friends chat member(s) near you"; + super(image, plugin); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamCapesOverlay.java similarity index 93% rename from runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesOverlay.java rename to runelite-client/src/main/java/net/runelite/client/plugins/team/TeamCapesOverlay.java index 1d54c85935..d4f119c164 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamCapesOverlay.java @@ -22,7 +22,7 @@ * (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.teamcapes; +package net.runelite.client.plugins.team; import java.awt.Dimension; import java.awt.Graphics2D; @@ -41,12 +41,12 @@ import net.runelite.client.ui.overlay.components.ImageComponent; class TeamCapesOverlay extends OverlayPanel { - private final TeamCapesPlugin plugin; - private final TeamCapesConfig config; + private final TeamPlugin plugin; + private final TeamConfig config; private final ItemManager manager; @Inject - private TeamCapesOverlay(TeamCapesPlugin plugin, TeamCapesConfig config, ItemManager manager) + private TeamCapesOverlay(TeamPlugin plugin, TeamConfig config, ItemManager manager) { super(plugin); setPosition(OverlayPosition.TOP_LEFT); @@ -63,7 +63,7 @@ class TeamCapesOverlay extends OverlayPanel public Dimension render(Graphics2D graphics) { Map teams = plugin.getTeams(); - if (teams.isEmpty()) + if (teams.isEmpty() || !config.teamCapesOverlay()) { return null; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamConfig.java similarity index 62% rename from runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesConfig.java rename to runelite-client/src/main/java/net/runelite/client/plugins/team/TeamConfig.java index 17e42e0f24..4de3ffeae1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamConfig.java @@ -22,23 +22,65 @@ * (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.teamcapes; +package net.runelite.client.plugins.team; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigSection; -@ConfigGroup("teamCapes") -public interface TeamCapesConfig extends Config +@ConfigGroup(TeamConfig.GROUP) +public interface TeamConfig extends Config { + String GROUP = "teamCapes"; + + @ConfigSection( + name = "Team", + description = "Configuration for teams", + position = 10 + ) + String teamSection = "teamSection"; + + @ConfigSection( + name = "Friends Chat", + description = "Configuration for friends chat", + position = 20 + ) + String friendsChatSection = "friendsChatSection"; + + @ConfigItem( + keyName = "teamCapesOverlay", + name = "Team cape overlay", + description = "Configures whether to show the team cape overlay.", + position = 0, + section = teamSection + ) + default boolean teamCapesOverlay() + { + return false; + } + @ConfigItem( keyName = "minimumCapeCount", name = "Minimum Cape Count", description = "Configures the minimum number of team capes which must be present before being displayed.", - position = 0 + position = 1, + section = teamSection ) default int getMinimumCapeCount() { return 1; } + + @ConfigItem( + keyName = "friendsChatMemberCounter", + name = "Friends Chat Members Counter", + description = "Show the amount of friends chat members near you.", + position = 0, + section = friendsChatSection + ) + default boolean friendsChatMemberCounter() + { + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamPlugin.java new file mode 100644 index 0000000000..071065d023 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamPlugin.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2017, Devin French + * Copyright (c) 2021, Adam + * 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.team; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.inject.Provides; +import java.awt.image.BufferedImage; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.FriendsChatMember; +import net.runelite.api.GameState; +import net.runelite.api.Player; +import net.runelite.api.SpriteID; +import net.runelite.api.clan.ClanChannel; +import net.runelite.api.clan.ClanChannelMember; +import net.runelite.api.events.ClanChannelChanged; +import net.runelite.api.events.ClanMemberJoined; +import net.runelite.api.events.ClanMemberLeft; +import net.runelite.api.events.FriendsChatChanged; +import net.runelite.api.events.FriendsChatMemberJoined; +import net.runelite.api.events.FriendsChatMemberLeft; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.PlayerChanged; +import net.runelite.api.events.PlayerDespawned; +import net.runelite.api.events.PlayerSpawned; +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.SpriteManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.util.Text; + +@PluginDescriptor( + name = "Team", + description = "Shows how many team and clan mates are nearby", + tags = {"overlay", "players", "cape", "clan", "friend"}, + configName = "TeamCapesPlugin", // the old plugin's name + enabledByDefault = false +) +@Slf4j +public class TeamPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private OverlayManager overlayManager; + + @Inject + private TeamConfig config; + + @Inject + private TeamCapesOverlay overlay; + + @Inject + private SpriteManager spriteManager; + + @Inject + private InfoBoxManager infoBoxManager; + + // Team number -> Number of players + @Getter(AccessLevel.PACKAGE) + private Map teams = new LinkedHashMap<>(); + // Player -> Team number + private final Map playerTeam = new HashMap<>(); + + private final BiMap players = HashBiMap.create(); + private int friendsChatCount; + private MembersIndicator friendsChatIndicator; + + @Provides + TeamConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(TeamConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + + clientThread.invokeLater(() -> client.getPlayers().forEach(this::updateTeam)); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + teams.clear(); + playerTeam.clear(); + players.clear(); + removeFriendsChatCounter(); + friendsChatCount = 0; + } + + @Subscribe + public void onConfigChanged(ConfigChanged configChanged) + { + if (configChanged.getGroup().equals(TeamConfig.GROUP)) + { + if (config.friendsChatMemberCounter()) + { + clientThread.invoke(this::addFriendsChatCounter); + } + else + { + removeFriendsChatCounter(); + } + } + } + + @Subscribe + public void onGameStateChanged(GameStateChanged state) + { + GameState gameState = state.getGameState(); + + if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.CONNECTION_LOST || gameState == GameState.HOPPING) + { + players.clear(); + removeFriendsChatCounter(); + } + } + + @Subscribe + public void onPlayerSpawned(PlayerSpawned event) + { + final Player local = client.getLocalPlayer(); + final Player player = event.getPlayer(); + + if (player != local) + { + players.put(Text.removeTags(player.getName()), player); + + if (player.isFriendsChatMember()) + { + ++friendsChatCount; + addFriendsChatCounter(); + } + } + } + + @Subscribe + public void onPlayerDespawned(PlayerDespawned playerDespawned) + { + Player player = playerDespawned.getPlayer(); + Integer team = playerTeam.remove(player); + if (team != null) + { + teams.computeIfPresent(team, (key, value) -> value > 1 ? value - 1 : null); + sortTeams(); + } + + players.inverse().remove(player); + + if (player.isFriendsChatMember()) + { + if (friendsChatCount > 0) + { + if (--friendsChatCount == 0) + { + removeFriendsChatCounter(); + } + } + } + } + + @Subscribe + public void onPlayerChanged(PlayerChanged playerChanged) + { + Player player = playerChanged.getPlayer(); + updateTeam(player); + } + + private void updateTeam(Player player) + { + int oldTeam = playerTeam.getOrDefault(player, 0); + if (oldTeam == player.getTeam()) + { + return; + } + + log.debug("{} has changed teams: {} -> {}", player.getName(), oldTeam, player.getTeam()); + + if (oldTeam > 0) + { + teams.computeIfPresent(oldTeam, (key, value) -> value > 1 ? value - 1 : null); + playerTeam.remove(player); + } + + if (player.getTeam() > 0) + { + teams.merge(player.getTeam(), 1, Integer::sum); + playerTeam.put(player, player.getTeam()); + } + + sortTeams(); + } + + private void sortTeams() + { + // Sort teams by value in descending order and then by key in ascending order, limited to 5 entries + teams = teams.entrySet().stream() + .sorted( + Comparator.comparing(Map.Entry::getValue, Comparator.reverseOrder()) + .thenComparingInt(Map.Entry::getKey) + ) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); + } + + @Subscribe + public void onFriendsChatChanged(FriendsChatChanged event) + { + if (!event.isJoined()) + { + removeFriendsChatCounter(); + friendsChatCount = 0; + } + } + + @Subscribe + public void onFriendsChatMemberJoined(FriendsChatMemberJoined event) + { + final FriendsChatMember member = event.getMember(); + + if (member.getWorld() == client.getWorld()) + { + final String memberName = Text.toJagexName(member.getName()); + + final Player player = players.get(memberName); + if (player != null) + { + ++friendsChatCount; + addFriendsChatCounter(); + } + } + } + + @Subscribe + public void onFriendsChatMemberLeft(FriendsChatMemberLeft event) + { + final FriendsChatMember member = event.getMember(); + + if (member.getWorld() == client.getWorld()) + { + final String memberName = Text.toJagexName(member.getName()); + final Player player = players.get(memberName); + if (player != null) + { + if (friendsChatCount > 0) + { + if (--friendsChatCount == 0) + { + removeFriendsChatCounter(); + } + } + } + } + } + + private void addFriendsChatCounter() + { + if (!config.friendsChatMemberCounter() || friendsChatIndicator != null || friendsChatCount == 0) + { + return; + } + + final BufferedImage image = spriteManager.getSprite(SpriteID.TAB_FRIENDS_CHAT, 0); + friendsChatIndicator = new MembersIndicator(image, this) + { + @Override + public String getText() + { + return Integer.toString(friendsChatCount); + } + + @Override + public String getTooltip() + { + return friendsChatCount + " friends chat member(s) near you"; + } + }; + infoBoxManager.addInfoBox(friendsChatIndicator); + } + + private void removeFriendsChatCounter() + { + infoBoxManager.removeInfoBox(friendsChatIndicator); + friendsChatIndicator = null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesPlugin.java deleted file mode 100644 index c36b7ddd76..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesPlugin.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2017, Devin French - * 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.teamcapes; - -import com.google.inject.Provides; -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.stream.Collectors; -import javax.inject.Inject; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.Player; -import net.runelite.api.events.PlayerChanged; -import net.runelite.api.events.PlayerDespawned; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Team Capes", - description = "Show the different team capes in your area and the amount of each", - tags = {"overlay", "players"}, - enabledByDefault = false -) -@Slf4j -public class TeamCapesPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private ClientThread clientThread; - - @Inject - private OverlayManager overlayManager; - - @Inject - private TeamCapesOverlay overlay; - - // Team number -> Number of players - @Getter(AccessLevel.PACKAGE) - private Map teams = new LinkedHashMap<>(); - // Player -> Team number - private final Map playerTeam = new HashMap<>(); - - @Provides - TeamCapesConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(TeamCapesConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - - clientThread.invokeLater(() -> client.getPlayers().forEach(this::update)); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - teams.clear(); - playerTeam.clear(); - } - - @Subscribe - public void onPlayerChanged(PlayerChanged playerChanged) - { - Player player = playerChanged.getPlayer(); - update(player); - } - - private void update(Player player) - { - int oldTeam = playerTeam.getOrDefault(player, 0); - if (oldTeam == player.getTeam()) - { - return; - } - - log.debug("{} has changed teams: {} -> {}", player.getName(), oldTeam, player.getTeam()); - - if (oldTeam > 0) - { - teams.computeIfPresent(oldTeam, (key, value) -> value > 1 ? value - 1 : null); - playerTeam.remove(player); - } - - if (player.getTeam() > 0) - { - teams.merge(player.getTeam(), 1, Integer::sum); - playerTeam.put(player, player.getTeam()); - } - - sort(); - } - - @Subscribe - public void onPlayerDespawned(PlayerDespawned playerDespawned) - { - Player player = playerDespawned.getPlayer(); - Integer team = playerTeam.remove(player); - if (team != null) - { - teams.computeIfPresent(team, (key, value) -> value > 1 ? value - 1 : null); - sort(); - } - } - - private void sort() - { - // Sort teams by value in descending order and then by key in ascending order, limited to 5 entries - teams = teams.entrySet().stream() - .sorted( - Comparator.comparing(Map.Entry::getValue, Comparator.reverseOrder()) - .thenComparingInt(Map.Entry::getKey) - ) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); - } -} From fb7cea1678812c566f424c86f9c18be5d64c2b0f Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 28 May 2021 21:06:04 -0400 Subject: [PATCH 04/13] team: add clan member counter --- .../main/java/net/runelite/api/SpriteID.java | 1 + .../client/plugins/team/TeamConfig.java | 19 +++ .../client/plugins/team/TeamPlugin.java | 129 ++++++++++++++++++ 3 files changed, 149 insertions(+) diff --git a/runelite-api/src/main/java/net/runelite/api/SpriteID.java b/runelite-api/src/main/java/net/runelite/api/SpriteID.java index 77cae9b584..3721e8689a 100644 --- a/runelite-api/src/main/java/net/runelite/api/SpriteID.java +++ b/runelite-api/src/main/java/net/runelite/api/SpriteID.java @@ -1579,6 +1579,7 @@ public final class SpriteID public static final int HEALTHBAR_DEFAULT_BACK_140PX = 2189; public static final int HEALTHBAR_DEFAULT_FRONT_160PX = 2190; public static final int HEALTHBAR_DEFAULT_BACK_160PX = 2191; + public static final int TAB_CLAN_CHAT = 2307; public static final int WIKI_DESELECTED = 2420; public static final int WIKI_SELECTED = 2421; public static final int FRIENDS_CHAT_RANK_SMILEY_FRIEND = 2825; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamConfig.java index 4de3ffeae1..8f46f59101 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamConfig.java @@ -48,6 +48,13 @@ public interface TeamConfig extends Config ) String friendsChatSection = "friendsChatSection"; + @ConfigSection( + name = "Clan Chat", + description = "Configuration for clan chat", + position = 30 + ) + String clanChatSection = "clanChatSection"; + @ConfigItem( keyName = "teamCapesOverlay", name = "Team cape overlay", @@ -83,4 +90,16 @@ public interface TeamConfig extends Config { return false; } + + @ConfigItem( + keyName = "clanChatMemberCounter", + name = "Clan Chat Members Counter", + description = "Show the amount of clan chat members near you.", + position = 0, + section = clanChatSection + ) + default boolean clanChatMemberCounter() + { + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamPlugin.java index 071065d023..4d78816524 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/team/TeamPlugin.java @@ -105,7 +105,9 @@ public class TeamPlugin extends Plugin private final BiMap players = HashBiMap.create(); private int friendsChatCount; + private int clanChatCount; private MembersIndicator friendsChatIndicator; + private MembersIndicator clanChatIndicator; @Provides TeamConfig provideConfig(ConfigManager configManager) @@ -129,7 +131,9 @@ public class TeamPlugin extends Plugin playerTeam.clear(); players.clear(); removeFriendsChatCounter(); + removeClanChatCounter(); friendsChatCount = 0; + clanChatCount = 0; } @Subscribe @@ -145,6 +149,15 @@ public class TeamPlugin extends Plugin { removeFriendsChatCounter(); } + + if (config.clanChatMemberCounter()) + { + clientThread.invoke(this::addClanChatCounter); + } + else + { + removeClanChatCounter(); + } } } @@ -157,6 +170,7 @@ public class TeamPlugin extends Plugin { players.clear(); removeFriendsChatCounter(); + removeClanChatCounter(); } } @@ -175,6 +189,12 @@ public class TeamPlugin extends Plugin ++friendsChatCount; addFriendsChatCounter(); } + + if (player.isClanMember()) + { + ++clanChatCount; + addClanChatCounter(); + } } } @@ -201,6 +221,17 @@ public class TeamPlugin extends Plugin } } } + + if (player.isClanMember()) + { + if (clanChatCount > 0) + { + if (--clanChatCount == 0) + { + removeClanChatCounter(); + } + } + } } @Subscribe @@ -256,6 +287,33 @@ public class TeamPlugin extends Plugin } } + @Subscribe + public void onClanChannelChanged(ClanChannelChanged event) + { + if (!event.isGuest()) + { + removeClanChatCounter(); + clanChatCount = 0; + + ClanChannel clanChannel = event.getClanChannel(); + if (clanChannel != null) + { + for (ClanChannelMember member : clanChannel.getMembers()) + { + final String memberName = Text.toJagexName(member.getName()); + + final Player player = players.get(memberName); + if (player != null) + { + ++clanChatCount; + } + } + + addClanChatCounter(); + } + } + } + @Subscribe public void onFriendsChatMemberJoined(FriendsChatMemberJoined event) { @@ -296,6 +354,46 @@ public class TeamPlugin extends Plugin } } + @Subscribe + public void onClanMemberJoined(ClanMemberJoined clanMemberJoined) + { + final ClanChannelMember member = clanMemberJoined.getClanMember(); + + if (member.getWorld() == client.getWorld()) + { + final String memberName = Text.toJagexName(member.getName()); + + final Player player = players.get(memberName); + if (player != null) + { + ++clanChatCount; + addClanChatCounter(); + } + } + } + + @Subscribe + public void onClanMemberLeft(ClanMemberLeft clanMemberLeft) + { + final ClanChannelMember member = clanMemberLeft.getClanMember(); + + if (member.getWorld() == client.getWorld()) + { + final String memberName = Text.toJagexName(member.getName()); + final Player player = players.get(memberName); + if (player != null) + { + if (clanChatCount > 0) + { + if (--clanChatCount == 0) + { + removeClanChatCounter(); + } + } + } + } + } + private void addFriendsChatCounter() { if (!config.friendsChatMemberCounter() || friendsChatIndicator != null || friendsChatCount == 0) @@ -326,4 +424,35 @@ public class TeamPlugin extends Plugin infoBoxManager.removeInfoBox(friendsChatIndicator); friendsChatIndicator = null; } + + private void addClanChatCounter() + { + if (!config.clanChatMemberCounter() || clanChatIndicator != null || clanChatCount == 0) + { + return; + } + + final BufferedImage image = spriteManager.getSprite(SpriteID.TAB_CLAN_CHAT, 0); + clanChatIndicator = new MembersIndicator(image, this) + { + @Override + public String getText() + { + return Integer.toString(clanChatCount); + } + + @Override + public String getTooltip() + { + return clanChatCount + " clan chat member(s) near you"; + } + }; + infoBoxManager.addInfoBox(clanChatIndicator); + } + + private void removeClanChatCounter() + { + infoBoxManager.removeInfoBox(clanChatIndicator); + clanChatIndicator = null; + } } From 68e8712ffcc49a467427ec4990b80425f82e18fc Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 29 May 2021 22:06:05 -0400 Subject: [PATCH 05/13] chatchannel: fix clan join/leave timeouts with fc join/leave off --- .../client/plugins/chatchannel/ChatChannelConfig.java | 2 +- .../client/plugins/chatchannel/ChatChannelPlugin.java | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelConfig.java index 2897b73955..eeffc30f4d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelConfig.java @@ -117,7 +117,7 @@ public interface ChatChannelConfig extends Config position = 4, section = friendsChatSection ) - default boolean showJoinLeave() + default boolean showFriendsChatJoinLeave() { return false; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java index 951b3368cc..b77c6745cd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatchannel/ChatChannelPlugin.java @@ -201,7 +201,7 @@ public class ChatChannelPlugin extends Plugin return; } - if (!config.showJoinLeave() || + if (!config.showFriendsChatJoinLeave() || member.getRank().getValue() < config.joinLeaveRank().getValue()) { return; @@ -216,7 +216,7 @@ public class ChatChannelPlugin extends Plugin { final FriendsChatMember member = event.getMember(); - if (!config.showJoinLeave() || + if (!config.showFriendsChatJoinLeave() || member.getRank().getValue() < config.joinLeaveRank().getValue()) { return; @@ -315,11 +315,6 @@ public class ChatChannelPlugin extends Plugin } } - if (!config.showJoinLeave()) - { - return; - } - timeoutMessages(); addActivityMessages(); From d4dc309cf5b90faa4d7083df5dbc4bc1b8d15b57 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 30 May 2021 23:46:55 -0400 Subject: [PATCH 06/13] sprite manager: use constructor injection Also make cache private --- .../runelite/client/game/SpriteManager.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/game/SpriteManager.java b/runelite-client/src/main/java/net/runelite/client/game/SpriteManager.java index 7c0bd4f2fc..5920682dd7 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/SpriteManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/SpriteManager.java @@ -26,12 +26,12 @@ package net.runelite.client.game; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import com.google.inject.Inject; import java.awt.image.BufferedImage; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import javax.annotation.Nullable; +import javax.inject.Inject; import javax.inject.Singleton; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -48,20 +48,23 @@ import net.runelite.client.util.ImageUtil; @Singleton public class SpriteManager { - @Inject - private Client client; + private final Client client; + private final ClientThread clientThread; + private final InfoBoxManager infoBoxManager; - @Inject - private ClientThread clientThread; - - @Inject - private InfoBoxManager infoBoxManager; - - public Cache cache = CacheBuilder.newBuilder() + private final Cache cache = CacheBuilder.newBuilder() .maximumSize(128L) .expireAfterAccess(1, TimeUnit.HOURS) .build(); + @Inject + private SpriteManager(Client client, ClientThread clientThread, InfoBoxManager infoBoxManager) + { + this.client = client; + this.clientThread = clientThread; + this.infoBoxManager = infoBoxManager; + } + @Nullable public BufferedImage getSprite(int archive, int file) { From b6462e4619320ef9fda2e898bc36fbe4d23d08c1 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 30 May 2021 14:17:50 -0400 Subject: [PATCH 07/13] chat filter: fix collapsing replayed public chat Public chat is both replayed and also collapsed. Since replayed messages don't send chat message events, all replayed messages would be filtered due to the last message id not being updated for any of them. Instead, set all stored messages ids to -1 on login, since the ids are invalidated anyway, and then use it to not collapse replayed chat. --- .../plugins/chatfilter/ChatFilterPlugin.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java index 4cdcc62404..6baaeb79a5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java @@ -55,6 +55,7 @@ import net.runelite.api.MessageNode; import net.runelite.api.Player; import net.runelite.api.clan.ClanChannel; import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.OverheadTextChanged; import net.runelite.api.events.ScriptCallbackEvent; import net.runelite.client.config.ConfigManager; @@ -139,6 +140,19 @@ public class ChatFilterPlugin extends Plugin client.refreshChat(); } + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + switch (gameStateChanged.getGameState()) + { + // Login drops references to all messages and also resets the global message id counter. + // Invalidate the message id so it doesn't collide later when rebuilding the chatfilter. + case HOPPING: + case LOGGING_IN: + duplicateChatCache.values().forEach(d -> d.messageId = -1); + } + } + @Subscribe public void onScriptCallbackEvent(ScriptCallbackEvent event) { @@ -205,7 +219,10 @@ public class ChatFilterPlugin extends Plugin if (!blockMessage && shouldCollapse) { Duplicate duplicateCacheEntry = duplicateChatCache.get(name + ":" + message); - if (duplicateCacheEntry != null) + // If messageId is -1 then this is a replayed message, which we can't easily collapse since we don't know + // the most recent message. This is only for public chat since it is the only thing both replayed and also + // collapsed. Just allow uncollapsed playback. + if (duplicateCacheEntry != null && duplicateCacheEntry.messageId != -1) { blockMessage = duplicateCacheEntry.messageId != messageId || ((chatMessageType == PUBLICCHAT || chatMessageType == MODCHAT) && From 14545aac26de7178cf37ddb9aa1fe57396834a34 Mon Sep 17 00:00:00 2001 From: Max Weber Date: Sat, 29 May 2021 15:01:58 -0600 Subject: [PATCH 08/13] rl-client: never cache 4/5xx requests --- .../java/net/runelite/client/RuneLite.java | 24 +++- .../client/OkHttpCacheSanityTest.java | 125 ++++++++++++++++++ 2 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 runelite-client/src/test/java/net/runelite/client/OkHttpCacheSanityTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index 49ea8383a6..42b57e6366 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -73,6 +73,7 @@ import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay; import net.runelite.http.api.RuneLiteAPI; import okhttp3.Cache; import okhttp3.OkHttpClient; +import okhttp3.Response; import org.slf4j.LoggerFactory; @Singleton @@ -191,8 +192,8 @@ public class RuneLite } }); - OkHttpClient.Builder okHttpClientBuilder = RuneLiteAPI.CLIENT.newBuilder() - .cache(new Cache(new File(CACHE_DIR, "okhttp"), MAX_OKHTTP_CACHE_SIZE)); + OkHttpClient.Builder okHttpClientBuilder = RuneLiteAPI.CLIENT.newBuilder(); + setupCache(okHttpClientBuilder, new File(CACHE_DIR, "okhttp")); final boolean insecureSkipTlsVerification = options.has("insecure-skip-tls-verification"); if (insecureSkipTlsVerification || RuneLiteProperties.isInsecureSkipTlsVerification()) @@ -381,6 +382,25 @@ public class RuneLite } } + @VisibleForTesting + static void setupCache(OkHttpClient.Builder builder, File cacheDir) + { + builder.cache(new Cache(cacheDir, MAX_OKHTTP_CACHE_SIZE)) + .addNetworkInterceptor(chain -> + { + // This has to be a network interceptor so it gets hit before the cache tries to store stuff + Response res = chain.proceed(chain.request()); + if (res.code() >= 400 && "GET".equals(res.request().method())) + { + // if the request 404'd we don't want to cache it because its probably temporary + res = res.newBuilder() + .header("Cache-Control", "no-store") + .build(); + } + return res; + }); + } + private static void setupInsecureTrustManager(OkHttpClient.Builder okHttpClientBuilder) { try diff --git a/runelite-client/src/test/java/net/runelite/client/OkHttpCacheSanityTest.java b/runelite-client/src/test/java/net/runelite/client/OkHttpCacheSanityTest.java new file mode 100644 index 0000000000..2478042ed2 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/OkHttpCacheSanityTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2020 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client; + +import java.io.IOException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Locale; +import java.util.concurrent.TimeUnit; +import net.runelite.http.api.RuneLiteAPI; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class OkHttpCacheSanityTest +{ + @Rule + public TemporaryFolder cacheFolder = new TemporaryFolder(); + + @Rule + public MockWebServer server = new MockWebServer(); + + private static final DateTimeFormatter TIME_FMT = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.US) + .withZone(ZoneId.of("GMT")); + + private static final String BODY_404 = "404 not found"; + private static final String BODY_200 = "{success:true}"; + + /** + * The specific thing we are trying to catch here is when a 404 + * response is served by cloudflare after the upstream has gotten + * an updated document. CF serves the 404 response with a Date header, + * but no ETag or Last-Modified. OkHttp then uses the Date header, which + * is from after the upstream was edited, in a If-Modified-Since request, + * which does hit the upstream, returning 304 Not Modified. Since there + * is no body OkHttp serves the cached 404 as up-to-date. Better yet, since + * there is now an ETag in the 304 response it requests subsequent updates + * with the ETag, which will always 304 Not Modified, causing clients in + * this state to get incorrect 404s until the ETag changes. + */ + @Test + public void testCacheSanity() throws IOException, InterruptedException + { + OkHttpClient.Builder builder = RuneLiteAPI.CLIENT.newBuilder(); + RuneLite.setupCache(builder, cacheFolder.getRoot()); + OkHttpClient client = builder.build(); + + Instant lastModified = Instant.now().minusSeconds(20); + + server.enqueue(new MockResponse() + .setResponseCode(404) + .setHeader("Content-Type", "text/html") + .setHeader("Date", TIME_FMT.format(Instant.now().minusSeconds(10))) + .setBody(BODY_404)); + try (Response res = client.newCall(new Request.Builder() + .url(server.url("/manifest")) + .build()).execute()) + { + Assert.assertEquals(404, res.code()); + } + RecordedRequest req = server.takeRequest(1, TimeUnit.SECONDS); + Assert.assertNotNull("cache did not make a initial request", req); + + server.enqueue(new MockResponse() + .setResponseCode(200) + .setHeader("Content-Type", "text/html") + .setHeader("Date", TIME_FMT.format(Instant.now().minusSeconds(5))) + .setHeader("Last-Modified", TIME_FMT.format(lastModified)) + .setBody(BODY_200)); + try (Response res = client.newCall(new Request.Builder() + .url(server.url("/manifest")) + .build()).execute()) + { + Assert.assertEquals(200, res.code()); + } + req = server.takeRequest(1, TimeUnit.SECONDS); + Assert.assertNotNull("cache did not make a request", req); + Assert.assertNull(req.getHeader("If-Modified-Since")); + + server.enqueue(new MockResponse() + .setResponseCode(304) + .setHeader("Content-Type", "text/html") + .setHeader("Date", TIME_FMT.format(Instant.now())) + .setHeader("Last-Modified", TIME_FMT.format(lastModified))); + try (Response res = client.newCall(new Request.Builder() + .url(server.url("/manifest")) + .build()).execute()) + { + Assert.assertEquals(200, res.code()); + } + req = server.takeRequest(1, TimeUnit.SECONDS); + Assert.assertNotNull("cache did not make a conditional request", req); + Assert.assertNotNull(req.getHeader("If-Modified-Since")); + } +} From 9e780d58c8b820e8da65f277732799eed135e645 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 31 May 2021 11:34:59 -0400 Subject: [PATCH 09/13] Use junit rule for mock webserver --- .../net/runelite/http/api/RuneLiteAPITest.java | 13 +++---------- .../http/service/hiscore/HiscoreServiceTest.java | 13 +++---------- .../http/service/worlds/WorldsServiceTest.java | 14 +++----------- .../runelite/client/rs/ClientConfigLoaderTest.java | 13 +++---------- 4 files changed, 12 insertions(+), 41 deletions(-) diff --git a/http-api/src/test/java/net/runelite/http/api/RuneLiteAPITest.java b/http-api/src/test/java/net/runelite/http/api/RuneLiteAPITest.java index 42fadf4363..d1fd3562bd 100644 --- a/http-api/src/test/java/net/runelite/http/api/RuneLiteAPITest.java +++ b/http-api/src/test/java/net/runelite/http/api/RuneLiteAPITest.java @@ -28,27 +28,20 @@ import java.io.IOException; import okhttp3.Request; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; -import org.junit.After; import static org.junit.Assert.assertTrue; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; public class RuneLiteAPITest { - private final MockWebServer server = new MockWebServer(); + @Rule + public final MockWebServer server = new MockWebServer(); @Before public void before() throws IOException { server.enqueue(new MockResponse().setBody("OK")); - - server.start(); - } - - @After - public void after() throws IOException - { - server.shutdown(); } @Test diff --git a/http-service/src/test/java/net/runelite/http/service/hiscore/HiscoreServiceTest.java b/http-service/src/test/java/net/runelite/http/service/hiscore/HiscoreServiceTest.java index fb84ee63a4..f22d2c3f5d 100644 --- a/http-service/src/test/java/net/runelite/http/service/hiscore/HiscoreServiceTest.java +++ b/http-service/src/test/java/net/runelite/http/service/hiscore/HiscoreServiceTest.java @@ -29,9 +29,9 @@ import net.runelite.http.api.hiscore.HiscoreEndpoint; import net.runelite.http.api.hiscore.HiscoreResult; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; -import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; public class HiscoreServiceTest @@ -118,20 +118,13 @@ public class HiscoreServiceTest + "19301,62\n" + "1498,5847\n"; - private final MockWebServer server = new MockWebServer(); + @Rule + public final MockWebServer server = new MockWebServer(); @Before public void before() throws IOException { server.enqueue(new MockResponse().setBody(RESPONSE)); - - server.start(); - } - - @After - public void after() throws IOException - { - server.shutdown(); } @Test diff --git a/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java b/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java index a083bba0df..6d55fc52aa 100644 --- a/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java +++ b/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java @@ -32,18 +32,18 @@ import net.runelite.http.api.worlds.WorldType; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okio.Buffer; -import org.junit.After; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.sql2o.tools.IOUtils; public class WorldsServiceTest { - - private final MockWebServer server = new MockWebServer(); + @Rule + public final MockWebServer server = new MockWebServer(); @Before public void before() throws IOException @@ -55,14 +55,6 @@ public class WorldsServiceTest buffer.write(worldData); server.enqueue(new MockResponse().setBody(buffer)); - - server.start(); - } - - @After - public void after() throws IOException - { - server.shutdown(); } @Test diff --git a/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java b/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java index 6ee1ecdf33..ae5572f6ab 100644 --- a/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java +++ b/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java @@ -32,14 +32,15 @@ import java.io.InputStreamReader; import okhttp3.OkHttpClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; -import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; public class ClientConfigLoaderTest { - private final MockWebServer server = new MockWebServer(); + @Rule + public final MockWebServer server = new MockWebServer(); @Before public void before() throws IOException @@ -51,14 +52,6 @@ public class ClientConfigLoaderTest in, Charsets.UTF_8)); } server.enqueue(new MockResponse().setBody(response)); - - server.start(); - } - - @After - public void after() throws IOException - { - server.shutdown(); } @Test From e57f6d0d6e4ba4619d5fb433d07c980b9d8e5652 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Wed, 17 Feb 2021 22:46:40 -0800 Subject: [PATCH 10/13] XpInfoBox: Give stats panel equal column widths --- .../java/net/runelite/client/plugins/xptracker/XpInfoBox.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java index 0a0716c00e..af9c35fa53 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java @@ -29,6 +29,7 @@ package net.runelite.client.plugins.xptracker; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.GridLayout; import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.ArrayList; @@ -53,7 +54,6 @@ import net.runelite.api.Skill; import net.runelite.api.WorldType; import net.runelite.client.game.SkillIconManager; import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.DynamicGridLayout; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.SkillColor; import net.runelite.client.ui.components.MouseDragEventForwarder; @@ -190,7 +190,7 @@ class XpInfoBox extends JPanel headerPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); headerPanel.setLayout(new BorderLayout()); - statsPanel.setLayout(new DynamicGridLayout(2, 2)); + statsPanel.setLayout(new GridLayout(2, 2)); statsPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); statsPanel.setBorder(new EmptyBorder(9, 2, 9, 2)); From 25ec5a7c5c6103eb7a3714f0a1009e10d56a2704 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Wed, 17 Feb 2021 22:16:25 -0800 Subject: [PATCH 11/13] ProgressBar: Fix center label centering BorderLayout does not guarantee equal sizing of its children, so having a component centered between two components of unequal sizes will leave it centered relative to their sizes, such as the following: ``` |-----BorderLayout-------------------------------------------| ||----WEST----||------CENTER------||----------EAST----------|| ||------------||------------------||------------------------|| |------------------------------------------------------------| ``` Conversely, GridLayout uses fixed, equal-width columns for its children, ensuring the center component will always occupy the center third of the parent's dimensions. P.S. This change causes labels to truncate earlier as they do not expand beyond a third of the parent container's dimensions. Because the use case for this component is with small labels, I do not anticipate this will cause breakage. --- .../runelite/client/ui/components/ProgressBar.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/components/ProgressBar.java b/runelite-client/src/main/java/net/runelite/client/ui/components/ProgressBar.java index 3040440b4d..2347876076 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/components/ProgressBar.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/components/ProgressBar.java @@ -24,10 +24,10 @@ */ package net.runelite.client.ui.components; -import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; +import java.awt.GridLayout; import java.util.Collections; import java.util.List; import javax.swing.JLabel; @@ -53,7 +53,7 @@ public class ProgressBar extends DimmableJPanel public ProgressBar() { - setLayout(new BorderLayout()); + setLayout(new GridLayout(1, 3)); // The background color should be overridden setBackground(Color.GREEN.darker()); setForeground(Color.GREEN.brighter()); @@ -66,6 +66,7 @@ public class ProgressBar extends DimmableJPanel rightLabel.setFont(FontManager.getRunescapeSmallFont()); rightLabel.setForeground(Color.WHITE); + rightLabel.setHorizontalAlignment(SwingConstants.RIGHT); rightLabel.setBorder(new EmptyBorder(2, 0, 0, 5)); centerLabel.setFont(FontManager.getRunescapeSmallFont()); @@ -74,9 +75,9 @@ public class ProgressBar extends DimmableJPanel centerLabel.setBorder(new EmptyBorder(2, 0, 0, 0)); // Adds components to be automatically redrawn when paintComponents is called - add(leftLabel, BorderLayout.WEST); - add(centerLabel, BorderLayout.CENTER); - add(rightLabel, BorderLayout.EAST); + add(leftLabel); + add(centerLabel); + add(rightLabel); } @Override From b1dd93bb0b6a950634805f8fb2b5c62fc3cacd35 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Sat, 20 Feb 2021 19:26:02 -0800 Subject: [PATCH 12/13] item identification plugin: Add item mapping test This will ensure any ImmutableMap building errors are caught at test time rather than at runtime. --- .../ItemIdentificationTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/itemidentification/ItemIdentificationTest.java diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/itemidentification/ItemIdentificationTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/itemidentification/ItemIdentificationTest.java new file mode 100644 index 0000000000..bc04938c90 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/itemidentification/ItemIdentificationTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, Jordan Atwood + * 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.itemidentification; + +import net.runelite.api.ItemID; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class ItemIdentificationTest +{ + @Test + public void testInit() + { + assertEquals(ItemIdentification.YEW_SEED, ItemIdentification.get(ItemID.YEW_SEED)); + } +} From 8fe75748f9842e2a497da0e0bcb40a01271766df Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 1 Jun 2021 20:19:56 -0400 Subject: [PATCH 13/13] camera: add zoom slider tooltip when dragging Co-authored-by: superiorser9 --- .../main/java/net/runelite/api/ScriptID.java | 12 +++++++ .../client/plugins/camera/CameraPlugin.java | 34 ++++++++++++------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptID.java b/runelite-api/src/main/java/net/runelite/api/ScriptID.java index d106d6cab1..ba89d4190c 100644 --- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java +++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java @@ -351,4 +351,16 @@ public final class ScriptID */ @ScriptArguments(integer = 14, string = 3) public static final int CHATBOX_BUILD_LINE_WITH_CLAN = 4483; + + /** + * Drag callback for the camera zoom slider in the options side panel. + */ + @ScriptArguments(integer = 3) + public static final int ZOOM_SLIDER_ONDRAG = 833; + + /** + * Drag callback for the camera zoom slider in the settings. + */ + @ScriptArguments(integer = 6) + public static final int SETTINGS_ZOOM_SLIDER_ONDRAG = 3896; } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java index 904420080a..f650d3efba 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java @@ -367,15 +367,23 @@ public class CameraPlugin extends Plugin implements KeyListener, MouseListener @Subscribe private void onScriptPreFired(ScriptPreFired ev) { - if (ev.getScriptId() == ScriptID.SETTINGS_SLIDER_CHOOSE_ONOP) + switch (ev.getScriptId()) { - int arg = client.getIntStackSize() - 7; - int[] is = client.getIntStack(); - - if (is[arg] == SettingID.CAMERA_ZOOM) + case ScriptID.SETTINGS_SLIDER_CHOOSE_ONOP: { - addZoomTooltip(client.getScriptActiveWidget()); + int arg = client.getIntStackSize() - 7; + int[] is = client.getIntStack(); + + if (is[arg] == SettingID.CAMERA_ZOOM) + { + addZoomTooltip(client.getScriptActiveWidget()); + } + break; } + case ScriptID.ZOOM_SLIDER_ONDRAG: + case ScriptID.SETTINGS_ZOOM_SLIDER_ONDRAG: + sliderTooltip = makeSliderTooltip(); + break; } } @@ -390,12 +398,14 @@ public class CameraPlugin extends Plugin implements KeyListener, MouseListener private void addZoomTooltip(Widget w) { - w.setOnMouseRepeatListener((JavaScriptCallback) ev -> - { - int value = client.getVar(VarClientInt.CAMERA_ZOOM_RESIZABLE_VIEWPORT); - int max = config.innerLimit() ? config.INNER_ZOOM_LIMIT : CameraPlugin.DEFAULT_INNER_ZOOM_LIMIT; - sliderTooltip = new Tooltip("Camera Zoom: " + value + " / " + max); - }); + w.setOnMouseRepeatListener((JavaScriptCallback) ev -> sliderTooltip = makeSliderTooltip()); + } + + private Tooltip makeSliderTooltip() + { + int value = client.getVar(VarClientInt.CAMERA_ZOOM_RESIZABLE_VIEWPORT); + int max = config.innerLimit() ? config.INNER_ZOOM_LIMIT : CameraPlugin.DEFAULT_INNER_ZOOM_LIMIT; + return new Tooltip("Camera Zoom: " + value + " / " + max); } @Subscribe