party: remove Discord requirement

Orginally the only way to form a party was via Discord invites. This has
changed semi-recently to allow sharing party ids instead.

The Discord invite system is finnicky since it doesn't work unless
Discord is detected, doesn't work right with multiple clients, or
multiple Discords. And, discord_rpc is deprecated without a suitable
replacement.

This changes the party system to instead always require sharing party
ids instead.
This commit is contained in:
Adam
2022-05-23 22:43:30 -04:00
parent 66f6dade34
commit ff210a6b42
15 changed files with 84 additions and 471 deletions

View File

@@ -37,7 +37,6 @@ import java.time.temporal.ChronoUnit;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.inject.Named; import javax.inject.Named;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -50,11 +49,8 @@ import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.StatChanged; import net.runelite.api.events.StatChanged;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.discord.DiscordService; import net.runelite.client.discord.DiscordService;
import net.runelite.client.discord.events.DiscordJoinGame;
import net.runelite.client.discord.events.DiscordReady;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged; import net.runelite.client.events.ConfigChanged;
import net.runelite.client.events.PartyChanged;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule; import net.runelite.client.task.Schedule;
@@ -65,8 +61,7 @@ import net.runelite.client.util.LinkBrowser;
import net.runelite.client.ws.PartyMember; import net.runelite.client.ws.PartyMember;
import net.runelite.client.ws.PartyService; import net.runelite.client.ws.PartyService;
import net.runelite.client.ws.WSClient; import net.runelite.client.ws.WSClient;
import net.runelite.http.api.ws.messages.party.UserJoin; import net.runelite.discord.DiscordUser;
import net.runelite.http.api.ws.messages.party.UserPart;
import net.runelite.http.api.ws.messages.party.UserSync; import net.runelite.http.api.ws.messages.party.UserSync;
import okhttp3.Call; import okhttp3.Call;
import okhttp3.Callback; import okhttp3.Callback;
@@ -137,11 +132,6 @@ public class DiscordPlugin extends Plugin
checkForGameStateUpdate(); checkForGameStateUpdate();
checkForAreaUpdate(); checkForAreaUpdate();
if (discordService.getCurrentUser() != null)
{
partyService.setUsername(discordService.getCurrentUser().username + "#" + discordService.getCurrentUser().discriminator);
}
wsClient.registerMessage(DiscordUserInfo.class); wsClient.registerMessage(DiscordUserInfo.class);
} }
@@ -150,7 +140,6 @@ public class DiscordPlugin extends Plugin
{ {
clientToolbar.removeNavigation(discordButton); clientToolbar.removeNavigation(discordButton);
resetState(); resetState();
partyService.changeParty(null);
wsClient.unregisterMessage(DiscordUserInfo.class); wsClient.unregisterMessage(DiscordUserInfo.class);
} }
@@ -209,30 +198,9 @@ public class DiscordPlugin extends Plugin
} }
} }
@Subscribe
public void onDiscordReady(DiscordReady event)
{
partyService.setUsername(event.getUsername() + "#" + event.getDiscriminator());
}
@Subscribe
public void onDiscordJoinGame(DiscordJoinGame joinGame)
{
UUID partyId = UUID.fromString(joinGame.getJoinSecret());
partyService.changeParty(partyId);
updatePresence();
}
@Subscribe @Subscribe
public void onDiscordUserInfo(final DiscordUserInfo event) public void onDiscordUserInfo(final DiscordUserInfo event)
{ {
final PartyMember memberById = partyService.getMemberById(event.getMemberId());
if (memberById == null || memberById.getAvatar() != null)
{
return;
}
final CharMatcher matcher = CharMatcher.anyOf("abcdef0123456789"); final CharMatcher matcher = CharMatcher.anyOf("abcdef0123456789");
// animated avatars contain a_ as prefix so we need to get rid of that first to check against matcher // animated avatars contain a_ as prefix so we need to get rid of that first to check against matcher
@@ -246,13 +214,7 @@ public class DiscordPlugin extends Plugin
if (Strings.isNullOrEmpty(event.getAvatarId())) if (Strings.isNullOrEmpty(event.getAvatarId()))
{ {
final String[] split = memberById.getName().split("#", 2); int disc = Integer.parseInt(event.getDiscriminator());
if (split.length != 2)
{
return;
}
int disc = Integer.parseInt(split[1]);
int avatarId = disc % 5; int avatarId = disc % 5;
url = "https://cdn.discordapp.com/embed/avatars/" + avatarId + ".png"; url = "https://cdn.discordapp.com/embed/avatars/" + avatarId + ".png";
} }
@@ -292,7 +254,7 @@ public class DiscordPlugin extends Plugin
image = ImageIO.read(inputStream); image = ImageIO.read(inputStream);
} }
partyService.setPartyMemberAvatar(memberById.getMemberId(), image); partyService.setPartyMemberAvatar(event.getMemberId(), image);
} }
finally finally
{ {
@@ -302,12 +264,6 @@ public class DiscordPlugin extends Plugin
}); });
} }
@Subscribe
public void onUserJoin(final UserJoin event)
{
updatePresence();
}
@Subscribe @Subscribe
public void onUserSync(final UserSync event) public void onUserSync(final UserSync event)
{ {
@@ -315,30 +271,21 @@ public class DiscordPlugin extends Plugin
if (localMember != null) if (localMember != null)
{ {
if (discordService.getCurrentUser() != null) final DiscordUser discordUser = discordService.getCurrentUser();
if (discordUser != null)
{ {
final DiscordUserInfo userInfo = new DiscordUserInfo( final DiscordUserInfo userInfo = new DiscordUserInfo(
discordService.getCurrentUser().userId, discordUser.userId,
discordService.getCurrentUser().avatar); discordUser.username,
discordUser.discriminator,
discordUser.avatar
);
userInfo.setMemberId(localMember.getMemberId()); userInfo.setMemberId(localMember.getMemberId());
wsClient.send(userInfo); wsClient.send(userInfo);
} }
} }
} }
@Subscribe
public void onUserPart(final UserPart event)
{
updatePresence();
}
@Subscribe
public void onPartyChanged(final PartyChanged event)
{
updatePresence();
}
@Schedule( @Schedule(
period = 1, period = 1,
unit = ChronoUnit.MINUTES unit = ChronoUnit.MINUTES
@@ -348,11 +295,6 @@ public class DiscordPlugin extends Plugin
discordState.checkForTimeout(); discordState.checkForTimeout();
} }
private void updatePresence()
{
discordState.refresh();
}
private void resetState() private void resetState()
{ {
discordState.reset(); discordState.reset();

View File

@@ -38,8 +38,6 @@ import javax.inject.Named;
import lombok.Data; import lombok.Data;
import net.runelite.client.discord.DiscordPresence; import net.runelite.client.discord.DiscordPresence;
import net.runelite.client.discord.DiscordService; import net.runelite.client.discord.DiscordService;
import net.runelite.client.ws.PartyService;
import static net.runelite.client.ws.PartyService.PARTY_MAX;
/** /**
* This class contains data about currently active discord state. * This class contains data about currently active discord state.
@@ -57,7 +55,6 @@ class DiscordState
private final List<EventWithTime> events = new ArrayList<>(); private final List<EventWithTime> events = new ArrayList<>();
private final DiscordService discordService; private final DiscordService discordService;
private final DiscordConfig config; private final DiscordConfig config;
private final PartyService party;
private final String runeliteTitle; private final String runeliteTitle;
private final String runeliteVersion; private final String runeliteVersion;
private DiscordPresence lastPresence; private DiscordPresence lastPresence;
@@ -66,14 +63,12 @@ class DiscordState
private DiscordState( private DiscordState(
final DiscordService discordService, final DiscordService discordService,
final DiscordConfig config, final DiscordConfig config,
final PartyService party,
@Named("runelite.title") final String runeliteTitle, @Named("runelite.title") final String runeliteTitle,
@Named("runelite.version") final String runeliteVersion @Named("runelite.version") final String runeliteVersion
) )
{ {
this.discordService = discordService; this.discordService = discordService;
this.config = config; this.config = config;
this.party = party;
this.runeliteTitle = runeliteTitle; this.runeliteTitle = runeliteTitle;
this.runeliteVersion = runeliteVersion; this.runeliteVersion = runeliteVersion;
} }
@@ -88,30 +83,6 @@ class DiscordState
lastPresence = null; lastPresence = null;
} }
/**
* Force refresh discord presence
*/
void refresh()
{
if (lastPresence == null)
{
return;
}
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
.state(lastPresence.getState())
.details(lastPresence.getDetails())
.largeImageText(lastPresence.getLargeImageText())
.startTimestamp(lastPresence.getStartTimestamp())
.smallImageKey(lastPresence.getSmallImageKey())
.partyMax(lastPresence.getPartyMax());
setPresencePartyInfo(presenceBuilder);
discordService.updatePresence(presenceBuilder.build());
}
/** /**
* Trigger new discord state update. * Trigger new discord state update.
* *
@@ -197,8 +168,7 @@ class DiscordState
.state(MoreObjects.firstNonNull(state, "")) .state(MoreObjects.firstNonNull(state, ""))
.details(MoreObjects.firstNonNull(details, "")) .details(MoreObjects.firstNonNull(details, ""))
.largeImageText(runeliteTitle + " v" + versionShortHand) .largeImageText(runeliteTitle + " v" + versionShortHand)
.smallImageKey(imageKey) .smallImageKey(imageKey);
.partyMax(PARTY_MAX);
final Instant startTime; final Instant startTime;
switch (config.elapsedTimeType()) switch (config.elapsedTimeType())
@@ -225,8 +195,6 @@ class DiscordState
presenceBuilder.startTimestamp(startTime); presenceBuilder.startTimestamp(startTime);
setPresencePartyInfo(presenceBuilder);
final DiscordPresence presence = presenceBuilder.build(); final DiscordPresence presence = presenceBuilder.build();
// This is to reduce amount of RPC calls // This is to reduce amount of RPC calls
@@ -263,16 +231,4 @@ class DiscordState
updatePresenceWithLatestEvent(); updatePresenceWithLatestEvent();
} }
} }
private void setPresencePartyInfo(DiscordPresence.DiscordPresenceBuilder presenceBuilder)
{
if (party.isInParty())
{
presenceBuilder.partySize(party.getMembers().size());
// Set public party id and secret
presenceBuilder.partyId(party.getPublicPartyId().toString());
presenceBuilder.joinSecret(party.getPartyId().toString());
}
}
} }

View File

@@ -33,5 +33,7 @@ import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
class DiscordUserInfo extends PartyMemberMessage class DiscordUserInfo extends PartyMemberMessage
{ {
private final String userId; private final String userId;
private final String username;
private final String discriminator;
private final String avatarId; private final String avatarId;
} }

View File

@@ -208,7 +208,7 @@ public class DpsCounterPlugin extends Plugin
} }
// If not in a party, user local player name // If not in a party, user local player name
final String name = localMember == null ? player.getName() : localMember.getName(); final String name = localMember == null ? player.getName() : localMember.getDisplayName();
DpsMember dpsMember = members.computeIfAbsent(name, DpsMember::new); DpsMember dpsMember = members.computeIfAbsent(name, DpsMember::new);
dpsMember.addDamage(hit); dpsMember.addDamage(hit);
@@ -240,7 +240,7 @@ public class DpsCounterPlugin extends Plugin
return; return;
} }
String name = partyService.getMemberById(dpsUpdate.getMemberId()).getName(); String name = partyService.getMemberById(dpsUpdate.getMemberId()).getDisplayName();
if (name == null) if (name == null)
{ {
return; return;

View File

@@ -56,17 +56,6 @@ public interface PartyConfig extends Config
return true; return true;
} }
@ConfigItem(
keyName = "messages",
name = "Join messages",
description = "Enables members join/leave game messages",
position = 3
)
default boolean messages()
{
return true;
}
@ConfigItem( @ConfigItem(
keyName = "recolorNames", keyName = "recolorNames",
name = "Recolor names", name = "Recolor names",
@@ -85,17 +74,6 @@ public interface PartyConfig extends Config
position = 5 position = 5
) )
default boolean autoOverlay() default boolean autoOverlay()
{
return true;
}
@ConfigItem(
keyName = "includeSelf",
name = "Include yourself",
description = "Shows yourself in the panel as part of the party",
position = 6
)
default boolean includeSelf()
{ {
return false; return false;
} }

View File

@@ -40,6 +40,7 @@ import javax.swing.border.Border;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import net.runelite.client.ws.PartyMember;
import net.runelite.client.plugins.party.data.PartyData; import net.runelite.client.plugins.party.data.PartyData;
import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout; import net.runelite.client.ui.DynamicGridLayout;
@@ -61,9 +62,7 @@ class PartyMemberBox extends JPanel
private final ProgressBar hpBar = new ProgressBar(); private final ProgressBar hpBar = new ProgressBar();
private final ProgressBar prayerBar = new ProgressBar(); private final ProgressBar prayerBar = new ProgressBar();
private final JLabel topName = new JLabel(); private final JLabel name = new JLabel();
private final JLabel bottomName = new JLabel();
private final JLabel avatar = new JLabel(); private final JLabel avatar = new JLabel();
private final PartyConfig config; private final PartyConfig config;
@@ -113,14 +112,10 @@ class PartyMemberBox extends JPanel
namesPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); namesPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
namesPanel.setBorder(new EmptyBorder(2, 5, 2, 5)); namesPanel.setBorder(new EmptyBorder(2, 5, 2, 5));
topName.setFont(FontManager.getRunescapeSmallFont()); name.setFont(FontManager.getRunescapeSmallFont());
bottomName.setFont(FontManager.getRunescapeSmallFont()); name.putClientProperty("html.disable", Boolean.TRUE);
topName.putClientProperty("html.disable", Boolean.TRUE); namesPanel.add(name);
bottomName.putClientProperty("html.disable", Boolean.TRUE);
namesPanel.add(topName); // top
namesPanel.add(bottomName); // bottom
headerPanel.add(avatar, BorderLayout.WEST); headerPanel.add(avatar, BorderLayout.WEST);
headerPanel.add(namesPanel, BorderLayout.CENTER); headerPanel.add(namesPanel, BorderLayout.CENTER);
@@ -155,10 +150,12 @@ class PartyMemberBox extends JPanel
void update() void update()
{ {
final PartyMember member = memberPartyData.getMember();
// Avatar // Avatar
if (!avatarSet && memberPartyData.getMember().getAvatar() != null) if (!avatarSet && member.getAvatar() != null)
{ {
ImageIcon icon = new ImageIcon(ImageUtil.resizeImage(memberPartyData.getMember().getAvatar(), 32, 32)); ImageIcon icon = new ImageIcon(ImageUtil.resizeImage(member.getAvatar(), 32, 32));
icon.getImage().flush(); icon.getImage().flush();
avatar.setIcon(icon); avatar.setIcon(icon);
@@ -174,15 +171,12 @@ class PartyMemberBox extends JPanel
prayerBar.setMaximumValue(memberPartyData.getMaxPrayer()); prayerBar.setMaximumValue(memberPartyData.getMaxPrayer());
prayerBar.setCenterLabel(progressBarLabel(memberPartyData.getPrayer(), memberPartyData.getMaxPrayer())); prayerBar.setCenterLabel(progressBarLabel(memberPartyData.getPrayer(), memberPartyData.getMaxPrayer()));
// Update name labels // Update name label
Color playerColor = config.recolorNames() ? memberPartyData.getColor() : Color.WHITE; Color playerColor = config.recolorNames() ? memberPartyData.getColor() : Color.WHITE;
boolean isLoggedIn = !memberPartyData.getCharacterName().isEmpty(); boolean isLoggedIn = member.isLoggedIn();
topName.setForeground(playerColor); name.setForeground(isLoggedIn ? playerColor : Color.GRAY);
topName.setText(memberPartyData.getMember().getName()); name.setText(member.getDisplayName());
bottomName.setForeground(isLoggedIn ? playerColor : Color.GRAY);
bottomName.setText(isLoggedIn ? memberPartyData.getCharacterName() : "Logged out");
} }
private static String progressBarLabel(int current, int max) private static String progressBarLabel(int current, int max)

View File

@@ -57,7 +57,6 @@ class PartyPanel extends PluginPanel
private final PartyService party; private final PartyService party;
private final PartyConfig config; private final PartyConfig config;
private final Map<String, PartyRequestBox> requestBoxes = new HashMap<>();
private final Map<UUID, PartyMemberBox> memberBoxes = new HashMap<>(); private final Map<UUID, PartyMemberBox> memberBoxes = new HashMap<>();
private final JButton startButton = new JButton(); private final JButton startButton = new JButton();
@@ -68,7 +67,6 @@ class PartyPanel extends PluginPanel
private final PluginErrorPanel noPartyPanel = new PluginErrorPanel(); private final PluginErrorPanel noPartyPanel = new PluginErrorPanel();
private final PluginErrorPanel partyEmptyPanel = new PluginErrorPanel(); private final PluginErrorPanel partyEmptyPanel = new PluginErrorPanel();
private final JComponent memberBoxPanel = new DragAndDropReorderPane(); private final JComponent memberBoxPanel = new DragAndDropReorderPane();
private final JComponent requestBoxPanel = new DragAndDropReorderPane();
@Inject @Inject
PartyPanel(final PartyPlugin plugin, final PartyConfig config, final PartyService party) PartyPanel(final PartyPlugin plugin, final PartyConfig config, final PartyService party)
@@ -113,7 +111,6 @@ class PartyPanel extends PluginPanel
topPanel.add(rejoinPartyButton, c); topPanel.add(rejoinPartyButton, c);
layoutPanel.add(topPanel); layoutPanel.add(topPanel);
layoutPanel.add(requestBoxPanel);
layoutPanel.add(memberBoxPanel); layoutPanel.add(memberBoxPanel);
startButton.setText(party.isInParty() ? BTN_LEAVE_TEXT : BTN_CREATE_TEXT); startButton.setText(party.isInParty() ? BTN_LEAVE_TEXT : BTN_CREATE_TEXT);
@@ -280,30 +277,4 @@ class PartyPanel extends PluginPanel
{ {
memberBoxes.forEach((key, value) -> value.update()); memberBoxes.forEach((key, value) -> value.update());
} }
void addRequest(String userId, String userName)
{
PartyRequestBox partyRequestBox = new PartyRequestBox(plugin, requestBoxPanel, userId, userName);
requestBoxes.put(userId, partyRequestBox);
requestBoxPanel.add(partyRequestBox);
requestBoxPanel.revalidate();
}
void removeAllRequests()
{
requestBoxes.forEach((key, value) -> requestBoxPanel.remove(value));
requestBoxPanel.revalidate();
requestBoxes.clear();
}
void removeRequest(String userId)
{
final PartyRequestBox requestBox = requestBoxes.remove(userId);
if (requestBox != null)
{
requestBoxPanel.remove(requestBox);
requestBoxPanel.revalidate();
}
}
} }

View File

@@ -58,13 +58,9 @@ import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick; import net.runelite.api.events.GameTick;
import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.MenuOptionClicked;
import net.runelite.client.callback.ClientThread; import net.runelite.client.callback.ClientThread;
import net.runelite.client.chat.ChatColorType;
import net.runelite.client.chat.ChatMessageBuilder;
import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.chat.QueuedMessage; import net.runelite.client.chat.QueuedMessage;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.discord.DiscordService;
import net.runelite.client.discord.events.DiscordJoinRequest;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged; import net.runelite.client.events.ConfigChanged;
import net.runelite.client.events.OverlayMenuClicked; import net.runelite.client.events.OverlayMenuClicked;
@@ -138,9 +134,6 @@ public class PartyPlugin extends Plugin
@Inject @Inject
private ClientToolbar clientToolbar; private ClientToolbar clientToolbar;
@Inject
private DiscordService discordService;
@Inject @Inject
@Named("developerMode") @Named("developerMode")
boolean developerMode; boolean developerMode;
@@ -157,7 +150,6 @@ public class PartyPlugin extends Plugin
private int lastHp, lastPray; private int lastHp, lastPray;
private String lastCharacterName = ""; private String lastCharacterName = "";
private WorldPoint lastLocation; private WorldPoint lastLocation;
private boolean sendAlert;
@Override @Override
public void configure(Binder binder) public void configure(Binder binder)
@@ -207,7 +199,6 @@ public class PartyPlugin extends Plugin
wsClient.unregisterMessage(TilePing.class); wsClient.unregisterMessage(TilePing.class);
wsClient.unregisterMessage(LocationUpdate.class); wsClient.unregisterMessage(LocationUpdate.class);
wsClient.unregisterMessage(CharacterNameUpdate.class); wsClient.unregisterMessage(CharacterNameUpdate.class);
sendAlert = false;
lastLocation = null; lastLocation = null;
} }
@@ -231,21 +222,6 @@ public class PartyPlugin extends Plugin
void leaveParty() void leaveParty()
{ {
party.changeParty(null); party.changeParty(null);
if (!config.messages())
{
return;
}
final String leaveMessage = new ChatMessageBuilder()
.append(ChatColorType.HIGHLIGHT)
.append("You have left the party.")
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
.runeLiteFormattedMessage(leaveMessage)
.build());
} }
@Subscribe @Subscribe
@@ -253,22 +229,6 @@ public class PartyPlugin extends Plugin
{ {
if (event.getGroup().equals(PartyConfig.GROUP)) if (event.getGroup().equals(PartyConfig.GROUP))
{ {
final PartyMember localMember = party.getLocalMember();
if (localMember != null)
{
if (config.includeSelf())
{
final PartyData partyData = getPartyData(localMember.getMemberId());
assert partyData != null;
SwingUtilities.invokeLater(() -> panel.addMember(partyData));
}
else
{
SwingUtilities.invokeLater(() -> panel.removeMember(localMember.getMemberId()));
}
}
// rebuild the panel in the event the "Recolor names" option changes // rebuild the panel in the event the "Recolor names" option changes
SwingUtilities.invokeLater(panel::updateAll); SwingUtilities.invokeLater(panel::updateAll);
} }
@@ -314,35 +274,12 @@ public class PartyPlugin extends Plugin
wsClient.send(tilePing); wsClient.send(tilePing);
} }
@Subscribe
public void onDiscordJoinRequest(DiscordJoinRequest request)
{
final String requestMessage = new ChatMessageBuilder()
.append(ChatColorType.HIGHLIGHT)
.append("New join request received. Check your Party panel.")
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
.runeLiteFormattedMessage(requestMessage)
.build());
String userName = request.getUsername() + "#" + request.getDiscriminator();
SwingUtilities.invokeLater(() -> panel.addRequest(request.getUserId(), userName));
}
@Subscribe @Subscribe
public void onGameStateChanged(GameStateChanged event) public void onGameStateChanged(GameStateChanged event)
{ {
checkStateChanged(false); checkStateChanged(false);
} }
public void replyToRequest(String userId, int reply)
{
discordService.respondToRequest(userId, reply);
panel.removeRequest(userId);
}
@Subscribe @Subscribe
public void onTilePing(TilePing event) public void onTilePing(TilePing event)
{ {
@@ -400,12 +337,6 @@ public class PartyPlugin extends Plugin
@Subscribe @Subscribe
public void onGameTick(final GameTick event) public void onGameTick(final GameTick event)
{ {
if (sendAlert && client.getGameState() == GameState.LOGGED_IN)
{
sendAlert = false;
sendInstructionMessage();
}
checkStateChanged(false); checkStateChanged(false);
} }
@@ -430,11 +361,22 @@ public class PartyPlugin extends Plugin
return; return;
} }
String name = event.getCharacterName(); final String name = Text.removeTags(Text.toJagexName(event.getCharacterName()));
name = Text.removeTags(Text.toJagexName(name)); final PartyMember member = partyData.getMember();
partyData.setCharacterName(name); if (!name.isEmpty())
SwingUtilities.invokeLater(() -> panel.updateMember(partyData.getMember().getMemberId())); {
member.setDisplayName(name);
member.setLoggedIn(true);
partyData.setColor(ColorUtil.fromObject(name));
}
else
{
member.setLoggedIn(false);
partyData.setColor(Color.WHITE);
}
SwingUtilities.invokeLater(() -> panel.updateMember(member.getMemberId()));
} }
@Subscribe @Subscribe
@@ -477,30 +419,8 @@ public class PartyPlugin extends Plugin
@Subscribe @Subscribe
public void onUserJoin(final UserJoin event) public void onUserJoin(final UserJoin event)
{ {
final PartyData partyData = getPartyData(event.getMemberId()); // this has a side effect of creating the party data
getPartyData(event.getMemberId());
if (partyData == null || !config.messages())
{
return;
}
final String joinMessage = new ChatMessageBuilder()
.append(ChatColorType.HIGHLIGHT)
.append(partyData.getMember().getName())
.append(" has joined the party!")
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
.runeLiteFormattedMessage(joinMessage)
.build());
final PartyMember localMember = party.getLocalMember();
if (localMember != null && partyData.getMember().getMemberId().equals(localMember.getMemberId()))
{
sendAlert = true;
}
} }
@Subscribe @Subscribe
@@ -557,20 +477,6 @@ public class PartyPlugin extends Plugin
if (removed != null) if (removed != null)
{ {
if (config.messages())
{
final String joinMessage = new ChatMessageBuilder()
.append(ChatColorType.HIGHLIGHT)
.append(removed.getMember().getName())
.append(" has left the party!")
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
.runeLiteFormattedMessage(joinMessage)
.build());
}
worldMapManager.remove(removed.getWorldMapPoint()); worldMapManager.remove(removed.getWorldMapPoint());
SwingUtilities.invokeLater(() -> panel.removeMember(event.getMemberId())); SwingUtilities.invokeLater(() -> panel.removeMember(event.getMemberId()));
@@ -590,11 +496,7 @@ public class PartyPlugin extends Plugin
config.setPreviousPartyId(String.valueOf(event.getPartyId())); config.setPreviousPartyId(String.valueOf(event.getPartyId()));
} }
SwingUtilities.invokeLater(() -> SwingUtilities.invokeLater(panel::removeAllMembers);
{
panel.removeAllMembers();
panel.removeAllRequests();
});
} }
@Subscribe @Subscribe
@@ -610,7 +512,7 @@ public class PartyPlugin extends Plugin
chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Local ID " + party.getLocalMember().getMemberId()).build()); chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Local ID " + party.getLocalMember().getMemberId()).build());
for (PartyMember partyMember : party.getMembers()) for (PartyMember partyMember : party.getMembers())
{ {
chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value(" " + partyMember.getName() + " " + partyMember.getMemberId()).build()); chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Member " + partyMember.getName() + " " + partyMember.getDisplayName() + " " + partyMember.getMemberId()).build());
} }
} }
@@ -636,7 +538,6 @@ public class PartyPlugin extends Plugin
return partyDataMap.computeIfAbsent(uuid, (u) -> return partyDataMap.computeIfAbsent(uuid, (u) ->
{ {
final WorldMapPoint worldMapPoint = new PartyWorldMapPoint(new WorldPoint(0, 0, 0), memberById); final WorldMapPoint worldMapPoint = new PartyWorldMapPoint(new WorldPoint(0, 0, 0), memberById);
worldMapPoint.setTooltip(memberById.getName());
// When first joining a party, other members can join before getting a join for self // When first joining a party, other members can join before getting a join for self
PartyMember partyMember = party.getLocalMember(); PartyMember partyMember = party.getLocalMember();
@@ -648,32 +549,11 @@ public class PartyPlugin extends Plugin
worldMapManager.add(worldMapPoint); worldMapManager.add(worldMapPoint);
} }
PartyData partyData = new PartyData(memberById, worldMapPoint, ColorUtil.fromObject(memberById.getName())); PartyData partyData = new PartyData(memberById, worldMapPoint);
partyData.setShowOverlay(config.autoOverlay()); partyData.setShowOverlay(config.autoOverlay());
if (config.includeSelf() || !isSelf)
{
SwingUtilities.invokeLater(() -> panel.addMember(partyData)); SwingUtilities.invokeLater(() -> panel.addMember(partyData));
}
else
{
SwingUtilities.invokeLater(panel::updateParty);
}
return partyData; return partyData;
}); });
} }
private void sendInstructionMessage()
{
final String helpMessage = new ChatMessageBuilder()
.append(ChatColorType.HIGHLIGHT)
.append("To leave the party, click \"Leave party\" on the party panel.")
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
.runeLiteFormattedMessage(helpMessage)
.build());
}
} }

View File

@@ -1,111 +0,0 @@
/*
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
* 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.party;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.MouseDragEventForwarder;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.SwingUtil;
import net.runelite.discord.DiscordRPC;
class PartyRequestBox extends JPanel
{
private static final ImageIcon CONFIRM_ICON = new ImageIcon(ImageUtil.loadImageResource(PartyPlugin.class, "confirm_icon.png"));
private static final ImageIcon CONFIRM_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.bufferedImageFromImage(CONFIRM_ICON.getImage()), 0.54f));
private static final ImageIcon CANCEL_ICON = new ImageIcon(ImageUtil.loadImageResource(PartyPlugin.class, "cancel_icon.png"));
private static final ImageIcon CANCEL_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.bufferedImageFromImage(CANCEL_ICON.getImage()), 0.6f));
PartyRequestBox(final PartyPlugin plugin, final JComponent panel, String userId, String userName)
{
setLayout(new BorderLayout());
setBorder(new EmptyBorder(5, 0, 0, 0));
/* The box's wrapping container */
final JPanel container = new JPanel();
container.setLayout(new BorderLayout());
container.setBackground(ColorScheme.DARKER_GRAY_COLOR);
container.setBorder(new EmptyBorder(5, 5, 5, 5));
JPanel namesPanel = new JPanel();
namesPanel.setLayout(new DynamicGridLayout(2, 1));
namesPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
namesPanel.setBorder(new EmptyBorder(2, 5, 2, 5));
JShadowedLabel nameLabel = new JShadowedLabel();
nameLabel.setFont(FontManager.getRunescapeSmallFont());
nameLabel.setForeground(Color.WHITE);
nameLabel.setText(userName);
JShadowedLabel messageLabel = new JShadowedLabel();
messageLabel.setFont(FontManager.getRunescapeSmallFont());
messageLabel.setForeground(Color.WHITE);
messageLabel.setText("Wants to join your party!");
namesPanel.add(nameLabel);
namesPanel.add(messageLabel);
JPanel actionsContainer = new JPanel(new GridLayout(1, 2, 8, 0));
actionsContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
JButton confirmButton = new JButton(CONFIRM_ICON);
SwingUtil.removeButtonDecorations(confirmButton);
confirmButton.setToolTipText("Invite");
confirmButton.setRolloverIcon(CONFIRM_HOVER_ICON);
confirmButton.addActionListener(e -> plugin.replyToRequest(userId, DiscordRPC.DISCORD_REPLY_YES));
confirmButton.setPreferredSize(new Dimension(18, 18));
JButton cancelButton = new JButton(CANCEL_ICON);
SwingUtil.removeButtonDecorations(cancelButton);
cancelButton.setToolTipText("Reject");
cancelButton.setRolloverIcon(CANCEL_HOVER_ICON);
cancelButton.addActionListener(e -> plugin.replyToRequest(userId, DiscordRPC.DISCORD_REPLY_NO));
cancelButton.setPreferredSize(new Dimension(18, 18));
actionsContainer.add(confirmButton);
actionsContainer.add(cancelButton);
container.add(namesPanel, BorderLayout.WEST);
container.add(actionsContainer, BorderLayout.EAST);
// forward mouse drag events to parent panel for drag and drop reordering
MouseDragEventForwarder mouseDragEventForwarder = new MouseDragEventForwarder(panel);
container.addMouseListener(mouseDragEventForwarder);
container.addMouseMotionListener(mouseDragEventForwarder);
add(container, BorderLayout.NORTH);
}
}

