party: switch to protobuf

This switches party and member ids to also be 64bit ints. This uses
considerably less data and cpu due to being able to use binary websocket
frames, and the server can avoid json deserialization completely.

Also hold member ids instead of party member references in the party
plugin, since the members can be reset if connection is lost, causing it
hold refs to old party members.

Encode location update points into a single int, since the updates are
so frequent.
This commit is contained in:
Adam
2022-06-18 18:38:57 -04:00
parent d89a64505b
commit 2c8cbfdc8c
29 changed files with 3087 additions and 281 deletions

View File

@@ -143,6 +143,11 @@
<version>23.0.0</version> <version>23.0.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-javalite</artifactId>
<version>3.21.1</version>
</dependency>
<!-- JOGL --> <!-- JOGL -->
<dependency> <dependency>
@@ -488,6 +493,7 @@
<analysisCache>true</analysisCache> <analysisCache>true</analysisCache>
<excludes> <excludes>
<exclude>**/RuntimeTypeAdapterFactory.java</exclude> <exclude>**/RuntimeTypeAdapterFactory.java</exclude>
<exclude>net/runelite/client/party/Party.java</exclude>
</excludes> </excludes>
</configuration> </configuration>
<executions> <executions>

View File

@@ -24,12 +24,17 @@
*/ */
package net.runelite.client.events; package net.runelite.client.events;
import java.util.UUID;
import lombok.Value; import lombok.Value;
@Value @Value
public class PartyChanged public class PartyChanged
{ {
/**
* The passphrase used to derive the party id
*/
private final String passphrase; private final String passphrase;
private final UUID partyId; /**
* The new party id, or null if no party
*/
private final Long partyId;
} }

View File

