Skip to content
Merged
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
39 changes: 21 additions & 18 deletions src/main/java/cn/alini/trueuuid/config/TrueuuidConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,39 +71,42 @@ public static final class Common {
b.push("auth");

timeoutMs = b.defineInRange("timeoutMs", 30_000L, 1_000L, 600_000L);
allowOfflineOnTimeout = b.comment("false: 超时踢出 / Kick on timeout. true: 超时放行为离线 / Allow offline fallback on timeout.").define("allowOfflineOnTimeout", false);
allowOfflineOnFailure = b.comment("false: 失败时踢出 / Kick on failure. true: 鉴权失败放行为离线 / Allow offline fallback on authentication failure.").define("allowOfflineOnFailure", true);
allowOfflineOnTimeout = b.comment("false: kick on timeout. true: allow offline fallback on timeout. / false: 超时踢出。true: 超时允许离线兜底。").define("allowOfflineOnTimeout", false);
allowOfflineOnFailure = b.comment("false: kick on authentication failure. true: allow offline fallback on authentication failure. / false: 鉴权失败时踢出。true: 鉴权失败时允许离线兜底。").define("allowOfflineOnFailure", true);

timeoutKickMessage = b.comment("Kick message on authentication timeout. Use a trueuuid.* translation key for client-side localization, or enter plain text to force a custom server message.")
timeoutKickMessage = b.comment("Kick message on authentication timeout. Use a trueuuid.* translation key for client-side localization, or enter plain text to force a custom server message. / 鉴权超时踢出消息。使用 trueuuid.* 翻译键可按客户端语言显示,也可填写纯文本强制使用服务器消息。")
.define("timeoutKickMessage", "trueuuid.disconnect.timeout");
offlineFallbackMessage = b.define(
offlineFallbackMessage = b.comment("Offline fallback chat message. Keep the default trueuuid.* key to use each player's game language. / 离线兜底聊天提示。保留默认 trueuuid.* 翻译键可按每个玩家的游戏语言显示。")
.define(
"offlineFallbackMessage",
"trueuuid.chat.offline_fallback"
);

// 默认短、不占屏 (Default short, does not occupy screen)
offlineShortSubtitle = b.define("offlineShortSubtitle", "trueuuid.subtitle.offline");
onlineShortSubtitle = b.define("onlineShortSubtitle", "trueuuid.subtitle.online");
showJoinFeedback = b.comment("是否在玩家进服后显示登录状态提示。/ Show join feedback after a player joins. 关闭后不再发送正版/皮肤站/离线/单人模式 Title,也不发送离线兜底聊天提示;不影响皮肤刷新和鉴权逻辑。/ When disabled, no premium/skin-site/offline/single-player Title or offline fallback chat message is sent; authentication and skin refresh are unchanged.")
// Default subtitles are short and localized by the client language.
offlineShortSubtitle = b.comment("Offline fallback subtitle. Keep the default trueuuid.* key to use each player's game language. / 离线兜底副标题。保留默认 trueuuid.* 翻译键可按每个玩家的游戏语言显示。")
.define("offlineShortSubtitle", "trueuuid.subtitle.offline");
onlineShortSubtitle = b.comment("Premium login subtitle. Keep the default trueuuid.* key to use each player's game language. / 正版登录副标题。保留默认 trueuuid.* 翻译键可按每个玩家的游戏语言显示。")
.define("onlineShortSubtitle", "trueuuid.subtitle.online");
showJoinFeedback = b.comment("Show join feedback after a player joins. When disabled, no premium/skin-site/offline/single-player title or offline fallback chat message is sent; authentication and skin refresh are unchanged. / 玩家进服后显示登录状态提示。关闭后不再发送正版、皮肤站、离线、单人模式标题,也不发送离线兜底聊天提示;不影响鉴权和皮肤刷新。")
.define("showJoinFeedback", true);

// 策略项 (Strategy items)
knownPremiumDenyOffline = b.comment("一旦该名字成功验证过正版/皮肤站,后续鉴权失败时禁止以离线身份进入。/ Once a name has been verified as premium/skin-site, deny later offline fallback for that name.")
knownPremiumDenyOffline = b.comment("Once a name has been verified as premium/skin-site, deny later offline fallback for that name. / 一旦该名字成功验证过正版或皮肤站,后续鉴权失败时禁止以离线身份进入。")
.define("knownPremiumDenyOffline", true);
allowOfflineForUnknownOnly = b.comment("仅对从未验证为正版/皮肤站的新名字允许离线兜底。/ Only allow offline fallback for names that have never been verified as premium/skin-site.")
allowOfflineForUnknownOnly = b.comment("Only allow offline fallback for names that have never been verified as premium/skin-site. / 仅对从未验证为正版或皮肤站的新名字允许离线兜底。")
.define("allowOfflineForUnknownOnly", true);
recentIpGraceEnabled = b.comment("启用“退出后同 IP 短时重连”容错,只在玩家退出后的 TTL 秒内临时沿用上次认证来源。/ Enable short same-IP reconnect grace after logout, reusing the last verified identity only within the TTL window.")
recentIpGraceEnabled = b.comment("Enable short same-IP reconnect grace after logout, reusing the last verified identity only within the TTL window. / 启用退出后同 IP 短时重连容错,只在 TTL 窗口内临时沿用上次认证身份。")
.define("recentIpGrace.enabled", true);
recentIpGraceTtlSeconds = b.comment("退出游戏后允许同 IP 容错重连的秒数。默认 10 秒,避免长期误导为皮肤站/正版登录。/ Same-IP grace seconds after logout. Default is 10 seconds to avoid long-lived misleading premium/skin-site identity.")
recentIpGraceTtlSeconds = b.comment("Same-IP grace seconds after logout. Default is 10 seconds to avoid long-lived misleading premium/skin-site identity. / 退出游戏后允许同 IP 容错重连的秒数。默认 10 秒,避免长期误导为正版或皮肤站登录。")
.defineInRange("recentIpGrace.ttlSeconds", 10, 1, 60);
debug = b.comment("启用调试日志输出。/ Enable debug logging.").define("debug", false);
debug = b.comment("Enable debug logging. / 启用调试日志输出。").define("debug", false);

apiRootWhitelist = b.comment(
"authlib-injector 皮肤站域名白名单。/ Whitelist for authlib-injector skin-site domains.",
"留空(默认)表示信任客户端上报的任何皮肤站 URL。/ Empty by default: trust any skin-site URL reported by the client.",
"配置后,只有 URL 中包含白名单条目的皮肤站才会被接受。/ When configured, only URLs containing a whitelist entry are accepted.",
"例如 / Example: [\"littleskin.cn\", \"skin.example.com\"]"
).defineListAllowEmpty(List.of("yggdrasil.apiRootWhitelist"), List::of, o -> o instanceof String);
"Whitelist for authlib-injector skin-site domains. / authlib-injector 皮肤站域名白名单。",
"Empty by default: trust any skin-site URL reported by the client. / 留空表示信任客户端上报的任何皮肤站 URL。",
"When configured, only skin-site hosts matching a whitelist entry are accepted. / 配置后,只有主机名匹配白名单条目的皮肤站才会被接受。",
"Example: [\"littleskin.cn\", \"skin.example.com\"] / 示例: [\"littleskin.cn\", \"skin.example.com\"]"
).defineListAllowEmpty(List.of("yggdrasil", "apiRootWhitelist"), List::of, o -> o instanceof String);

b.pop();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ public abstract class ClientHandshakeMixin {
Connection loginConnection = this.connection;
int transactionId = packet.getTransactionId();

if (offlineUpgradeAvailable && NetIds.MIGRATION_CONFIRM_SERVER_ID.equals(serverId)) {
trueuuid$confirmOfflinePlayerDataUpgrade(mc, offlineUuid, offlineDataSummary, "", loginConnection, transactionId);
ci.cancel();
return;
}

// dev/离线启动常见的占位 token 不可能通过 Mojang 校验,立即回失败,避免登录线程等到服务器超时。
if (trueuuid$isMissingSessionToken(token)) {
trueuuid$sendAuthAck(loginConnection, transactionId, false, "", false, true);
Expand Down
Loading