View File

@@ -41,7 +41,7 @@ import net.runelite.client.ui.overlay.components.ComponentConstants;
import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.components.ProgressBarComponent; import net.runelite.client.ui.overlay.components.ProgressBarComponent;
import net.runelite.client.ui.overlay.components.TitleComponent; import net.runelite.client.ui.overlay.components.TitleComponent;
import net.runelite.client.ws.PartyService; import net.runelite.client.ws.PartyMember;
public class PartyStatsOverlay extends OverlayPanel public class PartyStatsOverlay extends OverlayPanel
{ {
@@ -51,15 +51,13 @@ public class PartyStatsOverlay extends OverlayPanel
private static final Color PRAY_BG = Color.black; private static final Color PRAY_BG = Color.black;
private final PartyPlugin plugin; private final PartyPlugin plugin;
private final PartyService party;
private final PartyConfig config; private final PartyConfig config;
@Inject @Inject
private PartyStatsOverlay(final PartyPlugin plugin, final PartyService party, final PartyConfig config) private PartyStatsOverlay(final PartyPlugin plugin, final PartyConfig config)
{ {
super(plugin); super(plugin);
this.plugin = plugin; this.plugin = plugin;
this.party = party;
this.config = config; this.config = config;
panelComponent.setBorder(new Rectangle()); panelComponent.setBorder(new Rectangle());
panelComponent.setGap(new Point(0, ComponentConstants.STANDARD_BORDER / 2)); panelComponent.setGap(new Point(0, ComponentConstants.STANDARD_BORDER / 2));
@@ -81,9 +79,9 @@ public class PartyStatsOverlay extends OverlayPanel
{ {
partyDataMap.forEach((k, v) -> partyDataMap.forEach((k, v) ->
{ {
boolean isSelf = party.getLocalMember() != null && party.getLocalMember().getMemberId().equals(k); final PartyMember member = v.getMember();
if (!v.isShowOverlay() || (!config.includeSelf() && isSelf)) if (!v.isShowOverlay())
{ {
return; return;
} }
@@ -92,7 +90,7 @@ public class PartyStatsOverlay extends OverlayPanel
panel.getChildren().clear(); panel.getChildren().clear();
final TitleComponent name = TitleComponent.builder() final TitleComponent name = TitleComponent.builder()
.text(v.getCharacterName().isEmpty() ? v.getMember().getName() : v.getCharacterName()) .text(member.getDisplayName())
.color(config.recolorNames() ? v.getColor() : Color.WHITE) .color(config.recolorNames() ? v.getColor() : Color.WHITE)
.build(); .build();

View File

@@ -45,12 +45,23 @@ class PartyWorldMapPoint extends WorldMapPoint
this.member = member; this.member = member;
this.setSnapToEdge(true); this.setSnapToEdge(true);
this.setJumpOnClick(true); this.setJumpOnClick(true);
this.setName(member.getName());
this.setImagePoint(new Point( this.setImagePoint(new Point(
ARROW.getWidth() / 2, ARROW.getWidth() / 2,
ARROW.getHeight())); ARROW.getHeight()));
} }
@Override
public String getName()
{
return member.getDisplayName();
}
@Override
public String getTooltip()
{
return member.getDisplayName();
}
@Override @Override
public BufferedImage getImage() public BufferedImage getImage()
{ {

View File

@@ -41,12 +41,11 @@ public class PartyData
private final PartyMember member; private final PartyMember member;
private final WorldMapPoint worldMapPoint; private final WorldMapPoint worldMapPoint;
private final PanelComponent panel = new PanelComponent(); private final PanelComponent panel = new PanelComponent();
private final Color color; private Color color = Color.WHITE;
private int hitpoints; private int hitpoints;
private int maxHitpoints; private int maxHitpoints;
private int prayer; private int prayer;
private int maxPrayer; private int maxPrayer;
private String characterName = "";
private boolean showOverlay; private boolean showOverlay;
} }

View File

@@ -315,7 +315,7 @@ public class SpecialCounterPlugin extends Plugin
return; return;
} }
String name = party.getMemberById(event.getMemberId()).getName(); String name = party.getMemberById(event.getMemberId()).getDisplayName();
if (name == null) if (name == null)
{ {
return; return;

View File

@@ -33,5 +33,7 @@ public class PartyMember
{ {
private final UUID memberId; private final UUID memberId;
private final String name; private final String name;
private String displayName = "<unknown>";
private boolean loggedIn;
private BufferedImage avatar; private BufferedImage avatar;
} }

View File

@@ -25,18 +25,16 @@
*/ */
package net.runelite.client.ws; package net.runelite.client.ws;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType; import net.runelite.api.ChatMessageType;
import net.runelite.client.account.AccountSession; import net.runelite.client.account.AccountSession;
@@ -46,8 +44,8 @@ import net.runelite.client.chat.QueuedMessage;
import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.PartyChanged; import net.runelite.client.events.PartyChanged;
import net.runelite.client.util.Text;
import net.runelite.client.events.PartyMemberAvatar; import net.runelite.client.events.PartyMemberAvatar;
import net.runelite.client.util.Text;
import static net.runelite.client.util.Text.JAGEX_PRINTABLE_CHAR_MATCHER; import static net.runelite.client.util.Text.JAGEX_PRINTABLE_CHAR_MATCHER;
import net.runelite.http.api.ws.messages.party.Join; import net.runelite.http.api.ws.messages.party.Join;
import net.runelite.http.api.ws.messages.party.Part; import net.runelite.http.api.ws.messages.party.Part;
@@ -60,9 +58,9 @@ import net.runelite.http.api.ws.messages.party.UserSync;
@Singleton @Singleton
public class PartyService public class PartyService
{ {
public static final int PARTY_MAX = 15;
private static final int MAX_MESSAGE_LEN = 150; private static final int MAX_MESSAGE_LEN = 150;
private static final int MAX_USERNAME_LEN = 32; // same as Discord private static final int MAX_USERNAME_LEN = 32; // same as Discord
private static final String USERNAME = "rluser-" + new Random().nextInt(Integer.MAX_VALUE);
private final WSClient wsClient; private final WSClient wsClient;
private final SessionManager sessionManager; private final SessionManager sessionManager;
@@ -73,15 +71,9 @@ public class PartyService
@Getter @Getter
private UUID localPartyId = UUID.randomUUID(); private UUID localPartyId = UUID.randomUUID();
@Getter
private UUID publicPartyId; // public party id, for advertising on discord, derived from the secret
@Getter @Getter
private UUID partyId; // secret party id private UUID partyId; // secret party id
@Setter
private String username;
@Inject @Inject
private PartyService(final WSClient wsClient, final SessionManager sessionManager, final EventBus eventBus, final ChatMessageManager chat) private PartyService(final WSClient wsClient, final SessionManager sessionManager, final EventBus eventBus, final ChatMessageManager chat)
{ {
@@ -94,12 +86,6 @@ public class PartyService
public void changeParty(@Nullable UUID newParty) public void changeParty(@Nullable UUID newParty)
{ {
if (username == null)
{
log.warn("Tried to join a party with no username");
return;
}
if (wsClient.sessionExists()) if (wsClient.sessionExists())
{ {
wsClient.send(new Part()); wsClient.send(new Part());
@@ -108,8 +94,6 @@ public class PartyService
log.debug("Party change to {}", newParty); log.debug("Party change to {}", newParty);
members.clear(); members.clear();
partyId = newParty; partyId = newParty;
// The public party ID needs to be consistent across party members, but not a secret
publicPartyId = newParty != null ? UUID.nameUUIDFromBytes(Hashing.sha256().hashString(newParty.toString(), Charsets.UTF_8).asBytes()) : null;
if (partyId == null) if (partyId == null)
{ {
@@ -135,7 +119,7 @@ public class PartyService
} }
eventBus.post(new PartyChanged(partyId)); eventBus.post(new PartyChanged(partyId));
wsClient.send(new Join(partyId, username)); wsClient.send(new Join(partyId, USERNAME));
} }
@Subscribe(priority = 1) // run prior to plugins so that the member is joined by the time the plugins see it. @Subscribe(priority = 1) // run prior to plugins so that the member is joined by the time the plugins see it.
@@ -171,11 +155,18 @@ public class PartyService
@Subscribe @Subscribe
public void onPartyChatMessage(final PartyChatMessage message) public void onPartyChatMessage(final PartyChatMessage message)
{ {
final PartyMember member = getMemberById(message.getMemberId());
if (member == null || !member.isLoggedIn())
{
log.debug("Dropping party chat from non logged-in member");
return;
}
// Remove non-printable characters, and <img> tags from message // Remove non-printable characters, and <img> tags from message
String sentMesage = JAGEX_PRINTABLE_CHAR_MATCHER.retainFrom(message.getValue()) String sentMesage = JAGEX_PRINTABLE_CHAR_MATCHER.retainFrom(message.getValue())
.replaceAll("<img=.+>", ""); .replaceAll("<img=.+>", "");
// Cap the mesage length // Cap the message length
if (sentMesage.length() > MAX_MESSAGE_LEN) if (sentMesage.length() > MAX_MESSAGE_LEN)
{ {
sentMesage = sentMesage.substring(0, MAX_MESSAGE_LEN); sentMesage = sentMesage.substring(0, MAX_MESSAGE_LEN);
@@ -184,14 +175,14 @@ public class PartyService
chat.queue(QueuedMessage.builder() chat.queue(QueuedMessage.builder()
.type(ChatMessageType.FRIENDSCHAT) .type(ChatMessageType.FRIENDSCHAT)
.sender("Party") .sender("Party")
.name(getMemberById(message.getMemberId()).getName()) .name(member.getDisplayName())
.runeLiteFormattedMessage(sentMesage) .runeLiteFormattedMessage(sentMesage)
.build()); .build());
} }
public PartyMember getLocalMember() public PartyMember getLocalMember()
{ {
return getMemberByName(username); return getMemberByName(USERNAME);
} }
public PartyMember getMemberById(final UUID id) public PartyMember getMemberById(final UUID id)