Skip to content

Commit beb7324

Browse files
committed
Store playfab ID as well, and store it on join instead of much later
1 parent 730325c commit beb7324

12 files changed

Lines changed: 136 additions & 85 deletions

File tree

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ plugins {
88
group = "org.geysermc.globallinkserver"
99

1010
dependencies {
11-
paperweight.paperDevBundle("1.21.8-R0.1-SNAPSHOT")
11+
paperweight.paperDevBundle("1.21.11-R0.1-SNAPSHOT")
1212

1313
compileOnly(libs.geyser.core)
1414
compileOnly(libs.floodgate.api)

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[versions]
2-
geyser = "2.8.4-SNAPSHOT"
2+
geyser = "2.9.4-SNAPSHOT"
33
floodgate = "2.2.3-SNAPSHOT"
44
hikari = "7.0.2"
55
postgresql = "42.7.8"

src/main/java/org/geysermc/globallinkserver/GlobalLinkServer.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021-2025 GeyserMC
2+
* Copyright (c) 2021-2026 GeyserMC
33
* Licensed under the MIT license
44
* @link https://github.com/GeyserMC/GlobalLinkServer
55
*/
@@ -43,6 +43,7 @@
4343
import org.geysermc.globallinkserver.manager.PlayerManager;
4444
import org.geysermc.globallinkserver.service.LinkInfoService;
4545
import org.geysermc.globallinkserver.service.LinkLookupService;
46+
import org.geysermc.globallinkserver.service.MappingService;
4647
import org.geysermc.globallinkserver.util.MultiConditionSet;
4748
import org.geysermc.globallinkserver.util.Utils;
4849

@@ -73,6 +74,7 @@ public void onEnable() {
7374
var linkManager = new LinkManager(playerManager, databaseManager);
7475
linkLookupService = new LinkLookupService(playerManager, databaseManager);
7576
linkInfoService = new LinkInfoService(linkLookupService, playerManager);
77+
var mappingService = new MappingService(databaseManager);
7678

7779
var commandUtils = new CommandHandler(linkLookupService, linkInfoService, linkManager, playerManager, this);
7880

@@ -83,7 +85,7 @@ public void onEnable() {
8385

8486
var pluginManager = getServer().getPluginManager();
8587
pluginManager.registerEvents(this, this);
86-
pluginManager.registerEvents(new JoinHandler(linkLookupService, playerIdleTracker, this), this);
88+
pluginManager.registerEvents(new JoinHandler(playerManager, linkLookupService, mappingService, playerIdleTracker, this), this);
8789
pluginManager.registerEvents(new MoveInactivityHandler(playerIdleTracker), this);
8890
pluginManager.registerEvents(new TeleportToSpawnHandler(config.spawn()), this);
8991

src/main/java/org/geysermc/globallinkserver/handler/CommandHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021-2025 GeyserMC
2+
* Copyright (c) 2021-2026 GeyserMC
33
* Licensed under the MIT license
44
* @link https://github.com/GeyserMC/GlobalLinkServer
55
*/
@@ -84,7 +84,7 @@ public int linkWithCode(CommandContext<CommandSourceStack> ctx) {
8484
}
8585

8686
String correctUsername = playerManager.correctUsername(player);
87-
Link completedLink = Link.fromRequest(linkRequest, player.getUniqueId(), correctUsername, playerManager.nameTimestampMillis(player), isRequesterBedrock);
87+
Link completedLink = Link.fromRequest(linkRequest, player.getUniqueId(), correctUsername, isRequesterBedrock);
8888

8989
linkManager.finaliseLink(completedLink).whenComplete((result, error) -> {
9090
if (error != null || !result) {

src/main/java/org/geysermc/globallinkserver/handler/JoinHandler.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2025 GeyserMC
2+
* Copyright (c) 2025-2026 GeyserMC
33
* Licensed under the MIT license
44
* @link https://github.com/GeyserMC/GlobalLinkServer
55
*/
@@ -11,19 +11,33 @@
1111
import org.bukkit.event.Listener;
1212
import org.bukkit.event.player.PlayerJoinEvent;
1313
import org.bukkit.plugin.Plugin;
14+
import org.geysermc.geyser.session.GeyserSession;
15+
import org.geysermc.geyser.session.auth.AuthData;
1416
import org.geysermc.globallinkserver.Components;
17+
import org.geysermc.globallinkserver.manager.PlayerManager;
1518
import org.geysermc.globallinkserver.service.LinkLookupService;
19+
import org.geysermc.globallinkserver.service.MappingService;
1620
import org.geysermc.globallinkserver.util.MultiConditionSet;
1721
import org.jspecify.annotations.NullMarked;
1822

1923
@NullMarked
2024
public final class JoinHandler implements Listener {
25+
private final PlayerManager playerManager;
2126
private final LinkLookupService linkLookupService;
27+
private final MappingService mappingService;
2228
private final MultiConditionSet<UUID> playerIdleTracker;
2329
private final Plugin plugin;
2430

25-
public JoinHandler(LinkLookupService linkLookupService, MultiConditionSet<UUID> playerIdleTracker, Plugin plugin) {
31+
public JoinHandler(
32+
PlayerManager playerManager,
33+
LinkLookupService linkLookupService,
34+
MappingService mappingService,
35+
MultiConditionSet<UUID> playerIdleTracker,
36+
Plugin plugin
37+
) {
38+
this.playerManager = playerManager;
2639
this.linkLookupService = linkLookupService;
40+
this.mappingService = mappingService;
2741
this.playerIdleTracker = playerIdleTracker;
2842
this.plugin = plugin;
2943
}
@@ -42,6 +56,23 @@ public void onPlayerJoin(PlayerJoinEvent event) {
4256
otherPlayer.hidePlayer(plugin, player);
4357
});
4458

59+
GeyserSession bedrockSession = playerManager.bedrockSession(player);
60+
if (bedrockSession != null) {
61+
AuthData authData = bedrockSession.getAuthData();
62+
mappingService.insertBedrockProfile(
63+
player.getUniqueId().getLeastSignificantBits(),
64+
authData.name(),
65+
authData.playFabId(),
66+
authData.issuedAt()
67+
);
68+
} else {
69+
long earliestKnownAt = player.getPlayerProfile().getTextures().getTimestamp();
70+
if (earliestKnownAt == 0) {
71+
earliestKnownAt = System.currentTimeMillis();
72+
}
73+
mappingService.insertJavaProfile(player.getUniqueId(), player.getName(), earliestKnownAt);
74+
}
75+
4576
playerIdleTracker.add(player.getUniqueId());
4677

4778
linkLookupService.lookup(player).whenComplete(($, throwable) -> {
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2025 GeyserMC
2+
* Copyright (c) 2025-2026 GeyserMC
33
* Licensed under the MIT license
44
* @link https://github.com/GeyserMC/GlobalLinkServer
55
*/
@@ -9,15 +9,15 @@
99
import org.jspecify.annotations.NullMarked;
1010

1111
@NullMarked
12-
public record Link(UUID javaId, String javaUsername, long javaNameTimestamp, long bedrockId, String bedrockName, long bedrockNameTimestamp) {
13-
public Link(UUID javaId, String javaUsername, long javaNameTimestamp, UUID bedrockId, String bedrockName, long bedrockNameTimestamp) {
14-
this(javaId, javaUsername, javaNameTimestamp, bedrockId.getLeastSignificantBits(), bedrockName, bedrockNameTimestamp);
12+
public record Link(UUID javaId, String javaUsername, long bedrockId, String bedrockName) {
13+
public Link(UUID javaId, String javaUsername, UUID bedrockId, String bedrockName) {
14+
this(javaId, javaUsername, bedrockId.getLeastSignificantBits(), bedrockName);
1515
}
1616

17-
public static Link fromRequest(LinkRequest left, UUID rightUuid, String rightUsername, long rightNameTimestamp, boolean isLeftBedrock) {
17+
public static Link fromRequest(LinkRequest left, UUID rightUuid, String rightUsername, boolean isLeftBedrock) {
1818
if (isLeftBedrock) {
19-
return new Link(rightUuid, rightUsername, rightNameTimestamp, left.requesterUuid(), left.requesterUsername(), left.nameTimestamp());
19+
return new Link(rightUuid, rightUsername, left.requesterUuid(), left.requesterUsername());
2020
}
21-
return new Link(left.requesterUuid(), left.requesterUsername(), left.nameTimestamp(), rightUuid, rightUsername, rightNameTimestamp);
21+
return new Link(left.requesterUuid(), left.requesterUsername(), rightUuid, rightUsername);
2222
}
2323
}

src/main/java/org/geysermc/globallinkserver/link/LinkManager.java

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021-2025 GeyserMC
2+
* Copyright (c) 2021-2026 GeyserMC
33
* Licensed under the MIT license
44
* @link https://github.com/GeyserMC/GlobalLinkServer
55
*/
@@ -12,8 +12,6 @@
1212
import java.sql.Connection;
1313
import java.sql.PreparedStatement;
1414
import java.sql.SQLException;
15-
import java.sql.Timestamp;
16-
import java.time.Instant;
1715
import java.util.Iterator;
1816
import java.util.Random;
1917
import java.util.UUID;
@@ -48,9 +46,8 @@ public LinkManager(PlayerManager playerManager, DatabaseManager database) {
4846
}
4947

5048
public int createTempLink(Player player) {
51-
long nameTimestamp = playerManager.nameTimestampMillis(player);
5249
String correctUsername = playerManager.correctUsername(player);
53-
var linkRequest = new LinkRequest(createCode(), PENDING_LINK_TTL_MILLIS, player.getUniqueId(), correctUsername, nameTimestamp);
50+
var linkRequest = new LinkRequest(createCode(), PENDING_LINK_TTL_MILLIS, player.getUniqueId(), correctUsername);
5451

5552
linkRequests.put(linkRequest.code(), linkRequest);
5653
linkRequestForPlayer.put(player.getUniqueId(), linkRequest.code());
@@ -102,32 +99,6 @@ public CompletableFuture<Boolean> finaliseLink(Link linkRequest) {
10299
return CompletableFuture.supplyAsync(
103100
() -> {
104101
try (Connection connection = database.connection()) {
105-
try (PreparedStatement query = connection.prepareStatement("""
106-
INSERT INTO java_identity_current AS c(id, username, detected_at)
107-
VALUES (?::uuid, ?, ?)
108-
ON CONFLICT (id) DO
109-
UPDATE SET username = EXCLUDED.username, detected_at = EXCLUDED.detected_at
110-
WHERE c.detected_at <= EXCLUDED.detected_at AND c.username != EXCLUDED.username
111-
""")) {
112-
query.setString(1, linkRequest.javaId().toString());
113-
query.setString(2, linkRequest.javaUsername());
114-
query.setTimestamp(3, Timestamp.from(Instant.EPOCH.plusMillis(linkRequest.javaNameTimestamp())));
115-
query.executeUpdate();
116-
}
117-
118-
try (PreparedStatement query = connection.prepareStatement("""
119-
INSERT INTO xbox_identity_current AS c(xuid, gamertag, detected_at)
120-
VALUES (?::xuid, ?, ?)
121-
ON CONFLICT (xuid) DO
122-
UPDATE SET gamertag = EXCLUDED.gamertag, detected_at = EXCLUDED.detected_at
123-
WHERE c.detected_at <= EXCLUDED.detected_at AND c.gamertag != EXCLUDED.gamertag
124-
""")) {
125-
query.setLong(1, linkRequest.bedrockId());
126-
query.setString(2, linkRequest.bedrockName());
127-
query.setTimestamp(3, Timestamp.from(Instant.EPOCH.plusMillis(linkRequest.bedrockNameTimestamp())));
128-
query.executeUpdate();
129-
}
130-
131102
try (PreparedStatement query = connection.prepareStatement("""
132103
INSERT INTO links (xuid, java_id)
133104
VALUES (?::xuid, ?::uuid)

src/main/java/org/geysermc/globallinkserver/link/LinkRequest.java

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021-2025 GeyserMC
2+
* Copyright (c) 2021-2026 GeyserMC
33
* Licensed under the MIT license
44
* @link https://github.com/GeyserMC/GlobalLinkServer
55
*/
@@ -18,14 +18,12 @@ public final class LinkRequest {
1818
private final long expiryTime;
1919
private final UUID requesterUuid;
2020
private final String requesterUsername;
21-
private final long nameTimestamp;
2221

23-
public LinkRequest(int code, long ttl, UUID requesterUuid, String requesterUsername, long nameTimestamp) {
22+
public LinkRequest(int code, long ttl, UUID requesterUuid, String requesterUsername) {
2423
this.code = code;
2524
this.expiryTime = System.nanoTime() + ttl;
2625
this.requesterUuid = requesterUuid;
2726
this.requesterUsername = requesterUsername;
28-
this.nameTimestamp = nameTimestamp;
2927
}
3028

3129
public @Nullable Player requester() {
@@ -48,10 +46,6 @@ public String requesterUsername() {
4846
return requesterUsername;
4947
}
5048

51-
public long nameTimestamp() {
52-
return nameTimestamp;
53-
}
54-
5549
@Override
5650
public boolean equals(Object obj) {
5751
if (obj == this) return true;
@@ -60,13 +54,12 @@ public boolean equals(Object obj) {
6054
return this.code == that.code &&
6155
this.expiryTime == that.expiryTime &&
6256
Objects.equals(this.requesterUuid, that.requesterUuid) &&
63-
Objects.equals(this.requesterUsername, that.requesterUsername) &&
64-
this.nameTimestamp == that.nameTimestamp;
57+
Objects.equals(this.requesterUsername, that.requesterUsername);
6558
}
6659

6760
@Override
6861
public int hashCode() {
69-
return Objects.hash(code, expiryTime, requesterUuid, requesterUsername, nameTimestamp);
62+
return Objects.hash(code, expiryTime, requesterUuid, requesterUsername);
7063
}
7164

7265
@Override
@@ -75,8 +68,7 @@ public String toString() {
7568
"code=" + code + ", " +
7669
"expiryTime=" + expiryTime + ", " +
7770
"requesterUuid=" + requesterUuid + ", " +
78-
"requesterUsername=" + requesterUsername + ", " +
79-
"nameTimestamp=" + nameTimestamp + ']';
71+
"requesterUsername=" + requesterUsername + ']';
8072
}
8173

8274
}

src/main/java/org/geysermc/globallinkserver/manager/DatabaseManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2025 GeyserMC
2+
* Copyright (c) 2025-2026 GeyserMC
33
* Licensed under the MIT license
44
* @link https://github.com/GeyserMC/GlobalLinkServer
55
*/

src/main/java/org/geysermc/globallinkserver/manager/PlayerManager.java

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2025 GeyserMC
2+
* Copyright (c) 2025-2026 GeyserMC
33
* Licensed under the MIT license
44
* @link https://github.com/GeyserMC/GlobalLinkServer
55
*/
@@ -36,7 +36,7 @@ public boolean isBedrockId(UUID id) {
3636
return api.getPlayer(uuid);
3737
}
3838

39-
private @Nullable GeyserSession bedrockSession(Player player) {
39+
public @Nullable GeyserSession bedrockSession(Player player) {
4040
// There is no linking in the linking server itself, only link management
4141
if (player.getUniqueId().getMostSignificantBits() != 0L) {
4242
return null;
@@ -58,25 +58,4 @@ public String correctUsername(Player player) {
5858
}
5959
return floodgatePlayer.getUsername();
6060
}
61-
62-
/**
63-
* Returns the earliest known time that the profile has this name.
64-
* Works for both Java and Bedrock accounts.
65-
*/
66-
public long nameTimestampMillis(Player player) {
67-
GeyserSession session = bedrockSession(player);
68-
if (session == null) {
69-
long timestamp = player.getPlayerProfile().getTextures().getTimestamp();
70-
if (timestamp == 0L) {
71-
return System.currentTimeMillis();
72-
}
73-
return timestamp;
74-
}
75-
76-
long issuedAt = session.getAuthData().issuedAt();
77-
if (issuedAt == -1) {
78-
return System.currentTimeMillis();
79-
}
80-
return issuedAt * 1000L;
81-
}
8261
}

0 commit comments

Comments
 (0)