@@ -25,12 +25,11 @@
package net.runelite.client.events; package net.runelite.client.events;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.UUID;
import lombok.Value; import lombok.Value;
@Value @Value
public class PartyMemberAvatar public class PartyMemberAvatar
{ {
private final UUID memberId; private final long memberId;
private final BufferedImage image; private final BufferedImage image;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -25,14 +25,12 @@
package net.runelite.client.party; package net.runelite.client.party;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.UUID;
import lombok.Data; import lombok.Data;
@Data @Data
public class PartyMember public class PartyMember
{ {
private final UUID memberId; private final long memberId;
private final String name;
private String displayName = "<unknown>"; private String displayName = "<unknown>";
private boolean loggedIn; private boolean loggedIn;
private BufferedImage avatar; private BufferedImage avatar;

View File

@@ -50,14 +50,11 @@ 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.events.PartyMemberAvatar; import net.runelite.client.events.PartyMemberAvatar;
import net.runelite.client.party.messages.Join;
import net.runelite.client.party.messages.Part;
import net.runelite.client.party.messages.PartyChatMessage; import net.runelite.client.party.messages.PartyChatMessage;
import net.runelite.client.party.messages.PartyMessage; import net.runelite.client.party.messages.PartyMessage;
import net.runelite.client.party.messages.UserJoin; import net.runelite.client.party.events.UserJoin;
import net.runelite.client.party.messages.UserPart; import net.runelite.client.party.events.UserPart;
import net.runelite.client.party.messages.UserSync; import net.runelite.client.party.messages.UserSync;
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;
@Slf4j @Slf4j
@@ -65,8 +62,6 @@ import static net.runelite.client.util.Text.JAGEX_PRINTABLE_CHAR_MATCHER;
public class PartyService 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 String USERNAME = "rluser-" + new Random().nextInt(Integer.MAX_VALUE);
private static final String ALPHABET = "bcdfghjklmnpqrstvwxyz"; private static final String ALPHABET = "bcdfghjklmnpqrstvwxyz";
private final Client client; private final Client client;
@@ -76,7 +71,8 @@ public class PartyService
private final List<PartyMember> members = new ArrayList<>(); private final List<PartyMember> members = new ArrayList<>();
@Getter @Getter
private UUID partyId; // secret party id private long partyId; // secret party id
private long memberId = randomMemberId();
@Getter @Getter
private String partyPassphrase; private String partyPassphrase;
@@ -146,7 +142,7 @@ public class PartyService
} }
String partyPassphrase = sb.toString(); String partyPassphrase = sb.toString();
log.debug("Generated party passpharse {}", partyPassphrase); log.debug("Generated party passphrase {}", partyPassphrase);
return partyPassphrase; return partyPassphrase;
} }
@@ -154,20 +150,21 @@ public class PartyService
{ {
if (wsClient.sessionExists()) if (wsClient.sessionExists())
{ {
wsClient.send(new Part()); wsClient.part();
memberId = randomMemberId(); // use a different member id between parties
} }
UUID id = passphrase != null ? passphraseToId(passphrase) : null; long id = passphrase != null ? passphraseToId(passphrase) : 0;
log.debug("Party change to {} (id {})", passphrase, id); log.debug("Party change to {} (id {})", passphrase, id);
members.clear(); members.clear();
partyId = id; partyId = id;
partyPassphrase = passphrase; partyPassphrase = passphrase;
if (partyId == null) if (passphrase == null)
{ {
wsClient.changeSession(null); wsClient.changeSession(null);
eventBus.post(new PartyChanged(partyPassphrase, partyId)); eventBus.post(new PartyChanged(partyPassphrase, null));
return; return;
} }
@@ -178,7 +175,7 @@ public class PartyService
} }
eventBus.post(new PartyChanged(partyPassphrase, partyId)); eventBus.post(new PartyChanged(partyPassphrase, partyId));
wsClient.send(new Join(partyId, USERNAME)); wsClient.join(partyId, memberId);
} }
public <T extends PartyMessage> void send(T message) public <T extends PartyMessage> void send(T message)
@@ -187,11 +184,10 @@ public class PartyService
{ {
log.debug("Reconnecting to server"); log.debug("Reconnecting to server");
PartyMember local = getLocalMember(); members.clear();
members.removeIf(m -> m != local);
wsClient.connect(); wsClient.connect();
wsClient.send(new Join(partyId, USERNAME)); wsClient.join(partyId, memberId);
} }
wsClient.send(message); wsClient.send(message);
@@ -200,7 +196,7 @@ public class PartyService
@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.
public void onUserJoin(final UserJoin message) public void onUserJoin(final UserJoin message)
{ {
if (!partyId.equals(message.getPartyId())) if (partyId != message.getPartyId())
{ {
// This can happen when a session is resumed server side after the client party // This can happen when a session is resumed server side after the client party
// changes when disconnected. // changes when disconnected.
@@ -210,7 +206,7 @@ public class PartyService
PartyMember partyMember = getMemberById(message.getMemberId()); PartyMember partyMember = getMemberById(message.getMemberId());
if (partyMember == null) if (partyMember == null)
{ {
partyMember = new PartyMember(message.getMemberId(), cleanUsername(message.getName())); partyMember = new PartyMember(message.getMemberId());
members.add(partyMember); members.add(partyMember);
log.debug("User {} joins party, {} members", partyMember, members.size()); log.debug("User {} joins party, {} members", partyMember, members.size());
} }
@@ -219,8 +215,8 @@ public class PartyService
// Send info to other clients that this user successfully finished joining party // Send info to other clients that this user successfully finished joining party
if (localMember != null && localMember == partyMember) if (localMember != null && localMember == partyMember)
{ {
log.debug("Requesting sync");
final UserSync userSync = new UserSync(); final UserSync userSync = new UserSync();
userSync.setMemberId(message.getMemberId());
wsClient.send(userSync); wsClient.send(userSync);
} }
} }
@@ -228,7 +224,7 @@ public class PartyService
@Subscribe(priority = 1) // run prior to plugins so that the member is removed by the time the plugins see it. @Subscribe(priority = 1) // run prior to plugins so that the member is removed by the time the plugins see it.
public void onUserPart(final UserPart message) public void onUserPart(final UserPart message)
{ {
if (members.removeIf(member -> member.getMemberId().equals(message.getMemberId()))) if (members.removeIf(member -> member.getMemberId() == message.getMemberId()))
{ {
log.debug("User {} leaves party, {} members", message.getMemberId(), members.size()); log.debug("User {} leaves party, {} members", message.getMemberId(), members.size());
} }
@@ -264,27 +260,14 @@ public class PartyService
public PartyMember getLocalMember() public PartyMember getLocalMember()
{ {
return getMemberByName(USERNAME); return getMemberById(memberId);
} }
public PartyMember getMemberById(final UUID id) public PartyMember getMemberById(final long id)
{ {
for (PartyMember member : members) for (PartyMember member : members)
{ {
if (id.equals(member.getMemberId())) if (id == member.getMemberId())
{
return member;
}
}
return null;
}
public PartyMember getMemberByName(final String name)
{
for (PartyMember member : members)
{
if (name.equals(member.getName()))
{ {
return member; return member;
} }
@@ -300,10 +283,10 @@ public class PartyService
public boolean isInParty() public boolean isInParty()
{ {
return partyId != null; return partyId != 0;
} }
public void setPartyMemberAvatar(UUID memberID, BufferedImage image) public void setPartyMemberAvatar(long memberID, BufferedImage image)
{ {
final PartyMember memberById = getMemberById(memberID); final PartyMember memberById = getMemberById(memberID);
@@ -314,22 +297,15 @@ public class PartyService
} }
} }
private static String cleanUsername(String username) private static long passphraseToId(String passphrase)
{ {
String s = Text.removeTags(JAGEX_PRINTABLE_CHAR_MATCHER.retainFrom(username)); return Hashing.sha256().hashBytes(
if (s.length() >= MAX_USERNAME_LEN) passphrase.getBytes(StandardCharsets.UTF_8)
{ ).asLong() & Long.MAX_VALUE;
s = s.substring(0, MAX_USERNAME_LEN);
}
return s;
} }
private static UUID passphraseToId(String passphrase) private static long randomMemberId()
{ {
return UUID.nameUUIDFromBytes( return new Random().nextLong() & Long.MAX_VALUE;
Hashing.sha256().hashBytes(
passphrase.getBytes(StandardCharsets.UTF_8)
).asBytes()
);
} }
} }

View File

@@ -26,6 +26,8 @@ package net.runelite.client.party;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.protobuf.InvalidProtocolBufferException;
import java.io.InputStreamReader;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
@@ -37,8 +39,9 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite; import net.runelite.client.RuneLite;
import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.EventBus;
import net.runelite.client.party.messages.Handshake; import net.runelite.client.party.events.UserJoin;
import net.runelite.client.party.messages.PartyMessage; import net.runelite.client.party.events.UserPart;
import net.runelite.client.party.messages.PartyMemberMessage;
import net.runelite.client.party.messages.WebsocketMessage; import net.runelite.client.party.messages.WebsocketMessage;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
@@ -46,6 +49,7 @@ import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
import okhttp3.WebSocket; import okhttp3.WebSocket;
import okhttp3.WebSocketListener; import okhttp3.WebSocketListener;
import okio.ByteString;
@Slf4j @Slf4j
@Singleton @Singleton
@@ -104,15 +108,13 @@ public class WSClient extends WebSocketListener implements AutoCloseable
} }
Request request = new Request.Builder() Request request = new Request.Builder()
.url(runeliteWs) .url(runeliteWs.newBuilder()
.addQueryParameter("sessionId", sessionId.toString())
.build())
.header("User-Agent", RuneLite.USER_AGENT) .header("User-Agent", RuneLite.USER_AGENT)
.build(); .build();
webSocket = okHttpClient.newWebSocket(request, this); webSocket = okHttpClient.newWebSocket(request, this);
Handshake handshake = new Handshake();
handshake.setSession(sessionId);
send(handshake);
} }
boolean isOpen() boolean isOpen()
@@ -136,7 +138,42 @@ public class WSClient extends WebSocketListener implements AutoCloseable
} }
} }
public void send(WebsocketMessage message) void join(long partyId, long memberId)
{
final Party.Join join = Party.Join.newBuilder()
.setPartyId(partyId)
.setMemberId(memberId)
.build();
final Party.C2S c2s = Party.C2S.newBuilder()
.setJoin(join)
.build();
send(c2s);
}
void part()
{
final Party.Part part = Party.Part.newBuilder()
.build();
final Party.C2S c2s = Party.C2S.newBuilder()
.setPart(part)
.build();
send(c2s);
}
void send(WebsocketMessage message)
{
log.debug("Sending: {}", message);
final String json = gson.toJson(message, WebsocketMessage.class);
final Party.Data data = Party.Data.newBuilder()
.setData(com.google.protobuf.ByteString.copyFromUtf8(json))
.build();
final Party.C2S c2s = Party.C2S.newBuilder()
.setData(data)
.build();
send(c2s);
}
private void send(Party.C2S message)
{ {
if (webSocket == null) if (webSocket == null)
{ {
@@ -144,9 +181,7 @@ public class WSClient extends WebSocketListener implements AutoCloseable
connect(); connect();
} }
final String json = gson.toJson(message, WebsocketMessage.class); webSocket.send(ByteString.of(message.toByteArray()));
webSocket.send(json);
log.debug("Sent: {}", json);
} }
@Override @Override
@@ -165,28 +200,55 @@ public class WSClient extends WebSocketListener implements AutoCloseable
} }
@Override @Override
public void onMessage(WebSocket webSocket, String text) public void onMessage(WebSocket webSocket, ByteString bytes)
{ {
final WebsocketMessage message; Party.S2C s2c;
try try
{ {
message = gson.fromJson(text, WebsocketMessage.class); s2c = Party.S2C.parseFrom(bytes.toByteArray());
} }
catch (JsonParseException e) catch (InvalidProtocolBufferException e)
{ {
log.debug("Failed to deserialize message", e); log.debug("Failed to deserialize message", e);
return; return;
} }
if (message.isParty() && !(message instanceof PartyMessage)) switch (s2c.getMsgCase())
{ {
// spoofed message? case JOIN:
return; Party.UserJoin join = s2c.getJoin();
} UserJoin userJoin = new UserJoin(join.getPartyId(), join.getMemberId());
log.debug("Got: {}", userJoin);
eventBus.post(userJoin);
break;
case PART:
Party.UserPart part = s2c.getPart();
UserPart userPart = new UserPart(part.getMemberId());
log.debug("Got: {}", userPart);
eventBus.post(userPart);
break;
case DATA:
Party.PartyData data = s2c.getData();
final WebsocketMessage message;
log.debug("Got: {}", text); try
eventBus.post(message); {
message = gson.fromJson(new InputStreamReader(data.getData().newInput()), WebsocketMessage.class);
}
catch (JsonParseException e)
{
log.debug("Failed to deserialize message", e);
return;
}
if (message instanceof PartyMemberMessage)
{
((PartyMemberMessage) message).setMemberId(data.getMemberId());
}
log.debug("Got: {}", message);
eventBus.post(message);
}
} }
@Override @Override

