Skip to content

Commit 7dd2a74

Browse files
feat: parties
Took 6 hours 57 minutes
1 parent 205756a commit 7dd2a74

61 files changed

Lines changed: 3436 additions & 17 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,4 @@ jobs:
5353
service.itemtracker/build/libs/*.jar
5454
service.api/build/libs/*.jar
5555
service.datamutex/build/libs/*.jar
56+
service.party/build/libs/*.jar

commons/src/main/java/net/swofty/commons/ServerType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ public static boolean isServerType(String type) {
1414

1515
return false;
1616
}
17+
18+
public String formatName() {
19+
return StringUtility.toNormalCase(name());
20+
}
1721
}

commons/src/main/java/net/swofty/commons/ServiceType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ public enum ServiceType {
66
ITEM_TRACKER,
77
API,
88
DATA_MUTEX,
9+
PARTY,
910
;
1011
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package net.swofty.commons.party;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
import net.swofty.commons.StringUtility;
6+
import net.swofty.commons.protocol.Serializer;
7+
import org.json.JSONObject;
8+
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.UUID;
13+
14+
@Getter
15+
public class FullParty implements Party {
16+
private final UUID uuid;
17+
private final List<Member> members;
18+
19+
private FullParty(UUID uuid, List<Member> members) {
20+
this.uuid = uuid;
21+
this.members = members;
22+
}
23+
24+
public Member getFromUuid(UUID uuid) {
25+
return members.stream().filter(member -> member.getUuid().equals(uuid)).findFirst().orElseThrow();
26+
}
27+
28+
public Member getLeader() {
29+
return members.stream().filter(member -> member.getRole() == Role.LEADER).findFirst().orElseThrow();
30+
}
31+
32+
public static FullParty create(UUID leader, UUID invitee) {
33+
Member leaderMember = new Member(leader, Role.LEADER, true);
34+
Member inviteeMember = new Member(invitee, Role.MEMBER, true);
35+
36+
return new FullParty(UUID.randomUUID(), new ArrayList<>(List.of(leaderMember, inviteeMember)));
37+
}
38+
39+
public static Serializer<FullParty> getStaticSerializer() {
40+
FullParty party = create(UUID.randomUUID(), UUID.randomUUID());
41+
return party.getSerializer();
42+
}
43+
44+
@Override
45+
public Serializer<FullParty> getSerializer() {
46+
return new Serializer<FullParty>() {
47+
@Override
48+
public String serialize(FullParty value) {
49+
JSONObject json = new JSONObject();
50+
json.put("uuid", value.uuid.toString());
51+
json.put("members", value.members.stream()
52+
.map(member -> new JSONObject()
53+
.put("uuid", member.uuid.toString())
54+
.put("role", member.role.name())
55+
.put("joined", member.joined)
56+
).toList());
57+
return json.toString();
58+
}
59+
60+
@Override
61+
public FullParty deserialize(String json) {
62+
JSONObject jsonObject = new JSONObject(json);
63+
UUID uuid = UUID.fromString(jsonObject.getString("uuid"));
64+
List<Member> members = jsonObject.getJSONArray("members").toList().stream()
65+
.map(member -> {
66+
Map<String, Object> memberObject = (Map<String, Object>) member;
67+
68+
return new Member(
69+
UUID.fromString(memberObject.get("uuid").toString()),
70+
Role.valueOf(memberObject.get("role").toString()),
71+
memberObject.get("joined").toString().equals("true")
72+
);
73+
}).toList();
74+
return new FullParty(uuid, members);
75+
}
76+
77+
@Override
78+
public FullParty clone(FullParty value) {
79+
return new FullParty(value.uuid, value.members);
80+
}
81+
};
82+
}
83+
84+
@Override
85+
public List<UUID> getParticipants() {
86+
return members.stream().map(Member::getUuid).toList();
87+
}
88+
89+
@Setter
90+
@Getter
91+
public static class Member {
92+
private final UUID uuid;
93+
private Role role;
94+
private boolean joined;
95+
96+
public Member(UUID uuid, Role role, boolean joined) {
97+
this.uuid = uuid;
98+
this.role = role;
99+
this.joined = joined;
100+
}
101+
}
102+
103+
public enum Role {
104+
LEADER,
105+
MODERATOR,
106+
MEMBER,
107+
;
108+
109+
@Override
110+
public String toString() {
111+
return StringUtility.toNormalCase(name());
112+
}
113+
}
114+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package net.swofty.commons.party;
2+
3+
import net.swofty.commons.protocol.Serializer;
4+
5+
import java.util.List;
6+
import java.util.UUID;
7+
8+
public interface Party {
9+
Serializer<? extends Party> getSerializer();
10+
11+
List<UUID> getParticipants();
12+
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package net.swofty.commons.party;
2+
3+
import lombok.Getter;
4+
import lombok.NonNull;
5+
import net.swofty.commons.protocol.Serializer;
6+
import org.tinylog.Logger;
7+
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import java.util.UUID;
11+
12+
@Getter
13+
public abstract class PartyEvent {
14+
private final Party party;
15+
16+
public PartyEvent(Party party) {
17+
this.party = party;
18+
}
19+
20+
public abstract Serializer getSerializer();
21+
22+
public List<UUID> getParticipants() {
23+
return party != null ? party.getParticipants() : List.of();
24+
}
25+
26+
public static @NonNull PartyEvent findFromType(String className) {
27+
String[] packageNames = {
28+
"net.swofty.commons.party.events",
29+
"net.swofty.commons.party.events.response"
30+
};
31+
32+
for (String packageName : packageNames) {
33+
try {
34+
Class<?> clazz = Class.forName(packageName + "." + className);
35+
// Create a dummy instance just to get the serializer for deserialization
36+
// We'll never actually use this instance - it's just for getting the serializer
37+
return createDummyInstance(clazz);
38+
} catch (Exception e) {
39+
// Try next package
40+
}
41+
}
42+
43+
throw new RuntimeException("Failed to find party event class: " + className + " in " + Arrays.toString(packageNames));
44+
}
45+
46+
@SuppressWarnings("unchecked")
47+
private static PartyEvent createDummyInstance(Class<?> clazz) throws Exception {
48+
String className = clazz.getSimpleName();
49+
50+
// Handle request events (these all have null party or specific constructors)
51+
switch (className) {
52+
case "PartyAcceptInviteEvent" -> {
53+
var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class);
54+
return (PartyEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID());
55+
}
56+
case "PartyLeaveRequestEvent" -> {
57+
var constructor = clazz.getDeclaredConstructor(UUID.class);
58+
return (PartyEvent) constructor.newInstance(UUID.randomUUID());
59+
}
60+
case "PartyDisbandRequestEvent" -> {
61+
var constructor = clazz.getDeclaredConstructor(UUID.class);
62+
return (PartyEvent) constructor.newInstance(UUID.randomUUID());
63+
}
64+
case "PartyTransferRequestEvent" -> {
65+
var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class);
66+
return (PartyEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID());
67+
}
68+
case "PartyKickRequestEvent" -> {
69+
var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class);
70+
return (PartyEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID());
71+
}
72+
case "PartyPromoteRequestEvent" -> {
73+
var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class);
74+
return (PartyEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID());
75+
}
76+
case "PartyDemoteRequestEvent" -> {
77+
var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class);
78+
return (PartyEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID());
79+
}
80+
case "PartyPlayerSwitchedServerEvent" -> {
81+
var constructor = clazz.getDeclaredConstructor(UUID.class);
82+
return (PartyEvent) constructor.newInstance(UUID.randomUUID());
83+
}
84+
case "PartyWarpRequestEvent" -> {
85+
var constructor = clazz.getDeclaredConstructor(UUID.class);
86+
return (PartyEvent) constructor.newInstance(UUID.randomUUID());
87+
}
88+
case "PartyListRequestEvent" -> {
89+
var constructor = clazz.getDeclaredConstructor(UUID.class);
90+
return (PartyEvent) constructor.newInstance(UUID.randomUUID());
91+
}
92+
case "PartyHijackRequestEvent" -> {
93+
var constructor = clazz.getDeclaredConstructor(UUID.class, UUID.class);
94+
return (PartyEvent) constructor.newInstance(UUID.randomUUID(), UUID.randomUUID());
95+
}
96+
case "PartyChatMessageEvent" -> {
97+
var constructor = clazz.getDeclaredConstructor(UUID.class, String.class);
98+
return (PartyEvent) constructor.newInstance(UUID.randomUUID(), "");
99+
}
100+
// Handle response events
101+
case "PartyPlayerSwitchedServerResponseEvent" -> {
102+
var fullParty = net.swofty.commons.party.FullParty.create(UUID.randomUUID(), UUID.randomUUID());
103+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.FullParty.class, UUID.class);
104+
return (PartyEvent) constructor.newInstance(fullParty, UUID.randomUUID());
105+
}
106+
case "PartyChatMessageResponseEvent" -> {
107+
var fullParty = net.swofty.commons.party.FullParty.create(UUID.randomUUID(), UUID.randomUUID());
108+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.FullParty.class, UUID.class, String.class);
109+
return (PartyEvent) constructor.newInstance(fullParty, UUID.randomUUID(), "");
110+
}
111+
case "PartyInviteResponseEvent" -> {
112+
var pendingParty = net.swofty.commons.party.PendingParty.create(UUID.randomUUID(), UUID.randomUUID());
113+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.PendingParty.class);
114+
return (PartyEvent) constructor.newInstance(pendingParty);
115+
}
116+
case "PartyWarpOverviewResponseEvent" -> {
117+
var fullParty = net.swofty.commons.party.FullParty.create(UUID.randomUUID(), UUID.randomUUID());
118+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.FullParty.class, UUID.class, List.class, List.class);
119+
return (PartyEvent) constructor.newInstance(fullParty, UUID.randomUUID(), List.of(), List.of());
120+
}
121+
case "PartyStartedResponseEvent" -> {
122+
var constructor = clazz.getDeclaredConstructor(FullParty.class);
123+
return (PartyEvent) constructor.newInstance(FullParty.create(UUID.randomUUID(), UUID.randomUUID()));
124+
}
125+
case "PartyDisbandResponseEvent" -> {
126+
var fullParty = net.swofty.commons.party.FullParty.create(UUID.randomUUID(), UUID.randomUUID());
127+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.FullParty.class, UUID.class, String.class);
128+
return (PartyEvent) constructor.newInstance(fullParty, UUID.randomUUID(), "");
129+
}
130+
case "PartyLeaderTransferResponseEvent" -> {
131+
var fullParty = net.swofty.commons.party.FullParty.create(UUID.randomUUID(), UUID.randomUUID());
132+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.FullParty.class, UUID.class, UUID.class);
133+
return (PartyEvent) constructor.newInstance(fullParty, UUID.randomUUID(), UUID.randomUUID());
134+
}
135+
case "PartyMemberJoinResponseEvent" -> {
136+
var constructor = clazz.getDeclaredConstructor(FullParty.class, UUID.class, UUID.class);
137+
return (PartyEvent) constructor.newInstance(FullParty.create(UUID.randomUUID(), UUID.randomUUID()), UUID.randomUUID(), UUID.randomUUID());
138+
}
139+
case "PartyMemberKickResponseEvent" -> {
140+
var fullParty = net.swofty.commons.party.FullParty.create(UUID.randomUUID(), UUID.randomUUID());
141+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.FullParty.class, UUID.class, UUID.class);
142+
return (PartyEvent) constructor.newInstance(fullParty, UUID.randomUUID(), UUID.randomUUID());
143+
}
144+
case "PartyInviteExpiredResponseEvent" -> {
145+
var constructor = clazz.getDeclaredConstructor(FullParty.class, UUID.class, UUID.class);
146+
return (PartyEvent) constructor.newInstance(FullParty.create(UUID.randomUUID(), UUID.randomUUID()), UUID.randomUUID(), UUID.randomUUID());
147+
}
148+
case "PartyMemberLeaveResponseEvent" -> {
149+
var fullParty = net.swofty.commons.party.FullParty.create(UUID.randomUUID(), UUID.randomUUID());
150+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.FullParty.class, UUID.class);
151+
return (PartyEvent) constructor.newInstance(fullParty, UUID.randomUUID());
152+
}
153+
case "PartyPromotionResponseEvent" -> {
154+
var fullParty = net.swofty.commons.party.FullParty.create(UUID.randomUUID(), UUID.randomUUID());
155+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.FullParty.class, UUID.class, UUID.class, net.swofty.commons.party.FullParty.Role.class);
156+
return (PartyEvent) constructor.newInstance(fullParty, UUID.randomUUID(), UUID.randomUUID(), net.swofty.commons.party.FullParty.Role.MEMBER);
157+
}
158+
case "PartyWarpResponseEvent" -> {
159+
var fullParty = net.swofty.commons.party.FullParty.create(UUID.randomUUID(), UUID.randomUUID());
160+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.FullParty.class, UUID.class);
161+
return (PartyEvent) constructor.newInstance(fullParty, UUID.randomUUID());
162+
}
163+
case "PartyInviteEvent" -> {
164+
var pendingParty = net.swofty.commons.party.PendingParty.create(UUID.randomUUID(), UUID.randomUUID());
165+
var constructor = clazz.getDeclaredConstructor(net.swofty.commons.party.PendingParty.class);
166+
return (PartyEvent) constructor.newInstance(pendingParty);
167+
}
168+
default -> throw new IllegalArgumentException("Unknown party event class: " + className);
169+
}
170+
}
171+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package net.swofty.commons.party;
2+
3+
import net.swofty.commons.party.PartyEvent;
4+
5+
public abstract class PartyResponseEvent extends PartyEvent {
6+
public PartyResponseEvent(Party party) {
7+
super(party);
8+
}
9+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package net.swofty.commons.party;
2+
3+
import lombok.Getter;
4+
import net.swofty.commons.protocol.Serializer;
5+
import org.json.JSONObject;
6+
7+
import java.util.List;
8+
import java.util.UUID;
9+
10+
@Getter
11+
public class PendingParty implements Party {
12+
public final UUID resultPartyUUID;
13+
public final UUID invitee;
14+
public final UUID leader;
15+
16+
public PendingParty(UUID resultPartyUUID, UUID invitee, UUID leader) {
17+
this.resultPartyUUID = resultPartyUUID;
18+
this.invitee = invitee;
19+
this.leader = leader;
20+
}
21+
22+
@Override
23+
public List<UUID> getParticipants() {
24+
return List.of(invitee, leader);
25+
}
26+
27+
public static PendingParty create(UUID invitee, UUID leader) {
28+
return new PendingParty(UUID.randomUUID(), invitee, leader);
29+
}
30+
31+
public static Serializer<PendingParty> getStaticSerializer() {
32+
PendingParty party = create(UUID.randomUUID(), UUID.randomUUID());
33+
return party.getSerializer();
34+
}
35+
36+
@Override
37+
public Serializer<PendingParty> getSerializer() {
38+
return new Serializer<PendingParty>() {
39+
@Override
40+
public String serialize(PendingParty value) {
41+
JSONObject json = new JSONObject();
42+
json.put("resultPartyUUID", value.resultPartyUUID.toString());
43+
json.put("invitee", value.invitee.toString());
44+
json.put("leader", value.leader.toString());
45+
return json.toString();
46+
}
47+
48+
@Override
49+
public PendingParty deserialize(String json) {
50+
JSONObject jsonObject = new JSONObject(json);
51+
return new PendingParty(
52+
UUID.fromString(jsonObject.getString("resultPartyUUID")),
53+
UUID.fromString(jsonObject.getString("invitee")),
54+
UUID.fromString(jsonObject.getString("leader"))
55+
);
56+
}
57+
58+
@Override
59+
public PendingParty clone(PendingParty value) {
60+
return new PendingParty(value.resultPartyUUID, value.invitee, value.leader);
61+
}
62+
};
63+
}
64+
}

0 commit comments

Comments
 (0)