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)); - } -}