Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/main/java/cn/alini/trueuuid/Trueuuid.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,24 @@ public class Trueuuid {
private static final Logger LOGGER = LogUtils.getLogger();

public Trueuuid() {
// 注册并生成 config/trueuuid-common.toml
// 注册并生成 config/trueuuid-common.toml (Register and generate config/trueuuid-common.toml)
TrueuuidConfig.register();

// 初始化运行时单例(注册表、最近 IP 容错缓存等)
// 初始化运行时单例(注册表、最近 IP 容错缓存等) (Initialize runtime singleton (registry, recent IP grace cache, etc.))
TrueuuidRuntime.init();

// =====MoJang网络连通性测试=====
// 若开启 nomojang,则跳过启动时的 Mojang 网络连通性检测
// ===== MoJang网络连通性测试 (Mojang Network Connectivity Test)=====
// 若开启 nomojang,则跳过启动时的 Mojang 网络连通性检测 (If nomojang is enabled, skip Mojang network connectivity check at startup)
if (TrueuuidConfig.nomojangEnabled()) {
LOGGER.info("nomojang 已启用,跳过 Mojang 会话服务器连通性检测");
} else {
// =====MoJang网络连通性测试=====
// ===== MoJang网络连通性测试 (Mojang Network Connectivity Test )=====
try {
String testUrl = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=Mojang&serverId=test";
java.net.URL url = new java.net.URL(testUrl);
java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(3000); // 3秒超时
conn.setConnectTimeout(3000); // 3秒超时 (3 seconds timeout)
conn.setReadTimeout(3000);
conn.connect();

Expand Down
11 changes: 7 additions & 4 deletions src/main/java/cn/alini/trueuuid/api/TrueuuidApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,24 @@

/**
* TrueUUID API: 提供正版状态查询接口,供附属mod调用。
* (TrueUUID API: Provides premium status query interface for addon mods to call.)
*/
public class TrueuuidApi {
/**
* 判断指定玩家名称是否已被TrueUUID判定为正版。
* @param name 玩家名称(不区分大小写)
* @return 如果已被判定为正版,返回true,否则返回false。
* (Determines whether the specified player name has been determined as premium by TrueUUID.)
* @param name 玩家名称(不区分大小写) (Player name (case-insensitive))
* @return 如果已被判定为正版,返回true,否则返回false。 (Returns true if determined as premium, otherwise false.)
*/
public static boolean isPremium(String name) {
return TrueuuidRuntime.NAME_REGISTRY.isKnownPremiumName(name);
}

/**
* 获取指定玩家名称对应的正版UUID(如有)。
* @param name 玩家名称(不区分大小写)
* @return 如果有正版UUID,返回UUID,否则返回null。
* (Gets the premium UUID corresponding to the specified player name (if any).)
* @param name 玩家名称(不区分大小写) (Player name (case-insensitive))
* @return 如果有正版UUID,返回UUID,否则返回null。 (Returns UUID if there is a premium UUID, otherwise null.)
*/
public static UUID getPremiumUuid(String name) {
return TrueuuidRuntime.NAME_REGISTRY.getPremiumUuid(name).orElse(null);
Expand Down
60 changes: 30 additions & 30 deletions src/main/java/cn/alini/trueuuid/command/TrueuuidCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static void onRegister(RegisterCommandsEvent e) {
CommandDispatcher<CommandSourceStack> d = e.getDispatcher();
d.register(Commands.literal("trueuuid")
.requires(src -> src.hasPermission(3))
// 新增:/trueuuid mojang status
// 新增(Added):/trueuuid mojang status
.then(Commands.literal("config")
.requires(src -> src.hasPermission(3))
.then(Commands.literal("nomojang")
Expand Down Expand Up @@ -91,24 +91,24 @@ public static void onRegister(RegisterCommandsEvent e) {

}

// 新增方法:runtime 从磁盘重载配置并将值写入 TrueuuidConfig.COMMON
// 新增方法:runtime 从磁盘重载配置并将值写入 TrueuuidConfig.COMMON (Added method: runtime reload config from disk and write values to TrueuuidConfig.COMMON)
private static int cmdConfigReload(CommandSourceStack src) {
try {
Path cfgPath = FMLPaths.CONFIGDIR.get().resolve("trueuuid-common.toml");
CommentedFileConfig cfg = CommentedFileConfig.builder(cfgPath)
.sync() // 与磁盘保持同步
.sync() // 与磁盘保持同步 (Sync with disk)
.autosave()
.build();
cfg.load();

// 辅助读取函数:优先读取 auth.xxx,其次尝试不带 auth 前缀的样式(兼容不同定义位置)
// 辅助读取函数:优先读取 auth.xxx,其次尝试不带 auth 前缀的样式(兼容不同定义位置) (Helper read function: Prioritize reading auth.xxx, then try style without auth prefix (compatible with different definition locations))
java.util.function.BiFunction<String, String, Object> getVal = (authKey, altKey) -> {
if (cfg.contains(authKey)) return cfg.get(authKey);
if (altKey != null && cfg.contains(altKey)) return cfg.get(altKey);
return null;
};

// 布尔项
// 布尔项 (Boolean items)
Object v;
v = getVal.apply("auth.nomojang.enabled", "nomojang.enabled");
if (v instanceof Boolean) TrueuuidConfig.COMMON.nomojangEnabled.set((Boolean) v);
Expand All @@ -131,14 +131,14 @@ private static int cmdConfigReload(CommandSourceStack src) {
v = getVal.apply("auth.allowOfflineOnFailure", "allowOfflineOnFailure");
if (v instanceof Boolean) TrueuuidConfig.COMMON.allowOfflineOnFailure.set((Boolean) v);

// 数值项
// 数值项 (Numeric items)
v = getVal.apply("auth.timeoutMs", "timeoutMs");
if (v instanceof Number) TrueuuidConfig.COMMON.timeoutMs.set(((Number) v).longValue());

v = getVal.apply("auth.recentIpGrace.ttlSeconds", "recentIpGrace.ttlSeconds");
if (v instanceof Number) TrueuuidConfig.COMMON.recentIpGraceTtlSeconds.set(((Number) v).intValue());

// 字符串项
// 字符串项 (String items)
v = getVal.apply("auth.timeoutKickMessage", "timeoutKickMessage");
if (v != null) TrueuuidConfig.COMMON.timeoutKickMessage.set(String.valueOf(v));

Expand All @@ -151,7 +151,7 @@ private static int cmdConfigReload(CommandSourceStack src) {
v = getVal.apply("auth.onlineShortSubtitle", "onlineShortSubtitle");
if (v != null) TrueuuidConfig.COMMON.onlineShortSubtitle.set(String.valueOf(v));

// 完成反馈
// 完成反馈 (Completion feedback)
src.sendSuccess(() -> Component.literal("[TrueUUID] 配置已从磁盘重载").withStyle(net.minecraft.ChatFormatting.GREEN), false);
return 1;
} catch (Exception ex) {
Expand All @@ -160,7 +160,7 @@ private static int cmdConfigReload(CommandSourceStack src) {
}
}

// 以下方法加入到 `TrueuuidCommands` 类中(同一文件)
// 以下方法加入到 `TrueuuidCommands` 类中(同一文件) (The following methods are added to `TrueuuidCommands` class (same file))
private static int cmdNomojangStatus(CommandSourceStack src) {
boolean enabled = TrueuuidConfig.nomojangEnabled();
if (enabled) {
Expand All @@ -174,7 +174,7 @@ private static int cmdNomojangStatus(CommandSourceStack src) {
private static int cmdNomojangSet(CommandSourceStack src, boolean value) {
try {
TrueuuidConfig.COMMON.nomojangEnabled.set(value);
// 运行时也可记录日志
// 运行时也可记录日志 (Can also log at runtime)
src.sendSuccess(() -> Component.literal("[TrueUUID] NoMojang 已" + (value ? "启用" : "禁用"))
.withStyle(value ? net.minecraft.ChatFormatting.GREEN : net.minecraft.ChatFormatting.RED), false);
return 1;
Expand Down Expand Up @@ -263,24 +263,24 @@ private static int run(CommandSourceStack src, String name,
copyIfExists(offStats, backupDir.resolve("offline.stats.json"));
}

// ==== NBT 合并实现 ====
// ==== NBT 合并实现 (Merge Implementation) ====
if (Files.exists(offDat)) {
if (!Files.exists(premDat)) {
Files.move(offDat, premDat, StandardCopyOption.REPLACE_EXISTING);
} else {
// 合并 NBT(背包/末影箱)
// 合并 NBT(背包/末影箱) (Merge NBT (Inventory/EnderChest))
mergePlayerDatNBT(premDat, offDat, mergeInv, mergeEnder);
}
}
// ==== advancements 合并实现 ====
// ==== advancements 合并实现 (Merge Implementation) ====
if (Files.exists(offAdv)) {
if (!Files.exists(premAdv)) {
Files.move(offAdv, premAdv, StandardCopyOption.REPLACE_EXISTING);
} else {
mergeAdvancementsJson(premAdv, offAdv);
}
}
// ==== stats 合并实现 ====
// ==== stats 合并实现 (Merge Implementation) ====
if (Files.exists(offStats)) {
if (!Files.exists(premStats)) {
Files.move(offStats, premStats, StandardCopyOption.REPLACE_EXISTING);
Expand All @@ -299,13 +299,13 @@ private static int run(CommandSourceStack src, String name,
}

private static Optional<NameRegistry.Entry> getEntry(String name) {
// 仅供命令打印 premium,用不到其它字段时可改为直接 getPremiumUuid
// 仅供命令打印 premium,用不到其它字段时可改为直接 getPremiumUuid (Only for command printing premium, can be changed to direct getPremiumUuid when other fields are not used)
try {
var f = NameRegistry.class.getDeclaredField("map");
f.setAccessible(true);
} catch (Throwable ignored) {
}
// 简化:复用 getPremiumUuid,并构造一个 Entry
// 简化:复用 getPremiumUuid,并构造一个 Entry (Simplify: Reuse getPremiumUuid and construct an Entry)
return TrueuuidRuntime.NAME_REGISTRY.getPremiumUuid(name).map(u -> {
NameRegistry.Entry e = new NameRegistry.Entry();
e.premiumUuid = u;
Expand All @@ -320,7 +320,7 @@ private static void copyIfExists(Path from, Path to) throws Exception {
}
}

// --- NBT合并:背包/末影箱 ---
// --- NBT合并:背包/末影箱 (NBT Merge: Inventory/EnderChest) ---
private static void mergePlayerDatNBT(Path premDat, Path offDat, boolean mergeInv, boolean mergeEnder) throws Exception {
CompoundTag prem, off;
try (InputStream is = Files.newInputStream(premDat)) {
Expand All @@ -345,12 +345,12 @@ private static void mergePlayerDatNBT(Path premDat, Path offDat, boolean mergeIn
}
}

// 合并规则:以 premium 为主,offline中未出现的item补到后面(不会覆盖原物品槽号)
// 合并规则:以 premium 为主,offline中未出现的item补到后面(不会覆盖原物品槽号) (Merge rule: Premium is primary, items not appearing in offline are appended (will not overwrite original item slot numbers))
private static boolean mergeItemListTag(CompoundTag prem, CompoundTag off, String key) {
if (!prem.contains(key) || !off.contains(key)) return false;
ListTag premList = prem.getList(key, 10); // 10: CompoundTag
ListTag offList = off.getList(key, 10);
// 以槽号为主键
// 以槽号为主键 (Slot number as primary key)
Set<Integer> premSlots = new HashSet<>();
for (int i = 0; i < premList.size(); ++i) {
CompoundTag tag = premList.getCompound(i);
Expand All @@ -373,7 +373,7 @@ private static boolean mergeItemListTag(CompoundTag prem, CompoundTag off, Strin
return changed;
}

// --- advancements 合并:并集 ---
// --- advancements 合并:并集 (Advancements Merge: Union) ---
private static void mergeAdvancementsJson(Path premAdv, Path offAdv) throws Exception {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonObject prem, off;
Expand All @@ -397,7 +397,7 @@ private static void mergeAdvancementsJson(Path premAdv, Path offAdv) throws Exce
}
}

// 更健壮的 mergeStatsJson 实现,处理 JsonElement 类型差异,避免 ClassCastException
// 更健壮的 mergeStatsJson 实现,处理 JsonElement 类型差异,避免 ClassCastException (More robust mergeStatsJson implementation, handling JsonElement type differences to avoid ClassCastException)
private static void mergeStatsJson(Path premStats, Path offStats) throws Exception {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonObject prem, off;
Expand All @@ -411,7 +411,7 @@ private static void mergeStatsJson(Path premStats, Path offStats) throws Excepti

for (String cat : off.keySet()) {
JsonElement offElem = off.get(cat);
// 如果 premium 中没有该分类,直接拷贝整个元素(无论类型)
// 如果 premium 中没有该分类,直接拷贝整个元素(无论类型) (If premium does not have this category, copy the entire element directly (regardless of type))
if (!prem.has(cat)) {
prem.add(cat, offElem);
changed = true;
Expand All @@ -420,7 +420,7 @@ private static void mergeStatsJson(Path premStats, Path offStats) throws Excepti

JsonElement premElem = prem.get(cat);

// 两边都是对象 -> 逐条合并(数值累加,非数值保留 premium)
// 两边都是对象 -> 逐条合并(数值累加,非数值保留 premium) (Both are objects -> Merge item by item (accumulate numbers, keep premium for non-numbers))
if (offElem.isJsonObject() && premElem.isJsonObject()) {
JsonObject offCat = offElem.getAsJsonObject();
JsonObject premCat = premElem.getAsJsonObject();
Expand All @@ -431,7 +431,7 @@ private static void mergeStatsJson(Path premStats, Path offStats) throws Excepti
changed = true;
} else {
JsonElement premVal = premCat.get(key);
// 尝试对原语数值做累加
// 尝试对原语数值做累加 (Try to accumulate primitive numbers)
if (premVal.isJsonPrimitive() && offVal.isJsonPrimitive()) {
JsonPrimitive pPri = premVal.getAsJsonPrimitive();
JsonPrimitive oPri = offVal.getAsJsonPrimitive();
Expand All @@ -442,17 +442,17 @@ private static void mergeStatsJson(Path premStats, Path offStats) throws Excepti
premCat.addProperty(key, a + b);
changed = true;
} catch (Exception ignored) {
// 若不能以 long 累加则保持 premium 原值
// 若不能以 long 累加则保持 premium 原值 (If cannot accumulate as long, keep premium original value)
}
}
}
// 其他类型(数组/对象/非数值原语)优先保留 prem,不覆盖
// 其他类型(数组/对象/非数值原语)优先保留 prem,不覆盖 (Other types (array/object/non-numeric primitive) prioritize keeping prem, do not overwrite)
}
}
prem.add(cat, premCat);
} else {
// 类型不一致或都不是对象:
// 若两边都是原语且为数字,则尝试累加(例如少见的数值统计)
// 类型不一致或都不是对象: (Types inconsistent or neither are objects:)
// 若两边都是原语且为数字,则尝试累加(例如少见的数值统计) (If both are primitives and numbers, try to accumulate (e.g. rare numeric stats))
if (premElem.isJsonPrimitive() && offElem.isJsonPrimitive()) {
JsonPrimitive pPri = premElem.getAsJsonPrimitive();
JsonPrimitive oPri = offElem.getAsJsonPrimitive();
Expand All @@ -463,11 +463,11 @@ private static void mergeStatsJson(Path premStats, Path offStats) throws Excepti
prem.addProperty(cat, a + b);
changed = true;
} catch (Exception ignored) {
// 不可累加则保留 prem
// 不可累加则保留 prem (Cannot accumulate, keep prem)
}
}
}
// 其余情况(类型不一致且 prem 已存在)保持 prem,不覆盖
// 其余情况(类型不一致且 prem 已存在)保持 prem,不覆盖 (Other cases (types inconsistent and prem exists) keep prem, do not overwrite)
}
}

Expand Down
Loading