View File

@@ -29,29 +29,19 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import net.runelite.client.party.messages.Handshake;
import net.runelite.client.party.messages.Join;
import net.runelite.client.party.messages.Part;
import net.runelite.client.party.messages.PartyChatMessage; import net.runelite.client.party.messages.PartyChatMessage;
import net.runelite.client.party.messages.UserJoin;
import net.runelite.client.party.messages.UserPart;
import net.runelite.client.party.messages.UserSync; import net.runelite.client.party.messages.UserSync;
import net.runelite.client.party.messages.WebsocketMessage; import net.runelite.client.party.messages.WebsocketMessage;
import net.runelite.client.util.RuntimeTypeAdapterFactory; import net.runelite.client.util.RuntimeTypeAdapterFactory;
import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.RuneLiteAPI;
public class WebsocketGsonFactory class WebsocketGsonFactory
{ {
private static final Collection<Class<? extends WebsocketMessage>> MESSAGES; private static final Collection<Class<? extends WebsocketMessage>> MESSAGES;
static static
{ {
final List<Class<? extends WebsocketMessage>> messages = new ArrayList<>(); final List<Class<? extends WebsocketMessage>> messages = new ArrayList<>();
messages.add(Handshake.class);
messages.add(Join.class);
messages.add(Part.class);
messages.add(UserJoin.class);
messages.add(UserPart.class);
messages.add(UserSync.class); messages.add(UserSync.class);
messages.add(PartyChatMessage.class); messages.add(PartyChatMessage.class);
MESSAGES = messages; MESSAGES = messages;

View File

@@ -22,17 +22,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.party.messages; package net.runelite.client.party.events;
import java.util.UUID;
import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
@Value @Value
@EqualsAndHashCode(callSuper = true) public class UserJoin
public class UserJoin extends WebsocketMessage
{ {
private final UUID memberId; long partyId;
private final UUID partyId; long memberId;
private final String name;
} }

View File

@@ -22,15 +22,12 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.party.messages; package net.runelite.client.party.events;
import java.util.UUID;
import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
@Value @Value
@EqualsAndHashCode(callSuper = true) public class UserPart
public class UserPart extends WebsocketMessage
{ {
private final UUID memberId; long memberId;
} }

View File

@@ -1,34 +0,0 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.party.messages;
import java.util.UUID;
import lombok.Data;
@Data
public class Handshake extends WebsocketMessage
{
private UUID session;
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* 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.party.messages;
import java.util.UUID;
import lombok.EqualsAndHashCode;
import lombok.Value;
@Value
@EqualsAndHashCode(callSuper = true)
public class Join extends WebsocketMessage
{
private final UUID partyId;
private final String name;
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* 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.party.messages;
public class Part extends WebsocketMessage
{
}

View File

@@ -1,6 +1,5 @@
package net.runelite.client.party.messages; package net.runelite.client.party.messages;
import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@@ -8,5 +7,5 @@ import lombok.Setter;
@Setter @Setter
public abstract class PartyMemberMessage extends PartyMessage public abstract class PartyMemberMessage extends PartyMessage
{ {
private UUID memberId; private transient long memberId;
} }

View File

@@ -26,8 +26,4 @@ package net.runelite.client.party.messages;
public abstract class PartyMessage extends WebsocketMessage public abstract class PartyMessage extends WebsocketMessage
{ {
public PartyMessage()
{
_party = true;
}
} }

View File

@@ -24,11 +24,6 @@
*/ */
package net.runelite.client.party.messages; package net.runelite.client.party.messages;
import lombok.EqualsAndHashCode;
import lombok.Value;
@Value
@EqualsAndHashCode(callSuper = true)
public class UserSync extends PartyMemberMessage public class UserSync extends PartyMemberMessage
{ {
} }

View File

@@ -24,12 +24,6 @@
*/ */
package net.runelite.client.party.messages; package net.runelite.client.party.messages;
public class WebsocketMessage public abstract class WebsocketMessage
{ {
protected boolean _party;
public boolean isParty()
{
return _party;
}
} }

View File

@@ -280,7 +280,6 @@ public class DiscordPlugin extends Plugin
discordUser.discriminator, discordUser.discriminator,
discordUser.avatar discordUser.avatar
); );
userInfo.setMemberId(localMember.getMemberId());
partyService.send(userInfo); partyService.send(userInfo);
} }
} }

