mirror of
https://github.com/System-End/Discord-MC-Chat.git
synced 2026-04-19 19:45:14 +00:00
feat: persist offline player name in LinkEntry for proper display in links command
Add offlinePlayerName field to LinkEntry record, stored only for offline-mode UUIDs (version 3) since Mojang API cannot resolve them. Online-mode players continue to use real-time Mojang API resolution. The field is omitted from JSON when null for clean serialization. MojangUtils.resolvePlayerName() now accepts an optional fallback name for offline UUIDs, returning "N/A" when no name is available. Updated README.md storage constraints and query display rules to reflect the new offline player name persistence. Co-authored-by: Xujiayao <58985541+Xujiayao@users.noreply.github.com>
This commit is contained in:
parent
b2f841e1fa
commit
7afea647a5
4 changed files with 52 additions and 10 deletions
|
|
@ -62,8 +62,9 @@ DMCC 所有运行模式都基于一个统一的通信模型,该模型包含两
|
|||
- **一个 Discord 账户可关联多个 Minecraft 账户**(方便玩家管理大号与小号)。
|
||||
- **一个 Minecraft 账户只能关联一个 Discord 账户**(确保游戏内身份的绝对唯一性)。
|
||||
- **数据持久化**: 绑定关系作为永久数据存储在 `Server` 端的 `account_linking/links.json` 中,以 Discord ID 为主键。
|
||||
- **存储约束**: `links.json` 中仅存储绑定关系最小必要字段(Discord ID、Minecraft UUID、添加时间),**不得额外存储**
|
||||
Discord 用户名或 Minecraft 玩家名;显示名称在查询时实时解析。
|
||||
- **存储约束**: `links.json` 中存储绑定关系最小必要字段(Discord ID、Minecraft UUID、添加时间)。对于离线模式玩家,
|
||||
额外存储 `offlinePlayerName`(绑定时的玩家名),因为离线 UUID 无法通过 Mojang API 反查玩家名。
|
||||
在线模式玩家不存储玩家名,显示名称在查询时通过 Mojang API 实时解析。Discord 用户名始终不存储,查询时实时解析。
|
||||
|
||||
### 4.2 安全绑定工作流 (严格的 MC 优先原则)
|
||||
|
||||
|
|
@ -82,7 +83,8 @@ DMCC 所有运行模式都基于一个统一的通信模型,该模型包含两
|
|||
|
||||
- **Discord `/unlink`**: 直接取消该 Discord 用户名下的所有 Minecraft 绑定(无需二次确认)。
|
||||
- **Minecraft `/dmcc unlink`**: 直接取消“当前执行玩家”对应的绑定关系(无需二次确认)。
|
||||
- **查询展示规则**: `links` 查询时实时解析显示名称,若无法解析则回退显示 UUID / Discord ID。
|
||||
- **查询展示规则**: `links` 查询时实时解析显示名称;在线模式玩家通过 Mojang API 解析,离线模式玩家使用绑定时记录的玩家名。
|
||||
若无法解析则显示 "N/A"(Minecraft 玩家名)或 Discord ID。
|
||||
|
||||
### 4.4 同步与跨平台交互
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public class LinksCommand implements Command {
|
|||
|
||||
for (LinkedAccountManager.LinkEntry link : links) {
|
||||
String time = DATE_FORMATTER.format(Instant.ofEpochMilli(link.linkedAt()));
|
||||
String mcName = MojangUtils.resolvePlayerName(link.minecraftUuid());
|
||||
String mcName = MojangUtils.resolvePlayerName(link.minecraftUuid(), link.offlinePlayerName());
|
||||
builder.append("\n - MC: ").append(mcName).append(" (").append(link.minecraftUuid()).append(")");
|
||||
builder.append(" (").append(time).append(")");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.xujiayao.discord_mc_chat.server.linking;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
|
@ -151,7 +153,7 @@ public class LinkedAccountManager {
|
|||
}
|
||||
|
||||
LINKED_ACCOUNTS.computeIfAbsent(discordId, k -> new ArrayList<>())
|
||||
.add(new LinkEntry(minecraftUuid, System.currentTimeMillis()));
|
||||
.add(new LinkEntry(minecraftUuid, System.currentTimeMillis(), isOfflineUuid(minecraftUuid) ? minecraftName : null));
|
||||
UUID_TO_DISCORD.put(minecraftUuid, discordId);
|
||||
|
||||
LOGGER.info(I18nManager.getDmccTranslation("linking.manager.linked", discordName, discordId, minecraftName, minecraftUuid));
|
||||
|
|
@ -260,12 +262,32 @@ public class LinkedAccountManager {
|
|||
return Collections.unmodifiableMap(LINKED_ACCOUNTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a Minecraft UUID is an offline-mode UUID (version 3).
|
||||
*
|
||||
* @param uuidString The UUID string.
|
||||
* @return true if the UUID is offline-mode (version 3), false otherwise.
|
||||
*/
|
||||
private static boolean isOfflineUuid(String uuidString) {
|
||||
try {
|
||||
return UUID.fromString(uuidString).version() == 3;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A linked Minecraft account entry.
|
||||
*
|
||||
* @param minecraftUuid The UUID of the linked Minecraft account.
|
||||
* @param linkedAt The timestamp (epoch millis) when the link was created.
|
||||
* @param minecraftUuid The UUID of the linked Minecraft account.
|
||||
* @param linkedAt The timestamp (epoch millis) when the link was created.
|
||||
* @param offlinePlayerName The player name stored at link time for offline-mode UUIDs only.
|
||||
* {@code null} for online-mode players (resolvable via Mojang API).
|
||||
*/
|
||||
public record LinkEntry(String minecraftUuid, long linkedAt) {
|
||||
public record LinkEntry(
|
||||
String minecraftUuid,
|
||||
long linkedAt,
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) String offlinePlayerName
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,22 @@ public class MojangUtils {
|
|||
* @return The resolved player name, or the original UUID string if resolution fails.
|
||||
*/
|
||||
public static String resolvePlayerName(String uuidString) {
|
||||
return resolvePlayerName(uuidString, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a Minecraft player name from a UUID string, with an optional fallback name
|
||||
* for offline-mode UUIDs.
|
||||
* <p>
|
||||
* If the UUID is an offline-mode UUID (version 3), {@code offlineFallbackName} is returned
|
||||
* if non-null; otherwise "N/A" is returned. For online-mode UUIDs (version 4), the Mojang
|
||||
* session server is queried. Network failures fall back to the raw UUID.
|
||||
*
|
||||
* @param uuidString The UUID string (standard dashed format).
|
||||
* @param offlineFallbackName The player name to use for offline UUIDs, or null.
|
||||
* @return The resolved player name, or the fallback/"N/A"/UUID string if resolution fails.
|
||||
*/
|
||||
public static String resolvePlayerName(String uuidString, String offlineFallbackName) {
|
||||
String cached = NAME_CACHE.get(uuidString);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
|
|
@ -44,8 +60,10 @@ public class MojangUtils {
|
|||
// Check if this is an offline-mode UUID (version 3)
|
||||
if (uuid.version() == 3) {
|
||||
// Offline UUIDs are generated from "OfflinePlayer:" + name
|
||||
// We cannot reverse this, so return the raw UUID
|
||||
return uuidString;
|
||||
// We cannot reverse this, so use the fallback name or "N/A"
|
||||
String name = (offlineFallbackName != null) ? offlineFallbackName : "N/A";
|
||||
NAME_CACHE.put(uuidString, name);
|
||||
return name;
|
||||
}
|
||||
|
||||
// Online UUID (version 4) - query Mojang
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue