Skip to content

Commit 3cf942f

Browse files
Merge pull request #763 from ArikSquad/fix/data-handler-fixes
Concurrency for DataHandler
2 parents 46320fb + 684fb53 commit 3cf942f

File tree

6 files changed

+73
-68
lines changed

6 files changed

+73
-68
lines changed

commons/src/main/java/net/swofty/commons/skyblock/SkyBlockPlayerProfiles.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
import lombok.Getter;
44
import lombok.Setter;
55

6-
import java.util.*;
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Random;
10+
import java.util.UUID;
11+
import java.util.concurrent.ConcurrentHashMap;
712

813
@Getter
914
@Setter
@@ -17,7 +22,7 @@ public class SkyBlockPlayerProfiles {
1722
"Potato", "Onion", "Garlic", "Celery",
1823
"Broccoli", "Cauliflower", "Spinach", "Asparagus"
1924
};
20-
private static final Map<UUID, SkyBlockPlayerProfiles> profilesCache = new HashMap<>();
25+
private static final Map<UUID, SkyBlockPlayerProfiles> profilesCache = new ConcurrentHashMap<>();
2126

2227
UUID currentlySelected = null;
2328
ArrayList<UUID> profiles = new ArrayList<>();

type.generic/src/main/java/net/swofty/type/generic/data/DataHandler.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,21 @@
66
import org.bson.Document;
77
import org.jetbrains.annotations.Nullable;
88

9-
import java.util.HashMap;
109
import java.util.Map;
1110
import java.util.UUID;
11+
import java.util.concurrent.ConcurrentHashMap;
1212

13+
@Getter
1314
public abstract class DataHandler {
14-
public static Map<UUID, DataHandler> userCache = new HashMap<>();
15+
public static Map<UUID, DataHandler> userCache = new ConcurrentHashMap<>();
1516

16-
@Getter protected UUID uuid;
17-
protected final Map<String, Datapoint<?>> datapoints = new HashMap<>();
17+
protected UUID uuid;
18+
protected final Map<String, Datapoint<?>> datapoints = new ConcurrentHashMap<>();
1819

1920
protected DataHandler() {}
2021
protected DataHandler(UUID uuid) { this.uuid = uuid; }
2122

2223
public Datapoint<?> getDatapoint(String key) { return this.datapoints.get(key); }
23-
public Map<String, Datapoint<?>> getDatapoints() { return this.datapoints; }
2424

2525
public static @NonNull DataHandler getUser(UUID uuid) {
2626
if (!userCache.containsKey(uuid)) throw new RuntimeException("User " + uuid + " does not exist!");

type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/SkyBlockDataHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,14 @@
4242
import java.util.Map;
4343
import java.util.Objects;
4444
import java.util.UUID;
45+
import java.util.concurrent.ConcurrentHashMap;
4546
import java.util.function.BiConsumer;
4647
import java.util.function.Function;
4748

4849
public class SkyBlockDataHandler extends DataHandler {
4950

5051
// SkyBlock specific cache
51-
public static final Map<UUID, SkyBlockDataHandler> skyBlockCache = new HashMap<>();
52+
public static final Map<UUID, SkyBlockDataHandler> skyBlockCache = new ConcurrentHashMap<>();
5253

5354
@Getter
5455
private UUID currentProfileId;
@@ -522,4 +523,4 @@ public static void startRepeatSetValueLoop() {
522523
return TaskSchedule.nextTick();
523524
});
524525
}
525-
}
526+
}

type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/data/ActionPlayerSkyBlockDataLoad.java

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import lombok.SneakyThrows;
44
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
55
import net.swofty.commons.skyblock.SkyBlockPlayerProfiles;
6+
import net.swofty.type.generic.data.datapoints.DatapointString;
67
import net.swofty.type.generic.data.mongodb.ProfilesDatabase;
78
import net.swofty.type.generic.data.mongodb.UserDatabase;
89
import net.swofty.type.generic.event.EventNodes;
@@ -15,6 +16,7 @@
1516
import org.bson.Document;
1617
import org.tinylog.Logger;
1718

19+
import java.util.Objects;
1820
import java.util.UUID;
1921