View File

@@ -198,7 +198,6 @@ public class DpsCounterPlugin extends Plugin
if (localMember != null) if (localMember != null)
{ {
final DpsUpdate dpsUpdate = new DpsUpdate(hit, isBoss); final DpsUpdate dpsUpdate = new DpsUpdate(hit, isBoss);
dpsUpdate.setMemberId(localMember.getMemberId());
partyService.send(dpsUpdate); partyService.send(dpsUpdate);
} }
@@ -235,7 +234,7 @@ public class DpsCounterPlugin extends Plugin
@Subscribe @Subscribe
public void onDpsUpdate(DpsUpdate dpsUpdate) public void onDpsUpdate(DpsUpdate dpsUpdate)
{ {
if (partyService.getLocalMember().getMemberId().equals(dpsUpdate.getMemberId())) if (partyService.getLocalMember().getMemberId() == dpsUpdate.getMemberId())
{ {
return; return;
} }

View File

@@ -38,6 +38,8 @@ 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.party.PartyMember;
import net.runelite.client.party.PartyService;
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;
@@ -45,7 +47,6 @@ import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.MouseDragEventForwarder; import net.runelite.client.ui.components.MouseDragEventForwarder;
import net.runelite.client.ui.components.ProgressBar; import net.runelite.client.ui.components.ProgressBar;
import net.runelite.client.util.ImageUtil; import net.runelite.client.util.ImageUtil;
import net.runelite.client.party.PartyMember;
class PartyMemberBox extends JPanel class PartyMemberBox extends JPanel
{ {
@@ -56,6 +57,7 @@ class PartyMemberBox extends JPanel
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
private final PartyData memberPartyData; private final PartyData memberPartyData;
private final PartyService partyService;
private final ProgressBar hpBar = new ProgressBar(); private final ProgressBar hpBar = new ProgressBar();
private final ProgressBar prayerBar = new ProgressBar(); private final ProgressBar prayerBar = new ProgressBar();
@@ -67,10 +69,12 @@ class PartyMemberBox extends JPanel
private boolean avatarSet; private boolean avatarSet;
PartyMemberBox(final PartyConfig config, final JComponent panel, final PartyData memberPartyData) PartyMemberBox(final PartyConfig config, final JComponent panel, final PartyData memberPartyData,
final PartyService partyService)
{ {
this.config = config; this.config = config;
this.memberPartyData = memberPartyData; this.memberPartyData = memberPartyData;
this.partyService = partyService;
setLayout(new BorderLayout()); setLayout(new BorderLayout());
setBorder(new EmptyBorder(5, 0, 0, 0)); setBorder(new EmptyBorder(5, 0, 0, 0));
@@ -137,7 +141,7 @@ class PartyMemberBox extends JPanel
void update() void update()
{ {
final PartyMember member = memberPartyData.getMember(); final PartyMember member = partyService.getMemberById(memberPartyData.getMemberId());
// Avatar // Avatar
if (!avatarSet && member.getAvatar() != null) if (!avatarSet && member.getAvatar() != null)

View File

@@ -34,7 +34,6 @@ import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.StringSelection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
@@ -42,12 +41,12 @@ 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.callback.ClientThread;
import net.runelite.client.party.PartyService;
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;
import net.runelite.client.ui.components.DragAndDropReorderPane; import net.runelite.client.ui.components.DragAndDropReorderPane;
import net.runelite.client.ui.components.PluginErrorPanel; import net.runelite.client.ui.components.PluginErrorPanel;
import net.runelite.client.party.PartyService;
class PartyPanel extends PluginPanel class PartyPanel extends PluginPanel
{ {
@@ -58,7 +57,7 @@ class PartyPanel extends PluginPanel
private final PartyService party; private final PartyService party;
private final PartyConfig config; private final PartyConfig config;
private final Map<UUID, PartyMemberBox> memberBoxes = new HashMap<>(); private final Map<Long, PartyMemberBox> memberBoxes = new HashMap<>();
private final JButton startButton = new JButton(); private final JButton startButton = new JButton();
private final JButton joinPartyButton = new JButton(); private final JButton joinPartyButton = new JButton();
@@ -216,10 +215,10 @@ class PartyPanel extends PluginPanel
void addMember(PartyData partyData) void addMember(PartyData partyData)
{ {
if (!memberBoxes.containsKey(partyData.getMember().getMemberId())) if (!memberBoxes.containsKey(partyData.getMemberId()))
{ {
PartyMemberBox partyMemberBox = new PartyMemberBox(config, memberBoxPanel, partyData); PartyMemberBox partyMemberBox = new PartyMemberBox(config, memberBoxPanel, partyData, party);
memberBoxes.put(partyData.getMember().getMemberId(), partyMemberBox); memberBoxes.put(partyData.getMemberId(), partyMemberBox);
memberBoxPanel.add(partyMemberBox); memberBoxPanel.add(partyMemberBox);
memberBoxPanel.revalidate(); memberBoxPanel.revalidate();
} }
@@ -234,7 +233,7 @@ class PartyPanel extends PluginPanel
updateParty(); updateParty();
} }
void removeMember(UUID memberId) void removeMember(long memberId)
{ {
final PartyMemberBox memberBox = memberBoxes.remove(memberId); final PartyMemberBox memberBox = memberBoxes.remove(memberId);
@@ -247,7 +246,7 @@ class PartyPanel extends PluginPanel
updateParty(); updateParty();
} }
void updateMember(UUID userId) void updateMember(long userId)
{ {
final PartyMemberBox memberBox = memberBoxes.get(userId); final PartyMemberBox memberBox = memberBoxes.get(userId);

View File

@@ -36,7 +36,6 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@@ -70,8 +69,8 @@ import net.runelite.client.input.KeyManager;
import net.runelite.client.party.PartyMember; import net.runelite.client.party.PartyMember;
import net.runelite.client.party.PartyService; import net.runelite.client.party.PartyService;
import net.runelite.client.party.WSClient; import net.runelite.client.party.WSClient;
import net.runelite.client.party.messages.UserJoin; import net.runelite.client.party.events.UserJoin;
import net.runelite.client.party.messages.UserPart; import net.runelite.client.party.events.UserPart;
import net.runelite.client.party.messages.UserSync; import net.runelite.client.party.messages.UserSync;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
@@ -138,7 +137,7 @@ public class PartyPlugin extends Plugin
boolean developerMode; boolean developerMode;
@Getter @Getter
private final Map<UUID, PartyData> partyDataMap = Collections.synchronizedMap(new HashMap<>()); private final Map<Long, PartyData> partyDataMap = Collections.synchronizedMap(new HashMap<>());
@Getter @Getter
private final List<PartyTilePingData> pendingTilePings = Collections.synchronizedList(new ArrayList<>()); private final List<PartyTilePingData> pendingTilePings = Collections.synchronizedList(new ArrayList<>());
@@ -295,7 +294,6 @@ public class PartyPlugin extends Plugin
event.consume(); event.consume();
final TilePing tilePing = new TilePing(selectedSceneTile.getWorldLocation()); final TilePing tilePing = new TilePing(selectedSceneTile.getWorldLocation());
tilePing.setMemberId(party.getLocalMember().getMemberId());
party.send(tilePing); party.send(tilePing);
} }
@@ -355,7 +353,6 @@ public class PartyPlugin extends Plugin
lastLocation = location; lastLocation = location;
final LocationUpdate locationUpdate = new LocationUpdate(location); final LocationUpdate locationUpdate = new LocationUpdate(location);
locationUpdate.setMemberId(localMember.getMemberId());
party.send(locationUpdate); party.send(locationUpdate);
} }
@@ -371,7 +368,6 @@ public class PartyPlugin extends Plugin
{ {
// Request sync // Request sync
final UserSync userSync = new UserSync(); final UserSync userSync = new UserSync();
userSync.setMemberId(party.getLocalMember().getMemberId());
party.send(userSync); party.send(userSync);
} }
} }
@@ -380,28 +376,29 @@ public class PartyPlugin extends Plugin
public void onCharacterNameUpdate(final CharacterNameUpdate event) public void onCharacterNameUpdate(final CharacterNameUpdate event)
{ {
final PartyData partyData = getPartyData(event.getMemberId()); final PartyData partyData = getPartyData(event.getMemberId());
if (partyData == null) if (partyData == null)
{ {
return; return;
} }
final String name = Text.removeTags(Text.toJagexName(event.getCharacterName())); final PartyMember member = party.getMemberById(event.getMemberId());
final PartyMember member = partyData.getMember(); if (member != null)
if (!name.isEmpty())
{ {
member.setDisplayName(name); final String name = Text.removeTags(Text.toJagexName(event.getCharacterName()));
member.setLoggedIn(true); if (!name.isEmpty())
partyData.setColor(ColorUtil.fromObject(name)); {
} member.setDisplayName(name);
else member.setLoggedIn(true);
{ partyData.setColor(ColorUtil.fromObject(name));
member.setLoggedIn(false); }
partyData.setColor(Color.WHITE); else
{
member.setLoggedIn(false);
partyData.setColor(Color.WHITE);
}
} }
SwingUtilities.invokeLater(() -> panel.updateMember(member.getMemberId())); SwingUtilities.invokeLater(() -> panel.updateMember(event.getMemberId()));
} }
@Subscribe @Subscribe
@@ -425,7 +422,7 @@ public class PartyPlugin extends Plugin
partyData.setMaxPrayer(event.getMax()); partyData.setMaxPrayer(event.getMax());
} }
SwingUtilities.invokeLater(() -> panel.updateMember(partyData.getMember().getMemberId())); SwingUtilities.invokeLater(() -> panel.updateMember(partyData.getMemberId()));
} }
@Subscribe @Subscribe
@@ -471,21 +468,18 @@ public class PartyPlugin extends Plugin
if (forceSend || currentHealth != lastHp) if (forceSend || currentHealth != lastHp)
{ {
final SkillUpdate update = new SkillUpdate(Skill.HITPOINTS, currentHealth, realHealth); final SkillUpdate update = new SkillUpdate(Skill.HITPOINTS, currentHealth, realHealth);
update.setMemberId(localMember.getMemberId());
party.send(update); party.send(update);
} }
if (forceSend || currentPrayer != lastPray) if (forceSend || currentPrayer != lastPray)
{ {
final SkillUpdate update = new SkillUpdate(Skill.PRAYER, currentPrayer, realPrayer); final SkillUpdate update = new SkillUpdate(Skill.PRAYER, currentPrayer, realPrayer);
update.setMemberId(localMember.getMemberId());
party.send(update); party.send(update);
} }
if (forceSend || !characterName.equals(lastCharacterName)) if (forceSend || !characterName.equals(lastCharacterName))
{ {
final CharacterNameUpdate update = new CharacterNameUpdate(characterName); final CharacterNameUpdate update = new CharacterNameUpdate(characterName);
update.setMemberId(localMember.getMemberId());
party.send(update); party.send(update);
} }
} }
@@ -536,7 +530,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("Member " + partyMember.getName() + " " + partyMember.getDisplayName() + " " + partyMember.getMemberId()).build()); chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Member " + partyMember.getDisplayName() + " " + partyMember.getMemberId()).build());
} }
} }
@@ -547,7 +541,7 @@ public class PartyPlugin extends Plugin
} }
@Nullable @Nullable
PartyData getPartyData(final UUID uuid) PartyData getPartyData(final long uuid)
{ {
final PartyMember memberById = party.getMemberById(uuid); final PartyMember memberById = party.getMemberById(uuid);
@@ -573,7 +567,7 @@ public class PartyPlugin extends Plugin
worldMapManager.add(worldMapPoint); worldMapManager.add(worldMapPoint);
} }
PartyData partyData = new PartyData(memberById, worldMapPoint); PartyData partyData = new PartyData(uuid, worldMapPoint);
SwingUtilities.invokeLater(() -> panel.addMember(partyData)); SwingUtilities.invokeLater(() -> panel.addMember(partyData));
return partyData; return partyData;

