使用YACL Config API自动将功能开关状态保存到文件内

使用文件系统监听器使配置文件被外部更改时可以自动重载到游戏内
解决直接连接窗口内输入框里的服务器IP没有被移除空格处理的问题
在移除空格之后打印日志
添加英文README
重新给main入口类添加`@Deprecated`标记,这东西确实用不到,后面看要不要直接删了
为AI Agent添加AGENTS.md文件以指示通用提示词
This commit is contained in:
TheWhiteDog9487
2026-06-04 11:42:35 +08:00
committed by TheWhiteDog9487
parent 5cb7a45ff4
commit 92d1e282d8
17 changed files with 289 additions and 65 deletions

6
AGENTS.md Normal file
View File

@@ -0,0 +1,6 @@
- 如果需要Minecraft经过反混淆的源码直接在`.gradle/loom-cache/minecraftMaven/net/minecraft`目录下查找。
- 源码使用完成之后记得删除解压jar产生的临时文件
- 使用帕斯卡命名法
- 如果你是正在翻译README的LLM请遵守README内使用注释编写的指令

View File

@@ -1,10 +1,24 @@
[//]: # (如果你是正在执行翻译任务的LLM)
[//]: # (请将这几行注释内容翻译到你的目标语言)
[//]: # (移除下方div内部第一行和第二行的注释符号并翻译其内容)
[//]: # (不要翻译最后一段“一些小彩蛋”,直接将其从翻译版本中移除)
<div align="center">
<!-- <strong>注意:本文档由中文编写。如果条件允许,建议阅读原始的中文文档而不是其他的翻译版本。</strong> -->
<!-- <br/> -->
<a href="https://github.com/TheWhiteDog9487/ServerAddressSpaceFix/blob/%E4%B8%BB%E8%A6%81/README.md">简体中文GitHub</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://git.thewhitedog9487.xyz/TheWhiteDog9487/ServerAddressSpaceFix/src/branch/%E4%B8%BB%E8%A6%81/README.md">简体中文Gitea</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://github.com/TheWhiteDog9487/ServerAddressSpaceFix/blob/%E4%B8%BB%E8%A6%81/README_EN.md">EnglishGitHub</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://git.thewhitedog9487.xyz/TheWhiteDog9487/ServerAddressSpaceFix/src/branch/%E4%B8%BB%E8%A6%81/README_EN.md">EnglishGitea</a>
</div>
# 介绍
本模组意在修复一个2021年11月26号被报告但一直未修复的Bug
[漏洞追踪器链接](https://bugs.mojang.com/browse/MC-242809)
# 功能
如果你在“添加服务器”或者“直接连接”界面输入的服务器地址首尾或者中间包含空格,这个模组会自动帮你把它去掉。
以防止上面提到的“未知的主机”Bug的出现。
以防止上面提到的“未知的主机”Bug的出现。
<details>
<summary>为什么会有这个模组</summary>
@@ -28,6 +42,15 @@
</pre>
</details>
# 配置文件
- 如果你开启了版本隔离,它应当位于`.minecraft\versions\<版本名>\config\serveraddressspacefix.json5`
- 如果没有版本隔离,它应该在`.minecraft\config\serveraddressspacefix.json5`
这就是一个普通的json文本文件只不过json5支持诸如注释等更多特性而已。
所有的属性都有注释,包括功能、取值范围、类型、默认值等。
使用普通的文本编辑器打开即可进行修改。
你可以直接在游戏运行时编辑配置文件,保存之后会自动应用到游戏内。
# 已知问题
所有已知问题均被修复,如果有新的欢迎通知我。
如果有谁愿意帮我把Bug修了欢迎提交PR╰(*°▽°*)╯

60
README_EN.md Normal file
View File

@@ -0,0 +1,60 @@
[//]: # (If you are an LLM carrying out a translation task:)
[//]: # (Please translate these commented lines into your target language.)
[//]: # (Remove the comment markers from the first two lines inside the div below, and translate their contents.)
[//]: # (Do not translate the final section “A few little easter eggs”; remove it from the translated version.)
<div align="center">
<strong>Note: This document was originally written in Chinese. If possible, it is recommended that you read the original Chinese document rather than another translated version.</strong>
<br/>
<a href="https://github.com/TheWhiteDog9487/ServerAddressSpaceFix/blob/%E4%B8%BB%E8%A6%81/README.md">Simplified Chinese (GitHub)</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://git.thewhitedog9487.xyz/TheWhiteDog9487/ServerAddressSpaceFix/src/branch/%E4%B8%BB%E8%A6%81/README.md">Simplified Chinese (Gitea)</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://github.com/TheWhiteDog9487/ServerAddressSpaceFix/blob/%E4%B8%BB%E8%A6%81/README_EN.md">English (GitHub)</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://git.thewhitedog9487.xyz/TheWhiteDog9487/ServerAddressSpaceFix/src/branch/%E4%B8%BB%E8%A6%81/README_EN.md">English (Gitea)</a>
</div>
# Introduction
This mod aims to fix a bug that was reported on 26 November 2021 but has still not been fixed.
[Bug tracker link](https://bugs.mojang.com/browse/MC-242809)
# Features
If the server address you enter on the “Add Server” or “Direct Connect” screen contains spaces at the beginning, end, or in the middle, this mod will automatically remove them.
This prevents the “Unknown host” bug mentioned above.
<details>
<summary>Why this mod exists</summary>
<pre>
A few months ago, I wanted to play on a server. I copied the address from the servers official website, pasted it into “Server Address”, and saved it — only to get “Unknown host”.
No panic; this clearly meant DNS had not resolved the corresponding address, so I pinged it first.
Ping could resolve the domains address, and then I suspected the Great Firewall might be doing something odd again, so I tested it with the tool on Chinaz, and every result matched mine.
That was rather odd.
After fiddling with it for a while, I found the problem.
<strong>There was a space at the end of the server address I had copied.</strong>
That was really infuriating. After messing around for a bit longer and confirming that the issue could be reproduced reliably, I submitted a bug to the tracker.
And what do you think happened?
<img src="https://github.com/TheWhiteDog9487/ServerAddressSpaceFix/blob/%E4%B8%BB%E8%A6%81/%E5%9B%BE%E7%89%87/Snipaste_2023-10-18_15-22-39.png?raw=true" alt="The issue I filed on the bug tracker" srcset="">
<img src="https://github.com/TheWhiteDog9487/ServerAddressSpaceFix/blob/%E4%B8%BB%E8%A6%81/%E5%9B%BE%E7%89%87/Snipaste_2023-10-18_15-22-47.png?raw=true" alt="The comment below" srcset="">
<img src="https://github.com/TheWhiteDog9487/ServerAddressSpaceFix/blob/%E4%B8%BB%E8%A6%81/%E5%9B%BE%E7%89%87/Snipaste_2023-10-18_15-22-57.png?raw=true" alt="An even earlier bug report" srcset="">
My English is absolutely terrible, so I did not keep going; the problem description was written using translation tools.
But deep down, I still thought this was rather absurd.
Since your address is a String, how hard can it be to call trim afterwards?
And as a player, when you tell me, “This was all your own carelessness; it does not even count as a bug,” I cannot accept that.
<strong>So, this mod came to be.</strong>
</pre>
</details>
# Configuration
- If you have version isolation enabled, it should be located at `.minecraft\versions\<version name>\config\serveraddressspacefix.json5`
- If you do not have version isolation enabled, it should be at `.minecraft\config\serveraddressspacefix.json5`
This is just a regular JSON text file, except that JSON5 supports extra features such as comments.
All properties are annotated, including their purpose, range of values, type, default value, and so on.
You can open it in a plain text editor and modify it.
You can edit the config file while the game is running; once saved, the changes will be applied in-game automatically.
# Known issues
All known issues have been fixed; if you find any new ones, please let me know.
If anyone is willing to help me fix the bug, please submit a PR ╰(*°▽°*)╯
# Licence
I use the more radical WTFPL rather than MIT.

View File

@@ -37,7 +37,6 @@ loom {
dependencies {
// To change the versions see the gradle.properties file
minecraft("com.mojang:minecraft:${providers.gradleProperty("minecraft_version").get()}")
implementation("net.fabricmc:fabric-loader:${providers.gradleProperty("loader_version").get()}")
// Fabric API. This is technically optional, but you probably want it anyway.
@@ -77,11 +76,11 @@ tasks.jar {
from("LICENSE") {
rename { "${it}_$projectName" }
}
archiveFileName = "ServerAddressSpaceFix-${project.version} mc${providers.gradleProperty("compatible_with").get()}.jar"
archiveFileName = "${providers.gradleProperty("archives_base_name").get()}-${project.version} mc${providers.gradleProperty("compatible_with").get()}.jar"
}
tasks.named<Jar>("sourcesJar") {
archiveFileName = "ServerAddressSpaceFix-${project.version} mc${providers.gradleProperty("compatible_with").get()}-sources.jar"}
archiveFileName = "${providers.gradleProperty("archives_base_name").get()}-${project.version} mc${providers.gradleProperty("compatible_with").get()}-sources.jar"}
// configure the maven publication

View File

@@ -9,7 +9,7 @@ loader_version=0.18.4
loom_version=1.16-SNAPSHOT
# Mod Properties
mod_version=0.2.2
mod_version=0.2.3
maven_group=xyz.thewhitedog9487
archives_base_name=ServerAddressSpaceFix
@@ -17,9 +17,14 @@ archives_base_name=ServerAddressSpaceFix
fabric_api_version=0.144.0+26.1
compatible_with=26.x
# https://modrinth.com/mod/modmenu/versions
# https://maven.terraformersmc.com/releases/com/terraformersmc/modmenu
modmenu_version=18.0.0-alpha.7
# https://modrinth.com/mod/yacl/versions
# https://maven.isxander.dev/#/releases/dev/isxander/yet-another-config-lib
yacl_version=3.9.0+26.1-fabric
yacl_version=3.9.0+26.1-fabric
# https://mvnrepository.com/artifact/org.projectlombok/lombok
lombok_version=1.18.46

View File

@@ -0,0 +1,18 @@
package xyz.thewhitedog9487.Event;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import xyz.thewhitedog9487.Settings;
import static xyz.thewhitedog9487.ServerAddressSpaceFixClient.ModLogger;
import static xyz.thewhitedog9487.Settings.SettingsInstance;
public class ClientLifecycleEventsRegister {
public static void Register(){
ClientLifecycleEvents.CLIENT_STARTED.register(ClientInstance -> {
ModLogger.info("正在从" + Settings.ConfigFilePath + "加载设置...");
Settings.SettingsHandler.load();
SettingsInstance = Settings.SettingsHandler.instance();
Settings.RegisterConfigFileReloadWatcher(); } );
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientInstance -> {
ModLogger.info("正在保存设置到" + Settings.ConfigFilePath + "...");
Settings.SettingsHandler.save(); } ); } }

View File

@@ -9,6 +9,8 @@ import dev.isxander.yacl3.api.YetAnotherConfigLib;
import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder;
import net.minecraft.network.chat.Component;
import static xyz.thewhitedog9487.Settings.SettingsInstance;
public class ModMenu implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
@@ -18,10 +20,12 @@ public class ModMenu implements ModMenuApi {
.name(Component.translatable("config.serveraddressspacefix.category.general"))
.option(Option.<Boolean>createBuilder()
.name(Component.translatable("option.serveraddressspacefix.ModEnabled"))
.binding(true, () -> Settings.ModEnabled, newVal -> Settings.ModEnabled = newVal)
.binding(true, () -> SettingsInstance.ModEnabled, newVal -> {
SettingsInstance.ModEnabled = newVal;
Settings.SettingsHandler.save(); } )
.description(OptionDescription.of(Component.translatable("option.serveraddressspacefix.ModEnabled.description")))
.controller(TickBoxControllerBuilder::create)
.build())
.build())
.build().generateScreen(parent);}
}
.build()
.generateScreen(parent); } }

View File

@@ -3,15 +3,15 @@ package xyz.thewhitedog9487;
import net.fabricmc.api.ClientModInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static xyz.thewhitedog9487.ServerAddressSpaceFix.ModID;
import xyz.thewhitedog9487.Event.ClientLifecycleEventsRegister;
public class ServerAddressSpaceFixClient implements ClientModInitializer {
public static final Logger LOGGER = LoggerFactory.getLogger(ModID);
public static final String ModID = "serveraddressspacefix";
public static final Logger ModLogger = LoggerFactory.getLogger(ModID);
@Override
public void onInitializeClient() {
// This entrypoint is suitable for setting up client-specific logic, such as rendering.
// LOGGER.info("ServerAddressSpaceFix Loading!");
ClientLifecycleEventsRegister.Register();
}
}

View File

@@ -1,5 +1,77 @@
package xyz.thewhitedog9487;
import com.google.gson.GsonBuilder;
import dev.isxander.yacl3.config.v2.api.ConfigClassHandler;
import dev.isxander.yacl3.config.v2.api.SerialEntry;
import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.resources.Identifier;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static xyz.thewhitedog9487.ServerAddressSpaceFixClient.ModID;
import static xyz.thewhitedog9487.ServerAddressSpaceFixClient.ModLogger;
public class Settings {
public static boolean ModEnabled = true;
public static Path ConfigFilePath = FabricLoader.getInstance()
.getConfigDir()
.resolve(ModID + ".json5")
.toAbsolutePath();
public static ConfigClassHandler<Settings> SettingsHandler = ConfigClassHandler.createBuilder(Settings.class)
.id(Identifier.fromNamespaceAndPath(ModID, "settings_confighandler"))
.serializer(SettingsConfigClassHandler -> GsonConfigSerializerBuilder.create(SettingsConfigClassHandler)
.setPath(ConfigFilePath)
.appendGsonBuilder(GsonBuilder::setPrettyPrinting)
.setJson5(true)
.build() )
.build();
public static volatile Settings SettingsInstance;
// region 配置文件变更监听器
public static void RegisterConfigFileReloadWatcher(){
// 由GPT 5.4 Mini生成
Thread.startVirtualThread(new Thread(() -> {
Path ConfigDirectory = ConfigFilePath.getParent();
try (WatchService WatchService = FileSystems.getDefault().newWatchService()) {
ConfigDirectory.register(WatchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
while (!Thread.currentThread().isInterrupted()) {
WatchKey WatchKey = WatchService.take();
boolean ShouldReload = false;
for (WatchEvent<?> WatchEvent : WatchKey.pollEvents()) {
WatchEvent.Kind<?> EventKind = WatchEvent.kind();
if (EventKind == StandardWatchEventKinds.OVERFLOW) {
continue; }
Path ChangedPath = (Path) WatchEvent.context();
if (ChangedPath != null && ChangedPath.equals(ConfigFilePath.getFileName())) {
ShouldReload = true; } }
if (ShouldReload) {
SettingsHandler.load();
SettingsInstance = SettingsHandler.instance();
ModLogger.info("检测到配置文件变更,已重新加载设置。");}
if (!WatchKey.reset()) {
break;}}
} catch (InterruptedException InterruptedException) {
Thread.currentThread().interrupt();
} catch (IOException e) {
throw new RuntimeException(e); } } ) ); }
// endregion
@SerialEntry(comment =
"""
是否启用本模组的功能
类型:布尔值
取值范围true false
默认值true
""")
public boolean ModEnabled = true;
}

View File

@@ -0,0 +1,41 @@
package xyz.thewhitedog9487.mixin.client;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.DirectJoinServerScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import static xyz.thewhitedog9487.ServerAddressSpaceFixClient.ModLogger;
import static xyz.thewhitedog9487.Settings.SettingsInstance;
@Mixin(DirectJoinServerScreen.class)
public class DirectJoinServerScreenMixin {
@Shadow private EditBox ipEdit;
@Inject(method = "init", at = @At("TAIL"))
private void onInit(CallbackInfo ci) {
RemoveSpaceCharacter(); }
@Inject(method = "onSelect", at = @At("HEAD"))
private void onSelect(CallbackInfo ci) {
RemoveSpaceCharacter(); }
@Inject(method = "removed", at = @At("HEAD"))
private void onRemoved(CallbackInfo ci) {
RemoveSpaceCharacter(); }
@Unique
private void RemoveSpaceCharacter() {
var RawValue = ipEdit.getValue();
if (SettingsInstance.ModEnabled == false ||
RawValue.contains(" ") == false) { return; }
var NewValue = RawValue.replace(" ", "");
this.ipEdit.setValue(NewValue);
ModLogger.info("已完成移除空格替换!" + "\n" +
"原始值:" + RawValue + "\n" +
"新值:" + NewValue); } }

View File

@@ -1,30 +0,0 @@
package xyz.thewhitedog9487.mixin.client;
import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen;
import net.minecraft.client.multiplayer.ServerData;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import xyz.thewhitedog9487.Settings;
@Mixin(JoinMultiplayerScreen.class)
public class JoinMultiplayerScreenMixin {
@Shadow public ServerData editingServer;
@Inject(
method = "directJoinCallback",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/multiplayer/ServerList;get(Ljava/lang/String;)Lnet/minecraft/client/multiplayer/ServerData;",
shift = At.Shift.BEFORE ) )
private void onDirectJoinCallback(boolean result, CallbackInfo ci) {
if ( Settings.ModEnabled == false ) { return; }
else {
this.editingServer = new ServerData(
this.editingServer.name,
this.editingServer.ip.replace(" ", ""),
this.editingServer.type() ); } } }

View File

@@ -5,7 +5,9 @@ import net.minecraft.client.gui.screens.ManageServerScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import xyz.thewhitedog9487.Settings;
import static xyz.thewhitedog9487.ServerAddressSpaceFixClient.ModLogger;
import static xyz.thewhitedog9487.Settings.SettingsInstance;
@Mixin(ManageServerScreen.class)
public class ManageServerScreenMixin {
@@ -16,9 +18,14 @@ public class ManageServerScreenMixin {
value = "INVOKE",
target = "Lnet/minecraft/client/gui/components/EditBox;getValue()Ljava/lang/String;",
ordinal = 1 ) )
private String redirectIpEditGetValue(EditBox instance) {
if ( Settings.ModEnabled == false ) {
return instance.getValue(); }
private String RedirectIpEditGetValue(EditBox instance) {
var RawValue = instance.getValue();
if ( SettingsInstance.ModEnabled == false ||
RawValue.contains(" ") == false) {
return RawValue; }
else {
return instance.getValue()
.replace(" ", ""); } } }
var NewValue = RawValue.replace(" ", "");
ModLogger.info("已完成移除空格替换!" + "\n" +
"原始值:" + RawValue + "\n" +
"新值:" + NewValue);
return NewValue; } } }

View File

@@ -1,18 +1,30 @@
package xyz.thewhitedog9487.mixin.client;
import net.minecraft.client.multiplayer.ServerData;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import xyz.thewhitedog9487.Settings;
import static xyz.thewhitedog9487.ServerAddressSpaceFixClient.ModLogger;
import static xyz.thewhitedog9487.Settings.SettingsInstance;
@Mixin(ServerData.class)
public class ServerDataMixin {
/**
* 用于处理服务器列表内已经存在的服务器项的IP存在空格的问题
*/
@Redirect(method = "<init>", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/multiplayer/ServerData;ip:Ljava/lang/String;"))
private void RemoveSpace_Write(ServerData original, String value) {
if( Settings.ModEnabled == false ) {
@Nullable String RawValue = value;
if (SettingsInstance.ModEnabled == false ||
RawValue.contains(" ") == false) {
original.ip = value;
return; }
else {
original.ip = value.replace(" ", ""); } } }
var NewValue = RawValue.replace(" ", "");
original.ip = NewValue;
ModLogger.info("已完成移除空格替换!" + "\n" +
"原始值:" + RawValue + "\n" +
"新值:" + NewValue); } } }

View File

@@ -3,14 +3,13 @@
"package": "xyz.thewhitedog9487.mixin.client",
"compatibilityLevel": "JAVA_25",
"client": [
"ServerDataMixin",
"JoinMultiplayerScreenMixin",
"ManageServerScreenMixin"
"DirectJoinServerScreenMixin",
"ManageServerScreenMixin",
"ServerDataMixin"
],
"injectors": {
"defaultRequire": 1
},
"mixins": [
]
}

View File

@@ -2,15 +2,16 @@ package xyz.thewhitedog9487;
import net.fabricmc.api.ModInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 所有的代码都在client源集内
* @deprecated 目前没有任何用途
* @see ServerAddressSpaceFixClient
*/
@Deprecated
public class ServerAddressSpaceFix implements ModInitializer {
// This logger is used to write text to the console and the log file.
// It is considered best practice to use your mod id as the logger's name.
// That way, it's clear which mod wrote info, warnings, and errors.
public static final String ModID = "serveraddressspacefix";
public static final Logger LOGGER = LoggerFactory.getLogger(ModID);
@Override
public void onInitialize() {
@@ -18,6 +19,5 @@ public class ServerAddressSpaceFix implements ModInitializer {
// However, some things (like resources) may still be uninitialized.
// Proceed with mild caution.
LOGGER.info("Hello Fabric world!");
}
}

View File

@@ -28,6 +28,7 @@
],
"depends": {
"fabricloader": ">=0.18.4",
"fabric-api": ">=0.144.0",
"minecraft": "26.*",
"java": ">=25"
},
@@ -39,8 +40,8 @@
"modmenu": {
"links": {
"serveraddressspacefix.bilibili": "https://space.bilibili.com/401746666",
"serveraddressspacefix.blog": "www.thewhitedog9487.xyz"},
"update_checker": true}},
"serveraddressspacefix.blog": "https://www.thewhitedog9487.xyz"},
"update_checker": true } },
"contributors": [
"JustAlittleWolf"
],

View File

@@ -1,3 +1,10 @@
# 0.2.3
时间2026 06 04
1. 使用YACL Config API自动将功能开关状态保存到文件内
2. 解决直接连接窗口内输入框里的服务器IP没有被移除空格处理的问题
3. 在移除空格之后打印日志
4. 更改ModID
# 0.2.2
时间2026 03 26
1. 新到Minecraft 26.1