diff --git a/README.en.md b/README.en.md index d3d8a51..de53d02 100644 --- a/README.en.md +++ b/README.en.md @@ -31,23 +31,47 @@ Configure Minecraft server with the following JVM parameter: ## Options ``` +-Dauthlibinjector.mojangNamespace={default|enabled|disabled} + Whether to enable Mojang namespace (@mojang suffix). + It's enabled by default if the authentication server does NOT send feature.no_mojang_namespace option. + + If enabled, virtual player @mojang will have the same skin as premium (Mojang) player . + For example, + - /give @p minecraft:skull 1 3 {SkullOwner:"Notch@mojang"} + - /npc skin Notch@mojang + will display Notch's skin. + + Note that the virtual player does NOT have the same UUID as its corresponding premium player. + To distinguish virtual players from actual ones, the most significant bit of time_hi_and_version is set to 1 (see RFC 4122 section 4.1.3). + For example: + 069a79f4-44e9-4726-a5be-fca90e38aaf5 Notch + 069a79f4-44e9-c726-a5be-fca90e38aaf5 Notch@mojang + We use this approach because, in RFC 4122, UUID version has only 6 possible values (0~5), which means the most significant is always 0. + In fact, Mojang uses version-4 (random) UUID, so its corresponding virtual player has a version-12 UUID. + -Dauthlibinjector.mojangProxy={proxy server URL} Use proxy when accessing Mojang authentication service. Only SOCKS protocol is supported. URL format: socks://: +-Dauthlibinjector.legacySkinPolyfill={default|enabled|disabled} + Whether to polyfill legacy skin API, namely 'GET /skins/MinecraftSkins/{username}.png'. + It's enabled by default if the authentication server does NOT send feature.legacy_skin_api option. + -Dauthlibinjector.debug (equals -Dauthlibinjector.debug=verbose,authlib) - or -Dauthlibinjector.debug= - Enable debug options. + or -Dauthlibinjector.debug={comma-separated debug options} Available debug options: - verbose enable verbose logging - authlib print logs from Mojang authlib - dumpClass dump modified classes - printUntransformed print classes that are analyzed but not transformed, implies 'verbose' + - verbose enable verbose logging + - authlib print logs from Mojang authlib + - dumpClass dump modified classes + - printUntransformed print classes that are analyzed but not transformed, implies 'verbose' -Dauthlibinjector.ignoredPackages={comma-separated package list} Ignore specified packages. Classes in these packages will not be analyzed or modified. -Dauthlibinjector.disableHttpd - Disable local HTTP server. Some features may not function properly. + Disable local HTTP server. + Features (see below) depending on local HTTP server will be unavailable: + - Mojang namespace + - Legacy skin API polyfill ``` diff --git a/README.md b/README.md index 544d516..19de8db 100644 --- a/README.md +++ b/README.md @@ -26,29 +26,53 @@ gradle ## 部署 通过添加以下 JVM 参数来配置: ``` --javaagent:{authlib-injector.jar 的路径}={验证服务器 URL(API 地址)} +-javaagent:{authlib-injector.jar 的路径}={验证服务器 URL (API 地址)} ``` ## 参数 ``` +-Dauthlibinjector.mojangNamespace={default|enabled|disabled} + 设置是否启用 Mojang 命名空间 (@mojang 后缀). + 若验证服务器未设置 feature.no_mojang_namespace 选项, 则该功能默认启用. + + 启用后, 则可以使用名为 @mojang 的虚拟角色来调用对应正版角色的皮肤. + 例如, + - /give @p minecraft:skull 1 3 {SkullOwner:"Notch@mojang"} + - /npc skin Notch@mojang + 显示的将会是 Notch 的皮肤. + + 注意, 虚拟角色和对应正版角色的 UUID 是不同的. 为了将虚拟角色和正版角色区别开, + 虚拟角色 UUID 中 time_hi_and_version 字段的最高位被置为 1 (见 RFC 4122 4.1.3 章节). + 例如: + 069a79f4-44e9-4726-a5be-fca90e38aaf5 Notch + 069a79f4-44e9-c726-a5be-fca90e38aaf5 Notch@mojang + 采用该方法的原因是, 在 RFC 4122 中 UUID 版本号只有 6 种可能的取值 (0~5), 版本号的最高位始终为 0. + 而实际上, Mojang 使用的是版本 4 (随机) UUID, 因此其对应的虚拟角色的 UUID 版本号为 12. + -Dauthlibinjector.mojangProxy={代理服务器 URL} - 设置访问 Mojang 验证服务时使用的代理,目前仅支持 SOCKS 协议 - URL 格式为 socks://: + 设置访问 Mojang 验证服务时使用的代理, 目前仅支持 SOCKS 协议. + URL 格式: socks://: + +-Dauthlibinjector.legacySkinPolyfill={default|enabled|disabled} + 是否启用旧式皮肤 API polyfill, 即 'GET /skins/MinecraftSkins/{username}.png'. + 若验证服务器未设置 feature.legacy_skin_api 选项, 则该功能默认启用. -Dauthlibinjector.debug (等价于 -Dauthlibinjector.debug=verbose,authlib) 或 -Dauthlibinjector.debug={调试选项; 逗号分隔} - 开启调试功能 - 可用的调试选项: - verbose 详细日志 - authlib 开启 Mojang authlib 的调试输出 - dumpClass 转储修改过的类 - printUntransformed 打印已分析但未修改的类,暗含 verbose + 可用的调试选项: + - verbose 详细日志 + - authlib 开启 Mojang authlib 的调试输出 + - dumpClass 转储修改过的类 + - printUntransformed 打印已分析但未修改的类; 隐含 verbose -Dauthlibinjector.ignoredPackages={包列表; 逗号分隔} - 忽略指定的包,其中的类将不会被分析或修改 + 忽略指定的包, 其中的类将不会被分析或修改. -Dauthlibinjector.disableHttpd - 禁用内建的 HTTP 服务器,可能导致部分功能不正常 + 禁用内建的 HTTP 服务器. + 以下依赖内建 HTTP 服务器的功能将不可用: + - Mojang 命名空间 + - 旧式皮肤 API polyfill ``` ## 捐助 diff --git a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java index adbf7c3..3b76025 100644 --- a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java +++ b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java @@ -209,6 +209,7 @@ public final class AuthlibInjector { private static List createFilters(APIMetadata config) { if (Config.httpdDisabled) { + log(INFO, "Disabled local HTTP server"); return emptyList(); } @@ -217,14 +218,20 @@ public final class AuthlibInjector { YggdrasilClient customClient = new YggdrasilClient(new CustomYggdrasilAPIProvider(config)); YggdrasilClient mojangClient = new YggdrasilClient(new MojangYggdrasilAPIProvider(), Config.mojangProxy); - if (Boolean.TRUE.equals(config.getMeta().get("feature.legacy_skin_api"))) { - log(INFO, "Disabled local redirect for legacy skin API, as the remote Yggdrasil server supports it"); - } else { + boolean legacySkinPolyfillDefault = !Boolean.TRUE.equals(config.getMeta().get("feature.legacy_skin_api")); + if (Config.legacySkinPolyfill.isEnabled(legacySkinPolyfillDefault)) { filters.add(new LegacySkinAPIFilter(customClient)); + } else { + log(INFO, "Disabled legacy skin API polyfill"); } - filters.add(new QueryUUIDsFilter(mojangClient, customClient)); - filters.add(new QueryProfileFilter(mojangClient, customClient)); + boolean mojangNamespaceDefault = !Boolean.TRUE.equals(config.getMeta().get("feature.no_mojang_namespace")); + if (Config.mojangNamespace.isEnabled(mojangNamespaceDefault)) { + filters.add(new QueryUUIDsFilter(mojangClient, customClient)); + filters.add(new QueryProfileFilter(mojangClient, customClient)); + } else { + log(INFO, "Disabled Mojang namespace"); + } return filters; } diff --git a/src/main/java/moe/yushi/authlibinjector/Config.java b/src/main/java/moe/yushi/authlibinjector/Config.java index 9ada876..eaa7675 100644 --- a/src/main/java/moe/yushi/authlibinjector/Config.java +++ b/src/main/java/moe/yushi/authlibinjector/Config.java @@ -32,53 +32,33 @@ import java.util.regex.Pattern; public final class Config { /* - * -Dauthlibinjector.mojangProxy={proxy server URL} + * See readme for option details. * - * Use proxy when accessing Mojang authentication service. - * Only SOCKS protocol is supported. - * URL format: socks://: - */ - - /* - * -Dauthlibinjector.debug (equals -Dauthlibinjector.debug=verbose,authlib) - * or -Dauthlibinjector.debug= - * - * Available debug options: - * - verbose ; enable verbose logging - * - authlib ; print logs from Mojang authlib - * - dumpClass ; dump modified classes - * - printUntransformed ; print classes that are analyzed but not transformed, implies 'verbose' - * - * Specially, for backward compatibility, -Dauthlibinjector.debug=all equals -Dauthlibinjector.debug - */ - - /* - * -Dauthlibinjector.ignoredPackages={comma-separated package list} - * - * Ignore specified packages. Classes in these packages will not be analyzed or modified. - */ - - /* - * -Dauthlibinjector.disableHttpd - * - * Disable local HTTP server. Some features may not function properly. - */ - - /* * Deprecated options: - * -Dauthlibinjector.debug=all ; use -Dauthlibinjector.debug instead - * -Dauthlibinjector.mojang.proxy=... ; use -Dauthlibinjector.mojangProxy=... instead + * -Dauthlibinjector.debug=all + * replaced by -Dauthlibinjector.debug + * -Dauthlibinjector.mojang.proxy=... + * replaced by -Dauthlibinjector.mojangProxy=... */ private Config() {} + public static enum FeatureOption { + DEFAULT, ENABLED, DISABLED; + public boolean isEnabled(boolean defaultValue) { + return this == DEFAULT ? defaultValue : this == ENABLED; + } + } + public static boolean verboseLogging; public static boolean authlibLogging; public static boolean printUntransformedClass; public static boolean dumpClass; public static boolean httpdDisabled; - public static Proxy mojangProxy; + public static /* nullable */ Proxy mojangProxy; public static Set ignoredPackages; + public static FeatureOption mojangNamespace; + public static FeatureOption legacySkinPolyfill; private static void initDebugOptions() { String prop = System.getProperty("authlibinjector.debug"); @@ -201,10 +181,26 @@ public final class Config { log(INFO, "Mojang proxy: " + mojangProxy); } + private static FeatureOption parseFeatureOption(String property) { + String prop = System.getProperty(property); + if (prop == null) { + return FeatureOption.DEFAULT; + } + try { + return FeatureOption.valueOf(prop.toUpperCase()); + } catch (IllegalArgumentException e) { + log(ERROR, "Invalid option: " + prop); + throw new InitializationException(e); + } + } + static void init() { initDebugOptions(); initIgnoredPackages(); - httpdDisabled = System.getProperty("-Dauthlibinjector.disableHttpd") != null; initMojangProxy(); + + mojangNamespace = parseFeatureOption("authlibinjector.mojangNamespace"); + legacySkinPolyfill = parseFeatureOption("authlibinjector.legacySkinPolyfill"); + httpdDisabled = System.getProperty("authlibinjector.disableHttpd") != null; } }