2022
public class ActionPlayerSkyBlockDataLoad implements HypixelEventClass {
@@ -26,7 +28,6 @@ public void run(AsyncPlayerConfigurationEvent event) {
2628

2729
final SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer();
2830
UUID playerUuid = player.getUuid();
29-
UUID islandUUID;
3031

3132
// Check if player has ever joined SkyBlock before
3233
SkyBlockPlayerProfiles profiles = new UserDatabase(playerUuid).getProfiles();
@@ -37,8 +38,6 @@ public void run(AsyncPlayerConfigurationEvent event) {
3738
Logger.info("New SkyBlock player detected: " + player.getUsername() + " - initializing...");
3839

3940
profileId = UUID.randomUUID();
40-
islandUUID = profileId; // Use profile ID as island ID for new players
41-
4241
// Create new profiles object
4342
profiles = new SkyBlockPlayerProfiles(playerUuid);
4443
profiles.setCurrentlySelected(profileId);
@@ -53,50 +52,55 @@ public void run(AsyncPlayerConfigurationEvent event) {
5352
if (profileId == null) {
5453
// Player has profiles but no selected profile - create new one
5554
profileId = UUID.randomUUID();
56-
islandUUID = profileId;
5755
profiles.setCurrentlySelected(profileId);
5856
profiles.addProfile(profileId);
5957

6058
// Save updated profiles
6159
UserDatabase userDb = new UserDatabase(playerUuid);
6260
userDb.saveProfiles(profiles);
63-
} else {
64-
// Load existing profile's island UUID
65-
ProfilesDatabase temp = new ProfilesDatabase(profileId.toString());
66-
Document doc = temp.getDocument();
67-
if (doc != null) {
68-
islandUUID = SkyBlockDataHandler.createFromProfileOnly(doc)
69-
.get(SkyBlockDataHandler.Data.ISLAND_UUID, DatapointUUID.class).getValue();
70-
} else {
71-
// Profile doesn't exist in database yet
72-
islandUUID = profileId;
73-
}
7461
}
7562
}
7663

77-
78-
// Set up the island
79-
SkyBlockIsland island = (SkyBlockIsland.getIsland(islandUUID) == null)
80-
? new SkyBlockIsland(islandUUID, profileId)
81-
: SkyBlockIsland.getIsland(islandUUID);
82-
player.setSkyBlockIsland(island);
83-
8464
// Load SkyBlock profile data
8565
ProfilesDatabase profileDb = new ProfilesDatabase(profileId.toString());
8666
SkyBlockDataHandler handler;
67+
boolean shouldPersistProfile = false;
8768

8869
if (profileDb.exists()) {
8970
Document profileDocument = profileDb.getDocument();
9071
handler = SkyBlockDataHandler.createFromProfile(playerUuid, profileId, profileDocument);
9172
} else {
9273
handler = SkyBlockDataHandler.initUserWithDefaultData(playerUuid, profileId);
93-
// Save the new profile
94-
profileDb.saveDocument(handler.toProfileDocument());
74+
shouldPersistProfile = true;
75+
}
76+
77+
DatapointUUID islandDatapoint = handler.get(SkyBlockDataHandler.Data.ISLAND_UUID, DatapointUUID.class);
78+
UUID islandUUID = islandDatapoint.getValue();
79+
if (islandUUID == null) {
80+
islandUUID = profileId;
81+
islandDatapoint.setValue(islandUUID);
82+
shouldPersistProfile = true;
83+
}
84+
85+
DatapointString profileNameDatapoint = handler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class);
86+
if (Objects.equals(profileNameDatapoint.getValue(), "null")) {
87+
profileNameDatapoint.setValue(SkyBlockPlayerProfiles.getRandomName());
88+
shouldPersistProfile = true;
9589
}
9690

9791
// Put in SkyBlock cache
9892
SkyBlockDataHandler.skyBlockCache.put(playerUuid, handler);
9993

94+
if (shouldPersistProfile) {
95+
profileDb.saveDocument(handler.toProfileDocument());
96+
}
97+
98+
// Set up the island after the cache is populated so island init can see the player as loaded
99+
SkyBlockIsland island = (SkyBlockIsland.getIsland(islandUUID) == null)
100+
? new SkyBlockIsland(islandUUID, profileId)
101+
: SkyBlockIsland.getIsland(islandUUID);
102+
player.setSkyBlockIsland(island);
103+
100104
Logger.info("Successfully loaded SkyBlock (profile " + profileId + ") for: " + player.getUsername());
101105
}
102-
}
106+
}

velocity.extension/src/main/java/net/swofty/velocity/gamemanager/TransferHandler.java

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,16 @@
99
import net.swofty.velocity.redis.RedisMessage;
1010
import org.json.JSONObject;
1111

12-
import java.util.ArrayList;
13-
import java.util.HashMap;
14-
import java.util.List;
1512
import java.util.Map;
13+
import java.util.Set;
1614
import java.util.UUID;
1715
import java.util.concurrent.CompletableFuture;
16+
import java.util.concurrent.ConcurrentHashMap;
1817

