Skip to content

Commit cc00860

Browse files
committed
Handle missing inspect names and tighten UUID resolution
- Reuse a single "player not found" path in inspect command handling - Return null when a UUID cannot be mapped to a known name instead of showing the UUID - Resolve identifiers via cached offline players first, then Mojang, without offline UUID fallback
1 parent b2cc93c commit cc00860

2 files changed

Lines changed: 74 additions & 40 deletions

File tree

src/main/java/dev/noah/perplayerkit/commands/inspect/AbstractInspectCommand.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,7 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
9595
CompletableFuture<Void> future = resolvePlayerIdentifierAsync(args[0])
9696
.thenCompose(targetUuid -> {
9797
if (targetUuid == null) {
98-
Bukkit.getScheduler().runTask(plugin, () -> {
99-
BroadcastManager.get().sendComponentMessage(player,
100-
ERROR_PREFIX.append(
101-
mm.deserialize("<red>Could not find a player with that name or UUID.</red>")));
102-
SoundManager.playFailure(player);
103-
});
98+
Bukkit.getScheduler().runTask(plugin, () -> showPlayerNotFound(player));
10499
return CompletableFuture.completedFuture(null);
105100
}
106101

@@ -184,8 +179,20 @@ private void showInspectResult(Player inspector, UUID targetUuid, int slot) {
184179
}
185180

186181
String targetName = getPlayerName(targetUuid);
182+
if (targetName == null) {
183+
showPlayerNotFound(inspector);
184+
return;
185+
}
186+
187187
BroadcastManager.get().sendComponentMessage(inspector,
188188
ERROR_PREFIX.append(mm.deserialize(missingDataMessage(targetName, slot))));
189189
SoundManager.playFailure(inspector);
190190
}
191+
192+
private void showPlayerNotFound(Player player) {
193+
BroadcastManager.get().sendComponentMessage(player,
194+
ERROR_PREFIX.append(
195+
mm.deserialize("<red>Could not find a player with that name or UUID.</red>")));
196+
SoundManager.playFailure(player);
197+
}
191198
}

src/main/java/dev/noah/perplayerkit/commands/inspect/InspectCommandUtil.java

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import org.jetbrains.annotations.Nullable;
3232

3333
import java.io.IOException;
34-
import java.nio.charset.StandardCharsets;
3534
import java.util.UUID;
3635
import java.util.concurrent.CompletableFuture;
3736

