party: use passphrases for party ids

These are easier to type and share than uuids.
This commit is contained in:
Adam
2022-05-25 20:13:37 -04:00
parent ff210a6b42
commit eb0cbd5f49
4 changed files with 105 additions and 47 deletions

View File

@@ -30,5 +30,6 @@ import lombok.Value;
@Value @Value
public class PartyChanged public class PartyChanged
{ {
private final String passphrase;
private final UUID partyId; private final UUID partyId;
} }

View File

@@ -41,6 +41,7 @@ import javax.swing.JComponent;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import net.runelite.client.callback.ClientThread;
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.PluginPanel; import net.runelite.client.ui.PluginPanel;
@@ -51,7 +52,7 @@ import net.runelite.client.ws.PartyService;
class PartyPanel extends PluginPanel class PartyPanel extends PluginPanel
{ {
private static final String BTN_CREATE_TEXT = "Create party"; private static final String BTN_CREATE_TEXT = "Create party";
private static final String BTN_LEAVE_TEXT = "Leave party"; private static final String BTN_LEAVE_TEXT = "Leave";
private final PartyPlugin plugin; private final PartyPlugin plugin;
private final PartyService party; private final PartyService party;
@@ -69,7 +70,7 @@ class PartyPanel extends PluginPanel
private final JComponent memberBoxPanel = new DragAndDropReorderPane(); private final JComponent memberBoxPanel = new DragAndDropReorderPane();
@Inject @Inject
PartyPanel(final PartyPlugin plugin, final PartyConfig config, final PartyService party) PartyPanel(final ClientThread clientThread, final PartyPlugin plugin, final PartyConfig config, final PartyService party)
{ {
this.plugin = plugin; this.plugin = plugin;
this.party = party; this.party = party;
@@ -122,7 +123,7 @@ class PartyPanel extends PluginPanel
rejoinPartyButton.setText("Join previous party"); rejoinPartyButton.setText("Join previous party");
rejoinPartyButton.setFocusable(false); rejoinPartyButton.setFocusable(false);
copyPartyIdButton.setText("Copy party id"); copyPartyIdButton.setText("Copy passphrase");
copyPartyIdButton.setFocusable(false); copyPartyIdButton.setFocusable(false);
startButton.addActionListener(e -> startButton.addActionListener(e ->
@@ -143,7 +144,7 @@ class PartyPanel extends PluginPanel
else else
{ {
// Create party // Create party
party.changeParty(party.getLocalPartyId()); clientThread.invokeLater(() -> party.changeParty(party.generatePasspharse()));
} }
}); });
@@ -153,8 +154,8 @@ class PartyPanel extends PluginPanel
{ {
String s = (String) JOptionPane.showInputDialog( String s = (String) JOptionPane.showInputDialog(
joinPartyButton, joinPartyButton,
"Please enter the party id:", "Please enter the party passphrase:",
"Party Id", "Party Passphrase",
JOptionPane.PLAIN_MESSAGE, JOptionPane.PLAIN_MESSAGE,
null, null,
null, null,
@@ -165,15 +166,7 @@ class PartyPanel extends PluginPanel
return; return;
} }
try party.changeParty(s);
{
party.changeParty(UUID.fromString(s));
}
catch (IllegalArgumentException ex)
{
JOptionPane.showMessageDialog(joinPartyButton, "You have entered an invalid party id.", "Invalid Party Id",
JOptionPane.ERROR_MESSAGE);
}
} }
}); });
@@ -181,17 +174,7 @@ class PartyPanel extends PluginPanel
{ {
if (!party.isInParty()) if (!party.isInParty())
{ {
try party.changeParty(config.previousPartyId());
{
party.changeParty(UUID.fromString(config.previousPartyId()));
}
catch (IllegalArgumentException ex)
{
JOptionPane.showMessageDialog(rejoinPartyButton,
"Failed to join your previous party, create a new party or join a new one.",
"Failed to Join Party",
JOptionPane.ERROR_MESSAGE);
}
} }
}); });
@@ -200,12 +183,11 @@ class PartyPanel extends PluginPanel
if (party.isInParty()) if (party.isInParty())
{ {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(String.valueOf(party.getPartyId())), null); clipboard.setContents(new StringSelection(party.getPartyPassphrase()), null);
} }
}); });
noPartyPanel.setContent("Not in a party", "Create a party to begin."); noPartyPanel.setContent("Not in a party", "Create a party to begin.");
partyEmptyPanel.setContent("Party created", "You can now invite friends!");
updateParty(); updateParty();
} }
@@ -226,6 +208,8 @@ class PartyPanel extends PluginPanel
} }
else if (plugin.getPartyDataMap().size() <= 1) else if (plugin.getPartyDataMap().size() <= 1)
{ {
partyEmptyPanel.setContent("Party created", "You can now invite friends!<br/>" +
"Your party passphrase is: " + party.getPartyPassphrase() + ".");
add(partyEmptyPanel); add(partyEmptyPanel);
} }
} }

View File