1918
public record TransferHandler(Player player) {
20-
public static final Map<Player, ServerType> playersGoalServerType = new HashMap<>();
21-
private static final Map<Player, RegisteredServer> playersOriginServer = new HashMap<>();
22-
private static final List<Player> disregard = new ArrayList<>();
19+
public static final Map<Player, ServerType> playersGoalServerType = new ConcurrentHashMap<>();
20+
private static final Map<Player, RegisteredServer> playersOriginServer = new ConcurrentHashMap<>();
21+
private static final Set<Player> disregard = ConcurrentHashMap.newKeySet();
2322

2423
public boolean isInLimbo() {
2524
return playersGoalServerType.containsKey(player);
@@ -37,6 +36,13 @@ public CompletableFuture<Boolean> sendToLimbo() {
3736
CompletableFuture<Boolean> future = new CompletableFuture<>();
3837

3938
new Thread(() -> {
39+
if (isInLimbo() && player.getCurrentServer()
40+
.map(server -> server.getServer().equals(SkyBlockVelocity.getLimboServer()))
41+
.orElse(false)) {
42+
future.complete(true);
43+
return;
44+
}
45+
4046
if (player.getCurrentServer().isPresent()) {
4147
RegisteredServer previousServer = player.getCurrentServer().get().getServer();
4248
playersOriginServer.put(player, previousServer);
@@ -81,17 +87,28 @@ public void previousServerIsFinished(RegisteredServer manualPick) {
8187

8288
public void previousServerIsFinished() {
8389
new Thread(() -> {
84-
if (disregard.contains(player)) return;
90+
if (disregard.contains(player) || !isInLimbo()) return;
8591

8692
ServerType type = playersGoalServerType.get(player);
93+
if (type == null) {
94+
playersGoalServerType.remove(player);
95+
playersOriginServer.remove(player);
96+
return;
97+
}
8798
GameManager.GameServer server = BalanceConfigurations.getServerFor(player, type);
8899

89100
if (server == null) {
101+
playersGoalServerType.remove(player);
102+
playersOriginServer.remove(player);
90103
player.disconnect(Component.text("§cThere are no Hypixel (type=" + type.name() + ") servers available at the moment."));
91104
return;
92105
}
93106

94107
RegisteredServer originServer = playersOriginServer.get(player);
108+
if (originServer == null) {
109+
playersGoalServerType.remove(player);
110+
return;
111+
}
95112
UUID originServerUUID = UUID.fromString(originServer.getServerInfo().getName());
96113
UUID sendingToServerUUID = server.internalID();
97114
ServerType originServerType = GameManager.getTypeFromRegisteredServer(originServer);
@@ -116,33 +133,8 @@ public void previousServerIsFinished() {
116133

117134
public void transferTo(ServerType type) {
118135
new Thread(() -> {
119-
RegisteredServer originServer = playersOriginServer.get(player);
120-
if (originServer == null) {
121-
player.getCurrentServer().ifPresent(conn -> playersOriginServer.put(player, conn.getServer()));
122-
originServer = playersOriginServer.get(player);
123-
}
124-
ServerType originServerType = GameManager.getTypeFromRegisteredServer(originServer);
125-
126-
playersGoalServerType.remove(player);
127-
playersOriginServer.remove(player);
128-
129-
GameManager.GameServer server = BalanceConfigurations.getServerFor(player, type);
130-
131-
if (server == null) {
132-
player.disconnect(Component.text("§cThere are no Hypixel (type=" + type.name() + ") servers available at the moment."));
133-
return;
134-
}
135-
136-
if (originServer != null && originServerType != null) {
137-
RedisMessage.sendMessageToServer(server.internalID(),
138-
FromProxyChannels.GIVE_PLAYERS_ORIGIN_TYPE,
139-
new JSONObject().put("uuid", player.getUniqueId().toString())
140-
.put("origin-type", originServerType.name())
141-
);
142-
}
143-
144-
player.sendMessage(Component.text("§7Sending to server " + server.displayName() + "..."));
145-
player.createConnectionRequest(server.registeredServer()).connectWithIndication();
136+
playersGoalServerType.put(player, type);
137+
sendToLimbo().join();
146138
}).start();
147139
}
148140

velocity.extension/src/main/java/net/swofty/velocity/redis/listeners/ListenerServerFinishedWithPlayer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ public JSONObject receivedMessage(JSONObject message, UUID serverUUID) {
2424

2525
Player player = potentialPlayer.get();
2626
TransferHandler handler = new TransferHandler(player);
27+
if (!handler.isInLimbo()) {
28+
return new JSONObject();
29+
}
2730
handler.previousServerIsFinished();
2831

2932
return new JSONObject();

0 commit comments

Comments
 (0)