@@ -48,7 +47,7 @@ private InspectCommandUtil() {
4847
/**
4948
* Attempts to resolve a player identifier (name or UUID) to a UUID asynchronously.
5049
* This method first tries to parse as UUID, then checks online players synchronously,
51-
* and finally searches offline players asynchronously.
50+
* and finally searches cached offline players and Mojang asynchronously.
5251
*
5352
* @param identifier Player name or UUID string
5453
* @return CompletableFuture containing UUID if found, null otherwise
@@ -68,53 +67,30 @@ public static CompletableFuture<UUID> resolvePlayerIdentifierAsync(String identi
6867
return CompletableFuture.completedFuture(onlinePlayer.getUniqueId());
6968
}
7069

71-
// Look up UUID via Mojang API (avoids the very slow Bukkit.getOfflinePlayers() scan)
7270
return CompletableFuture.supplyAsync(() -> {
73-
try {
74-
OkHttpClient client = new OkHttpClient();
75-
Request request = new Request.Builder()
76-
.url("https://api.mojang.com/users/profiles/minecraft/" + identifier)
77-
.build();
78-
Response response = client.newCall(request).execute();
79-
if (response.isSuccessful() && response.body() != null) {
80-
String body = response.body().string();
81-
// Parse the "id" field: {"id":"<uuid-no-dashes>","name":"<name>"}
82-
int idStart = body.indexOf("\"id\":\"") + 6;
83-
int idEnd = body.indexOf("\"", idStart);
84-
if (idStart > 5 && idEnd > idStart) {
85-
String raw = body.substring(idStart, idEnd);
86-
// Insert dashes into the 32-char UUID string
87-
String formatted = raw.substring(0, 8) + "-"
88-
+ raw.substring(8, 12) + "-"
89-
+ raw.substring(12, 16) + "-"
90-
+ raw.substring(16, 20) + "-"
91-
+ raw.substring(20);
92-
return UUID.fromString(formatted);
93-
}
94-
}
95-
} catch (IOException ignored) {
96-
// Fall through to offline UUID computation
71+
UUID cachedOfflinePlayer = findCachedOfflinePlayerUuid(identifier);
72+
if (cachedOfflinePlayer != null) {
73+
return cachedOfflinePlayer;
9774
}
98-
// Fallback for offline/cracked-mode servers: compute deterministic offline UUID
99-
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + identifier).getBytes(StandardCharsets.UTF_8));
75+
76+
return lookupPlayerUuidFromMojang(identifier);
10077
});
10178
}
10279

10380
/**
104-
* Gets a player's name from their UUID, falling back to UUID string if name is not available.
81+
* Gets a player's name from their UUID.
10582
*
10683
* @param uuid Player UUID
107-
* @return Player name or UUID string
84+
* @return Player name, or null if the UUID cannot be associated with a known player name
10885
*/
109-
public static String getPlayerName(@NotNull UUID uuid) {
86+
public static @Nullable String getPlayerName(@NotNull UUID uuid) {
11087
Player onlinePlayer = Bukkit.getPlayer(uuid);
11188
if (onlinePlayer != null) {
11289
return onlinePlayer.getName();
11390
}
11491

11592
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
116-
String name = offlinePlayer.getName();
117-
return name != null ? name : uuid.toString();
93+
return offlinePlayer.getName();
11894
}
11995

12096
/**
@@ -128,4 +104,55 @@ public static void showUsage(@NotNull Player player, @NotNull String commandName
128104
ERROR_PREFIX.append(
129105
mm.deserialize("<red>Usage: /" + commandName + " <player|uuid> <slot></red>")));
130106
}
107+
108+
private static @Nullable UUID findCachedOfflinePlayerUuid(@NotNull String identifier) {
109+
for (OfflinePlayer offlinePlayer : Bukkit.getOfflinePlayers()) {
110+
String name = offlinePlayer.getName();
111+
if (name != null && name.equalsIgnoreCase(identifier)) {
112+
return offlinePlayer.getUniqueId();
113+
}
114+
}
115+
return null;
116+
}
117+
118+
private static @Nullable UUID lookupPlayerUuidFromMojang(@NotNull String identifier) {
119+
try {
120+
OkHttpClient client = new OkHttpClient();
121+
Request request = new Request.Builder()
122+
.url("https://api.mojang.com/users/profiles/minecraft/" + identifier)
123+
.build();
124+
Response response = client.newCall(request).execute();
125+
try {
126+
if (!response.isSuccessful() || response.body() == null) {
127+
return null;
128+
}
129+
130+
String body = response.body().string();
131+
int idStart = body.indexOf("\"id\":\"");
132+
if (idStart < 0) {
133+
return null;
134+
}
135+
136+
idStart += 6;
137+
int idEnd = body.indexOf("\"", idStart);
138+
if (idEnd <= idStart) {
139+
return null;
140+
}
141+
142+
String raw = body.substring(idStart, idEnd);
143+
String formatted = raw.substring(0, 8) + "-"
144+
+ raw.substring(8, 12) + "-"
145+
+ raw.substring(12, 16) + "-"
146+
+ raw.substring(16, 20) + "-"
147+
+ raw.substring(20);
148+
return UUID.fromString(formatted);
149+
} finally {
150+
if (response.body() != null) {
151+
response.body().close();
152+
}
153+
}
154+
} catch (IOException | IllegalArgumentException ignored) {
155+
return null;
156+
}
157+
}
131158
}

0 commit comments

Comments
 (0)