View File

@@ -24,7 +24,6 @@
*/ */
package net.runelite.client.plugins.party; package net.runelite.client.plugins.party;
import java.util.UUID;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import net.runelite.client.plugins.party.data.PartyData; import net.runelite.client.plugins.party.data.PartyData;
@@ -36,5 +35,5 @@ public interface PartyPluginService
* @return party data for member * @return party data for member
*/ */
@Nullable @Nullable
PartyData getPartyData(UUID memberId); PartyData getPartyData(long memberId);
} }

View File

@@ -24,7 +24,6 @@
*/ */
package net.runelite.client.plugins.party; package net.runelite.client.plugins.party;
import java.util.UUID;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import net.runelite.client.plugins.party.data.PartyData; import net.runelite.client.plugins.party.data.PartyData;
@@ -42,7 +41,7 @@ public class PartyPluginServiceImpl implements PartyPluginService
} }
@Override @Override
public PartyData getPartyData(UUID memberId) public PartyData getPartyData(long memberId)
{ {
return plugin.getPartyData(memberId); return plugin.getPartyData(memberId);
} }

View File

@@ -31,14 +31,13 @@ import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
import net.runelite.client.party.PartyMember;
@Setter @Setter
@Getter @Getter
@RequiredArgsConstructor @RequiredArgsConstructor
public class PartyData public class PartyData
{ {
private final PartyMember member; private final long memberId;
private final WorldMapPoint worldMapPoint; private final WorldMapPoint worldMapPoint;
private final PanelComponent panel = new PanelComponent(); private final PanelComponent panel = new PanelComponent();
private Color color = Color.WHITE; private Color color = Color.WHITE;

View File

@@ -24,14 +24,27 @@
*/ */
package net.runelite.client.plugins.party.messages; package net.runelite.client.plugins.party.messages;
import lombok.EqualsAndHashCode; import lombok.ToString;
import lombok.Value;
import net.runelite.api.coords.WorldPoint; import net.runelite.api.coords.WorldPoint;
import net.runelite.client.party.messages.PartyMemberMessage; import net.runelite.client.party.messages.PartyMemberMessage;
@Value @ToString(onlyExplicitlyIncluded = true)
@EqualsAndHashCode(callSuper = true)
public class LocationUpdate extends PartyMemberMessage public class LocationUpdate extends PartyMemberMessage
{ {
private final WorldPoint worldPoint; private final int c;
public LocationUpdate(WorldPoint worldPoint)
{
c = (worldPoint.getPlane() << 28) | (worldPoint.getX() << 14) | (worldPoint.getY());
}
@ToString.Include
public WorldPoint getWorldPoint()
{
return new WorldPoint(
(c >> 14) & 0x3fff,
c & 0x3fff,
(c >> 28) & 3
);
}
} }

View File

@@ -314,7 +314,6 @@ public class SpecialCounterPlugin extends Plugin
if (!party.getMembers().isEmpty()) if (!party.getMembers().isEmpty())
{ {
final SpecialCounterUpdate specialCounterUpdate = new SpecialCounterUpdate(npcIndex, specialWeapon, hit, client.getWorld(), localPlayerId); final SpecialCounterUpdate specialCounterUpdate = new SpecialCounterUpdate(npcIndex, specialWeapon, hit, client.getWorld(), localPlayerId);
specialCounterUpdate.setMemberId(party.getLocalMember().getMemberId());
party.send(specialCounterUpdate); party.send(specialCounterUpdate);
} }
@@ -341,7 +340,7 @@ public class SpecialCounterPlugin extends Plugin
@Subscribe @Subscribe
public void onSpecialCounterUpdate(SpecialCounterUpdate event) public void onSpecialCounterUpdate(SpecialCounterUpdate event)
{ {
if (party.getLocalMember().getMemberId().equals(event.getMemberId()) if (party.getLocalMember().getMemberId() == event.getMemberId()
|| event.getWorld() != client.getWorld()) || event.getWorld() != client.getWorld())
{ {
return; return;

View File

@@ -18,7 +18,7 @@ runelite.imgur.client.id=30d71e5f6860809
runelite.api.base=https://api.runelite.net/runelite-${project.version} runelite.api.base=https://api.runelite.net/runelite-${project.version}
runelite.session=https://api.runelite.net/session runelite.session=https://api.runelite.net/session
runelite.static.base=https://static.runelite.net runelite.static.base=https://static.runelite.net
runelite.ws=https://api.runelite.net/ws runelite.ws=https://api.runelite.net/ws2
runelite.config=https://static.runelite.net/config.json runelite.config=https://static.runelite.net/config.json
runelite.osrstwitter.link=https://twitter.com/OldSchoolRS runelite.osrstwitter.link=https://twitter.com/OldSchoolRS
runelite.oauth.redirect=https://runelite.net/logged-in runelite.oauth.redirect=https://runelite.net/logged-in

View File

@@ -27,5 +27,6 @@
"-//Checkstyle//DTD SuppressionFilter Configuration 1.1//EN" "-//Checkstyle//DTD SuppressionFilter Configuration 1.1//EN"
"https://checkstyle.org/dtds/suppressions_1_1.dtd"> "https://checkstyle.org/dtds/suppressions_1_1.dtd">
<suppressions> <suppressions>
<suppress files="RuntimeTypeAdapterFactory\.java" checks="[a-zA-Z0-9]*"/> <suppress files="RuntimeTypeAdapterFactory\.java" checks=".*"/>
<suppress files="net[/\\]runelite[/\\]client[/\\]party[/\\]Party\.java" checks=".*"/>
</suppressions> </suppressions>