@@ -493,7 +493,7 @@ public class PartyPlugin extends Plugin
if (event.getPartyId() != null) if (event.getPartyId() != null)
{ {
config.setPreviousPartyId(String.valueOf(event.getPartyId())); config.setPreviousPartyId(event.getPassphrase());
} }
SwingUtilities.invokeLater(panel::removeAllMembers); SwingUtilities.invokeLater(panel::removeAllMembers);
@@ -507,8 +507,7 @@ public class PartyPlugin extends Plugin
return; return;
} }
chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Party " + party.getPartyId()).build()); chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Party " + party.getPartyPassphrase() + " ID " + party.getPartyId()).build());
chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Local Party " + party.getLocalPartyId()).build());
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())
{ {

View File

@@ -25,10 +25,14 @@
*/ */
package net.runelite.client.ws; package net.runelite.client.ws;
import com.google.common.base.CharMatcher;
import com.google.common.hash.Hashing;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.nio.charset.StandardCharsets;
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.Locale;
import java.util.Random; import java.util.Random;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -37,6 +41,9 @@ import javax.inject.Singleton;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType; import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.ItemComposition;
import net.runelite.client.account.AccountSession; import net.runelite.client.account.AccountSession;
import net.runelite.client.account.SessionManager; import net.runelite.client.account.SessionManager;
import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.ChatMessageManager;
@@ -61,22 +68,24 @@ public class PartyService
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 static final String USERNAME = "rluser-" + new Random().nextInt(Integer.MAX_VALUE);
private static final String ALPHABET = "bcdfghjklmnpqrstvwxyz";
private final Client client;
private final WSClient wsClient; private final WSClient wsClient;
private final SessionManager sessionManager; private final SessionManager sessionManager;
private final EventBus eventBus; private final EventBus eventBus;
private final ChatMessageManager chat; private final ChatMessageManager chat;
private final List<PartyMember> members = new ArrayList<>(); private final List<PartyMember> members = new ArrayList<>();
@Getter
private UUID localPartyId = UUID.randomUUID();
@Getter @Getter
private UUID partyId; // secret party id private UUID partyId; // secret party id
@Getter
private String partyPassphrase;
@Inject @Inject
private PartyService(final WSClient wsClient, final SessionManager sessionManager, final EventBus eventBus, final ChatMessageManager chat) private PartyService(final Client client, final WSClient wsClient, final SessionManager sessionManager, final EventBus eventBus, final ChatMessageManager chat)
{ {
this.client = client;
this.wsClient = wsClient; this.wsClient = wsClient;
this.sessionManager = sessionManager; this.sessionManager = sessionManager;
this.eventBus = eventBus; this.eventBus = eventBus;
@@ -84,28 +93,89 @@ public class PartyService
eventBus.register(this); eventBus.register(this);
} }
public void changeParty(@Nullable UUID newParty) public String generatePasspharse()
{
assert client.isClientThread();
Random r = new Random();
StringBuilder sb = new StringBuilder();
if (client.getGameState().getState() >= GameState.LOGIN_SCREEN.getState())
{
int len = 0;
final CharMatcher matcher = CharMatcher.javaLetter();
do
{
final int itemId = r.nextInt(client.getItemCount());
final ItemComposition def = client.getItemDefinition(itemId);
final String name = def.getName();
if (name == null || name.isEmpty() || name.equals("null"))
{
continue;
}
final String[] split = name.split(" ");
final String token = split[r.nextInt(split.length)];
if (!matcher.matchesAllOf(token) || token.length() <= 2)
{
continue;
}
if (sb.length() > 0)
{
sb.append('-');
}
sb.append(token.toLowerCase(Locale.US));
++len;
}
while (len < 4);
}
else
{
int len = 0;
do
{
if (sb.length() > 0)
{
sb.append('-');
}
for (int i = 0; i < 5; ++i)
{
sb.append(ALPHABET.charAt(r.nextInt(ALPHABET.length())));
}
++len;
}
while (len < 4);
}
String partyPassphrase = sb.toString();
log.debug("Generated party passpharse {}", partyPassphrase);
return partyPassphrase;
}
public void changeParty(@Nullable String passphrase)
{ {
if (wsClient.sessionExists()) if (wsClient.sessionExists())
{ {
wsClient.send(new Part()); wsClient.send(new Part());
} }
log.debug("Party change to {}", newParty); UUID id = passphrase != null ? passphraseToId(passphrase) : null;
log.debug("Party change to {} (id {})", passphrase, id);
members.clear(); members.clear();
partyId = newParty; partyId = id;
partyPassphrase = passphrase;
if (partyId == null) if (partyId == null)
{ {
localPartyId = UUID.randomUUID(); // cycle local party id so that a new party is created now
// close the websocket if the session id isn't for an account // close the websocket if the session id isn't for an account
if (sessionManager.getAccountSession() == null) if (sessionManager.getAccountSession() == null)
{ {
wsClient.changeSession(null); wsClient.changeSession(null);
} }
eventBus.post(new PartyChanged(partyId)); eventBus.post(new PartyChanged(partyPassphrase, partyId));
return; return;
} }
@@ -118,7 +188,7 @@ public class PartyService
wsClient.changeSession(uuid); wsClient.changeSession(uuid);
} }
eventBus.post(new PartyChanged(partyId)); eventBus.post(new PartyChanged(partyPassphrase, partyId));
wsClient.send(new Join(partyId, USERNAME)); wsClient.send(new Join(partyId, USERNAME));
} }
@@ -221,11 +291,6 @@ public class PartyService
return partyId != null; return partyId != null;
} }
public boolean isPartyOwner()
{
return localPartyId.equals(partyId);
}
public void setPartyMemberAvatar(UUID memberID, BufferedImage image) public void setPartyMemberAvatar(UUID memberID, BufferedImage image)
{ {
final PartyMember memberById = getMemberById(memberID); final PartyMember memberById = getMemberById(memberID);
@@ -246,4 +311,13 @@ public class PartyService
} }
return s; return s;
} }
private static UUID passphraseToId(String passphrase)
{
return UUID.nameUUIDFromBytes(
Hashing.sha256().hashBytes(
passphrase.getBytes(StandardCharsets.UTF_8)
).asBytes()
);
}
} }