6 Commits

Author SHA1 Message Date
TheWhiteDog9487 ca8953d52e 0.2.5
修复Windows文件系统对大小写不敏感导致配置文件迁移会实际上导致原始配置文件被删除的问题
2026-06-17 13:29:24 +08:00
TheWhiteDog9487 abd1378634 0.2.4
修复未安装YACL会导致游戏出现`NoClassDefFoundError`崩溃的问题
将配置文件名从`serveraddressspacefix.json5`改为`ServerAddressSpaceFix.json5`
为配置文件添加版本号
更改Logger名称
2026-06-17 13:28:14 +08:00
TheWhiteDog9487 92d1e282d8 使用YACL Config API自动将功能开关状态保存到文件内
使用文件系统监听器使配置文件被外部更改时可以自动重载到游戏内
解决直接连接窗口内输入框里的服务器IP没有被移除空格处理的问题
在移除空格之后打印日志
添加英文README
重新给main入口类添加`@Deprecated`标记,这东西确实用不到,后面看要不要直接删了
为AI Agent添加AGENTS.md文件以指示通用提示词
2026-06-04 19:40:45 +08:00
TheWhiteDog9487 5cb7a45ff4 更改ModID
同步Fabric Mod Template那边的Kotlin DSL官方配置
移除main入口类的`@Deprecated`标记
( 我当初为什么要弃用它?
补全ChangeLog.md
( 已经彻底忘记它的存在了
更新Github Action配置
更新Gradle版本

由于本次更改不存在对玩家具有实质影响的内容,故合并到下一个Mod版本内一并发布
2026-06-01 15:16:58 +08:00
TheWhiteDog9487 37722dcd8f 修复Github Action Workflow
又忘记改了
2026-03-26 09:22:05 +08:00
TheWhiteDog9487 85486ab217 0.2.2
更新到Minecraft 26.1
由于源码变更,更换了一个新的实现方案,稍微测试了一下没太大毛病,应该还行

( AI太好用了你们知道吗,我只需要描述我需要使用什么方法比如@Redirect @Inject注入哪个字段或者函数的哪个位置,代码就可以全自动生成,连字段描述符都不需要我弄了
2026-03-26 09:15:11 +08:00
34 changed files with 591 additions and 238 deletions
+7 -14
View File
@@ -8,30 +8,23 @@ on: [pull_request, push]
jobs: jobs:
build: build:
strategy: runs-on: ubuntu-24.04
matrix:
# Use these Java versions
java: [
21, # Current Java LTS
]
runs-on: ubuntu-22.04
steps: steps:
- name: checkout repository - name: checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v6
- name: validate gradle wrapper - name: validate gradle wrapper
uses: gradle/wrapper-validation-action@v2 uses: gradle/actions/wrapper-validation@v6
- name: setup jdk ${{ matrix.java }} - name: setup jdk
uses: actions/setup-java@v4 uses: actions/setup-java@v5
with: with:
java-version: ${{ matrix.java }} java-version: '25'
distribution: 'microsoft' distribution: 'microsoft'
- name: make gradle wrapper executable - name: make gradle wrapper executable
run: chmod +x ./gradlew run: chmod +x ./gradlew
- name: build - name: build
run: ./gradlew build run: ./gradlew build
- name: capture build artifacts - name: capture build artifacts
if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with: with:
name: Artifacts name: Artifacts
path: build/libs/ path: build/libs/
+6
View File
@@ -0,0 +1,6 @@
- 如果需要Minecraft经过反混淆的源码,直接在`.gradle/loom-cache/minecraftMaven/net/minecraft`目录下查找。
- 源码使用完成之后记得删除解压jar产生的临时文件
- 使用帕斯卡命名法
- 如果你是正在翻译README的LLM,请遵守README内使用注释编写的指令
+25
View File
@@ -1,3 +1,19 @@
[//]: # (如果你是正在执行翻译任务的LLM:)
[//]: # (请将这几行注释内容翻译到你的目标语言)
[//]: # (移除下方div内部第一行和第二行的注释符号,并翻译其内容)
[//]: # (不要翻译下方div内部a标签的文本内容和链接地址)
[//]: # (不要改动下方div标签的align="center"属性)
[//]: # (将翻译的结果放置到正确的文件内,目标文件的位置和主README.md同级,文件名格式是 README_<LANG>.md ,其中<LANG>的值是目标语言的IETF语言标签)
<div align="center">
<!-- <strong>注意:本文档由中文编写,使用AI翻译到其他语言。如果条件允许,建议阅读原始的中文文档而不是其他的翻译版本。</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 本模组意在修复一个2021年11月26号被报告但一直未修复的Bug
[漏洞追踪器链接](https://bugs.mojang.com/browse/MC-242809) [漏洞追踪器链接](https://bugs.mojang.com/browse/MC-242809)
@@ -28,6 +44,15 @@
</pre> </pre>
</details> </details>
# 配置文件
- 如果你开启了版本隔离,它应当位于`.minecraft\versions\<版本名>\config\ServerAddressSpaceFix.json5`
- 如果没有版本隔离,它应该在`.minecraft\config\ServerAddressSpaceFix.json5`
这就是一个普通的json文本文件,只不过json5支持诸如注释等更多特性而已。
所有的属性都有注释,包括功能、取值范围、类型、默认值等。
使用普通的文本编辑器打开即可进行修改。
你可以直接在游戏运行时编辑配置文件,保存之后会自动应用到游戏内。
# 已知问题 # 已知问题
所有已知问题均被修复,如果有新的欢迎通知我。 所有已知问题均被修复,如果有新的欢迎通知我。
如果有谁愿意帮我把Bug修了,欢迎提交PR╰(*°▽°*)╯ 如果有谁愿意帮我把Bug修了,欢迎提交PR╰(*°▽°*)╯
+62
View File
@@ -0,0 +1,62 @@
[//]: # (If you are an LLM performing a translation task:)
[//]: # (Translate these comment lines into your target language.)
[//]: # (Remove the comment markers from the first and second lines inside the div below, and translate their content.)
[//]: # (Do not translate the text content or link targets of the a tags inside the div below.)
[//]: # (Do not change the align="center" attribute on the div below.)
[//]: # (Place the translated result in the correct file. The target file should be at the same level as the main README.md, and the filename should be README_<LANG>.md, where <LANG> is the target language's IETF language tag.)
<div align="center">
<strong>Note: This document was originally written in Chinese and translated to other languages by AI. If possible, I recommend reading the original Chinese document instead of a translated version.</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>
# Introduction
This mod is intended to fix a bug that was reported on November 26, 2021 and still has 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, the 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 server's official website, pasted it into the "Server Address" field, saved it, and unexpectedly got an "Unknown Host" error.
No panic, this was obviously DNS failing to resolve the corresponding address. Let's try pinging it first.
Ping could resolve the domain name to an address, and then I suspected the Great Firewall might be doing something again, so I used a tool from ZhanZhangJia to test it. The results were exactly the same as mine.
That was rather strange.
Then, after fiddling with it for a while, I found the problem.
<strong>There was a space at the end of the server address I copied.</strong>
That was pretty hard to accept. After continuing to tinker for a while and confirming that the problem could be reproduced reliably, I submitted a bug report to the tracker.
And guess what?
<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 earlier bug report" srcset="">
My English is completely terrible, so I did not continue talking about it. The issue description was written using a translator.
But honestly, I felt this was kind of absurd.
Since your address is a String, how hard could it be to call trim on it afterwards?
Also, as a player, when you tell me, "This was your own carelessness, so it does not even count as a bug," I cannot accept that.
<strong>So, this mod was born.</strong>
</pre>
</details>
# Configuration file
- 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 located at `.minecraft\config\ServerAddressSpaceFix.json5`
This is just a regular JSON text file, except that JSON5 supports additional features such as comments.
All properties include comments, covering things such as functionality, value ranges, types, default values, and more.
You can edit it with a normal text editor.
You can even edit the configuration file while the game is running; it will be applied automatically after saving.
# Known issues
All known issues have been fixed. If you find any new ones, please let me know.
If anyone is willing to help fix a bug, PRs are welcome ╰(*°▽°*)╯
# License
I use the even more aggressive WTFPL than MIT.
+71 -40
View File
@@ -1,93 +1,124 @@
import java.nio.file.Paths
plugins { plugins {
id("fabric-loom") version "1.8-SNAPSHOT" id("net.fabricmc.fabric-loom")
id("maven-publish") `maven-publish`
} }
version = project.extra["mod_version"] as String version = providers.gradleProperty("mod_version").get()
group = project.extra["maven_group"] as String group = providers.gradleProperty("maven_group").get()
base {
archivesName.set(project.extra["archives_base_name"] as String)
}
repositories { repositories {
// Add repositories to retrieve artifacts from in here.
// You should only use this when depending on other mods because
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
maven { maven {
name = "Xander Maven" name = "Xander Maven"
url = uri("https://maven.isxander.dev/releases")} url = uri("https://maven.isxander.dev/releases") }
maven { maven {
name = "Terraformers" name = "Terraformers"
url = uri("https://maven.terraformersmc.com/releases")} url = uri("https://maven.terraformersmc.com/releases") }
} maven {
name = "Nucleoid"
url = uri("https://maven.nucleoid.xyz/") } }
afterEvaluate {
val MixinJarPath = configurations.loaderLibraries.get().resolvedConfiguration
.resolvedArtifacts
.find { it.moduleVersion.id.group == "net.fabricmc" && it.moduleVersion.id.name == "sponge-mixin" }!!
.file
val IsSupportDceVM = Paths.get(System.getProperty("java.home"))
.resolve("bin")
.resolve("java")
.toFile()
.let {
val ReturnCode = ProcessBuilder(it.absolutePath, "-XX:+AllowEnhancedClassRedefinition", "-version")
.start()
.waitFor()
return@let ReturnCode == 0 }
loom.runs.named("client") {
jvmArguments.add("-javaagent:${MixinJarPath.absolutePath}")
if (IsSupportDceVM == true) jvmArguments.add("-XX:+AllowEnhancedClassRedefinition") }
loom.runs.named("server") {
jvmArguments.add("-javaagent:${MixinJarPath.absolutePath}")
if (IsSupportDceVM == true) jvmArguments.add("-XX:+AllowEnhancedClassRedefinition") } }
loom { loom {
splitEnvironmentSourceSets() splitEnvironmentSourceSets()
mods { mods {
create("twd-sasf") { register("serveraddressspacefix") {
sourceSet(sourceSets["main"]) sourceSet(sourceSets.main.get())
sourceSet(sourceSets["client"]) sourceSet(sourceSets.getByName("client"))
} }
} }
accessWidenerPath = file("src/main/resources/serveraddressspacefix.classtweaker")
} }
dependencies { dependencies {
// To change the versions see the gradle.properties file // To change the versions see the gradle.properties file
minecraft("com.mojang:minecraft:${project.extra["minecraft_version"]}") minecraft("com.mojang:minecraft:${providers.gradleProperty("minecraft_version").get()}")
mappings("net.fabricmc:yarn:${project.extra["yarn_mappings"]}:v2") implementation("net.fabricmc:fabric-loader:${providers.gradleProperty("loader_version").get()}")
modImplementation("net.fabricmc:fabric-loader:${project.extra["loader_version"]}")
// Fabric API. This is technically optional, but you probably want it anyway. // Fabric API. This is technically optional, but you probably want it anyway.
modImplementation("net.fabricmc.fabric-api:fabric-api:${project.extra["fabric_version"]}") implementation("net.fabricmc.fabric-api:fabric-api:${providers.gradleProperty("fabric_api_version").get()}")
// Uncomment the following line to enable the deprecated Fabric API modules. implementation("com.terraformersmc:modmenu:${providers.gradleProperty("modmenu_version").get()}")
// These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. implementation("dev.isxander:yet-another-config-lib:${providers.gradleProperty("yacl_version").get()}")
// "modImplementation"("net.fabricmc.fabric-api:fabric-api-deprecated:${project.extra["fabric_version"]}")
modImplementation("com.terraformersmc:modmenu:${project.extra["modmenu_version"]}")
modImplementation("dev.isxander:yet-another-config-lib:${project.extra["yacl_version"]}")
} }
tasks.processResources { tasks.processResources {
inputs.property("version", project.version) val version = version
inputs.property("version", version)
filesMatching("fabric.mod.json") { filesMatching("fabric.mod.json") {
expand("version" to project.version) expand("version" to version)
} }
} }
tasks.withType<JavaCompile> { tasks.withType<JavaCompile>().configureEach {
options.release.set(21) options.release = 25
} }
java { java {
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// if it is present.
// If you remove this line, sources will not be generated.
withSourcesJar() withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21 sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
} }
tasks.jar { tasks.jar {
val projectName = project.name
inputs.property("projectName", projectName)
from("LICENSE") { from("LICENSE") {
rename { "${it}_${project.base.archivesName.get()}" } rename { "${it}_$projectName" }
} }
archiveFileName = "${providers.gradleProperty("archives_base_name").get()}-${project.version} mc${providers.gradleProperty("compatible_with").get()}.jar"
} }
tasks.remapJar{ tasks.named<Jar>("sourcesJar") {
// https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:archiveFileName archiveFileName = "${providers.gradleProperty("archives_base_name").get()}-${project.version} mc${providers.gradleProperty("compatible_with").get()}-sources.jar"}
// 用这个属性设置jar包的文件名格式
// 别用上面那个Jar任务的配置,会被remapJar覆盖掉
archiveFileName = "${project.base.archivesName.get()}-${project.version} mc${project.extra["compatible_with"]}.jar"}
tasks.remapSourcesJar{
archiveFileName = "${project.base.archivesName.get()}-${project.version} mc${project.extra["compatible_with"]}-sources.jar"}
// configure the maven publication
publishing { publishing {
publications { publications {
create<MavenPublication>("mavenJava") { register<MavenPublication>("mavenJava") {
from(components["java"]) from(components["java"])
} }
} }
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
repositories { repositories {
// Add repositories to publish to here. // Add repositories to publish to here.
// Notice: This block does NOT have the same function as the block in the top level. // Notice: This block does NOT have the same function as the block in the top level.
// The repositories here will be used for publishing your artifact, not for retrieving dependencies. // The repositories here will be used for publishing your artifact, not for
// retrieving dependencies.
} }
} }
+10 -14
View File
@@ -4,28 +4,24 @@ org.gradle.parallel=true
# Fabric Properties # Fabric Properties
# check these on https://fabricmc.net/develop # check these on https://fabricmc.net/develop
minecraft_version=1.21.3 minecraft_version=26.1
yarn_mappings=1.21.3+build.2 loader_version=0.18.4
loader_version=0.16.7 loom_version=1.17-SNAPSHOT
# Mod Properties # Mod Properties
mod_version=0.2.1 mod_version=0.2.5
maven_group=xyz.thewhitedog9487 maven_group=xyz.thewhitedog9487
archives_base_name=ServerAddressSpaceFix archives_base_name=ServerAddressSpaceFix
# Dependencies # Dependencies
fabric_version=0.106.1+1.21.3 fabric_api_version=0.144.0+26.1
compatible_with=26.x
compatible_with=1.21+1.21.x
# https://modrinth.com/mod/modmenu/versions # https://modrinth.com/mod/modmenu/versions
# https://maven.terraformersmc.com/releases/com/terraformersmc/modmenu # https://maven.terraformersmc.com/releases/com/terraformersmc/modmenu
modmenu_version=12.0.0-beta.1 modmenu_version=18.0.0-beta.1
# https://modrinth.com/mod/yacl/versions # https://modrinth.com/mod/yacl/versions
# https://maven.isxander.dev/#/releases/dev/isxander/yet-another-config-lib # https://maven.isxander.dev/#/releases/dev/isxander/yet-another-config-lib
yacl_version=3.6.1+1.21.2-fabric yacl_version=3.9.0+26.1-fabric
# loom_libraries_base=https://bmclapi2.bangbang93.com/maven/
# loom_resources_base=https://bmclapi2.bangbang93.com/assets/
# loom_version_manifests=https://bmclapi2.bangbang93.com/mc/game/version_manifest.json
# loom_experimental_versions=https://maven.fabricmc.net/net/minecraft/experimental_versions.json
# loom_fabric_repository=https://repository.hanbings.io/proxy/
Binary file not shown.
+3 -1
View File
@@ -1,7 +1,9 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
networkTimeout=10000 networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
Vendored
+13 -14
View File
@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# #
# Copyright © 2015-2021 the original authors. # Copyright © 2015 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;; NONSTOP* ) nonstop=true ;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
@@ -145,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
@@ -153,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" ) JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -202,16 +202,15 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command:
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# shell script including quotes and variable substitutions, so put them in # and any embedded shellness will be escaped.
# double quotes to make sure that they get re-expanded; and # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# * put everything else in single quotes, so that it's not re-expanded. # treated as '${Hostname}' itself on the command line.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
org.gradle.wrapper.GradleWrapperMain \
"$@" "$@"
# Stop when "xargs" is not available. # Stop when "xargs" is not available.
Vendored
+22 -32
View File
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@@ -21,8 +23,8 @@
@rem @rem
@rem ########################################################################## @rem ##########################################################################
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables, and ensure extensions are enabled
if "%OS%"=="Windows_NT" setlocal setlocal EnableExtensions
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
@@ -43,13 +45,13 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail "%COMSPEC%" /c exit 1
:findJavaFromJavaHome :findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
@@ -57,36 +59,24 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail "%COMSPEC%" /c exit 1
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* @rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
:end :exitWithErrorLevel
@rem End local scope for the variables with windows NT shell @rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
if %ERRORLEVEL% equ 0 goto mainEnd "%COMSPEC%" /c exit %ERRORLEVEL%
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+6 -3
View File
@@ -4,6 +4,9 @@ pluginManagement {
name = "Fabric" name = "Fabric"
url = uri("https://maven.fabricmc.net/")} url = uri("https://maven.fabricmc.net/")}
mavenCentral() mavenCentral()
gradlePluginPortal() gradlePluginPortal() }
} plugins {
} id("net.fabricmc.fabric-loom") version providers.gradleProperty("loom_version") } }
// Should match your modid
rootProject.name = "serveraddressspacefix"
@@ -0,0 +1,27 @@
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.*;
public class ClientLifecycleEventsRegister {
public static void Register(){
ClientLifecycleEvents.CLIENT_STARTED.register(ClientInstance -> {
if (Settings.SettingsHandler == null){
ModLogger.warn("当前没有安装YACL,因此无法调整和保持Mod配置");
SettingsInstance = new Settings(); }
else {
ModLogger.info("正在从" + Settings.ConfigFilePath + "加载设置...");
Settings.SettingsHandler.load();
SettingsInstance = Settings.SettingsHandler.instance();
if (SettingsInstance.ConfigurationVersionCode != CurrentConfigurationVersionCode){
// 必要时手动处理升降级,现在不必要,就这么办了
SettingsInstance.ConfigurationVersionCode = CurrentConfigurationVersionCode;
SettingsHandler.save(); }
Settings.RegisterConfigFileReloadWatcher(); } } );
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientInstance -> {
if (Settings.SettingsHandler == null) return;
ModLogger.info("正在保存设置到" + Settings.ConfigFilePath + "...");
Settings.SettingsHandler.save(); } ); } }
@@ -7,20 +7,25 @@ import dev.isxander.yacl3.api.Option;
import dev.isxander.yacl3.api.OptionDescription; import dev.isxander.yacl3.api.OptionDescription;
import dev.isxander.yacl3.api.YetAnotherConfigLib; import dev.isxander.yacl3.api.YetAnotherConfigLib;
import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder; import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder;
import net.minecraft.text.Text; import net.minecraft.network.chat.Component;
import static xyz.thewhitedog9487.Settings.SettingsInstance;
public class ModMenu implements ModMenuApi { public class ModMenu implements ModMenuApi {
@Override @Override
public ConfigScreenFactory<?> getModConfigScreenFactory() { public ConfigScreenFactory<?> getModConfigScreenFactory() {
return parent -> YetAnotherConfigLib.createBuilder() return parent -> YetAnotherConfigLib.createBuilder()
.title(Text.translatable("title.twd-sasf.config")) .title(Component.translatable("title.serveraddressspacefix.config"))
.category(ConfigCategory.createBuilder() .category(ConfigCategory.createBuilder()
.name(Text.translatable("config.twd-sasf.category.general")) .name(Component.translatable("config.serveraddressspacefix.category.general"))
.option(Option.<Boolean>createBuilder() .option(Option.<Boolean>createBuilder()
.name(Text.translatable("option.twd-sasf.ModEnabled")) .name(Component.translatable("option.serveraddressspacefix.ModEnabled"))
.binding(true, () -> Settings.ModEnabled, newVal -> Settings.ModEnabled = newVal) .binding(true, () -> SettingsInstance.ModEnabled, newVal -> {
.description(OptionDescription.of(Text.translatable("option.twd-sasf.ModEnabled.description"))) SettingsInstance.ModEnabled = newVal;
Settings.SettingsHandler.save(); } )
.description(OptionDescription.of(Component.translatable("option.serveraddressspacefix.ModEnabled.description")))
.controller(TickBoxControllerBuilder::create) .controller(TickBoxControllerBuilder::create)
.build()) .build())
.build()) .build())
.build().generateScreen(parent);}} .build()
.generateScreen(parent); } }
@@ -0,0 +1,31 @@
package xyz.thewhitedog9487;
import net.fabricmc.loader.api.FabricLoader;
import java.io.IOException;
import java.nio.file.Files;
import static xyz.thewhitedog9487.ServerAddressSpaceFixClient.*;
/**
* 预计27.1正式版发布后删除
*/
@Deprecated
public class RemoveInFuture {
@Deprecated
public static void MigrateConfiguration() {
var OldPath = FabricLoader.getInstance()
.getConfigDir()
.resolve(ModID + ".json5")
.toAbsolutePath();
if (OldPath.toFile().exists()){
try {
ModLogger.info("发现旧的配置文件,正在进行迁移");
var OldContent = new String(Files.readAllBytes(OldPath));
OldPath.toFile().delete();
Files.writeString(Settings.ConfigFilePath, OldContent);
ModLogger.info("迁移配置文件成功");
} catch (IOException e) {
ModLogger.error("迁移配置文件失败");
ModLogger.error(e.getLocalizedMessage());
e.printStackTrace(); } } } }
@@ -3,12 +3,17 @@ package xyz.thewhitedog9487;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import xyz.thewhitedog9487.Event.ClientLifecycleEventsRegister;
public class ServerAddressSpaceFixClient implements ClientModInitializer { public class ServerAddressSpaceFixClient implements ClientModInitializer {
public static final Logger LOGGER = LoggerFactory.getLogger("twd-sasf"); public static final String ModID = "serveraddressspacefix";
public static final String FriendlyModID = "ServerAddressSpaceFix";
public static final Logger ModLogger = LoggerFactory.getLogger(FriendlyModID);
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
// This entrypoint is suitable for setting up client-specific logic, such as rendering. // This entrypoint is suitable for setting up client-specific logic, such as rendering.
LOGGER.info("ServerAddressSpaceFix Loading!"); RemoveInFuture.MigrateConfiguration();
ClientLifecycleEventsRegister.Register();
} }
} }
@@ -1,5 +1,94 @@
package xyz.thewhitedog9487; 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.*;
public class Settings { public class Settings {
public static boolean ModEnabled = true; public static Path ConfigFilePath = FabricLoader.getInstance()
.getConfigDir()
.resolve(FriendlyModID + ".json5")
.toAbsolutePath();
public static ConfigClassHandler<Settings> SettingsHandler = null;
public static long CurrentConfigurationVersionCode = 0;
static {
try {
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();
} catch (NoClassDefFoundError _) {} }
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 =
"""
配置文件版本号
用于在配置文件结构发生变化且需要手动干预时进行兼容性处理
非必要情况下你不应该手动修改这个数据,否则可能导致本Mod的配置文件出现损坏或其他问题
类型:整数
取值范围:0 ~ Long.MAX_VALUE
当前值:0
""")
public long ConfigurationVersionCode = CurrentConfigurationVersionCode;
@SerialEntry(comment =
"""
是否启用本模组的功能
类型:布尔值
取值范围:true false
默认值:true
""")
public boolean ModEnabled = true;
} }
@@ -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); } }
@@ -0,0 +1,31 @@
package xyz.thewhitedog9487.mixin.client;
import net.minecraft.client.gui.components.EditBox;
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 static xyz.thewhitedog9487.ServerAddressSpaceFixClient.ModLogger;
import static xyz.thewhitedog9487.Settings.SettingsInstance;
@Mixin(ManageServerScreen.class)
public class ManageServerScreenMixin {
@Redirect(
method = "onAdd",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/gui/components/EditBox;getValue()Ljava/lang/String;",
ordinal = 1 ) )
private String RedirectIpEditGetValue(EditBox instance) {
var RawValue = instance.getValue();
if ( SettingsInstance.ModEnabled == false ||
RawValue.contains(" ") == false) {
return RawValue; }
else {
var NewValue = RawValue.replace(" ", "");
ModLogger.info("已完成移除空格替换!" + "\n" +
"原始值:" + RawValue + "\n" +
"新值:" + NewValue);
return NewValue; } } }
@@ -1,15 +0,0 @@
package xyz.thewhitedog9487.mixin.client;
import net.minecraft.client.gui.screen.multiplayer.AddServerScreen;
import net.minecraft.client.gui.widget.TextFieldWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import xyz.thewhitedog9487.Settings;
@Mixin(AddServerScreen.class)
public class MixinAddServerScreen {
@Redirect(method = "addAndClose", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/TextFieldWidget;getText()Ljava/lang/String;", ordinal = 1))
private String trimGetText(TextFieldWidget instance) {
if( Settings.ModEnabled == false ) { return instance.getText(); }
else return instance.getText().replace(" ", "");}}
@@ -1,23 +0,0 @@
package xyz.thewhitedog9487.mixin.client;
import net.minecraft.client.gui.screen.multiplayer.DirectConnectScreen;
import net.minecraft.client.gui.widget.TextFieldWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import xyz.thewhitedog9487.Settings;
@Mixin(DirectConnectScreen.class)
interface DirectConnectScreenAccessor {
@Accessor("addressField")
TextFieldWidget Mixin_GetAddressField();}
@Mixin(DirectConnectScreen.class)
public class MixinDirectConnectScreen {
@Redirect(method = "saveAndClose", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/TextFieldWidget;getText()Ljava/lang/String;"))
private String trimGetText(TextFieldWidget instance) {
if( Settings.ModEnabled == false ) { return instance.getText(); }
String trimmedText = instance.getText().replace(" ", "");
((DirectConnectScreenAccessor) this).Mixin_GetAddressField().setText(trimmedText);
return trimmedText;}}
@@ -1,19 +0,0 @@
package xyz.thewhitedog9487.mixin.client;
import net.minecraft.client.network.ServerInfo;
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 java.nio.file.Paths;
@Mixin(ServerInfo.class)
public class MixinServerInfo {
@Redirect(method = "<init>", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/network/ServerInfo;address:Ljava/lang/String;"))
private void RemoveSpace_Write(ServerInfo original, String value) {
if( Settings.ModEnabled == false ) {
original.address = value;
return; }
else { original.address = value.replace(" ", ""); } }}
@@ -0,0 +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 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) {
@Nullable String RawValue = value;
if (SettingsInstance.ModEnabled == false ||
RawValue.contains(" ") == false) {
original.ip = value;
return; }
else {
var NewValue = RawValue.replace(" ", "");
original.ip = NewValue;
ModLogger.info("已完成移除空格替换!" + "\n" +
"原始值:" + RawValue + "\n" +
"新值:" + NewValue); } } }
@@ -0,0 +1,15 @@
{
"required": true,
"package": "xyz.thewhitedog9487.mixin.client",
"compatibilityLevel": "JAVA_25",
"client": [
"DirectJoinServerScreenMixin",
"ManageServerScreenMixin",
"ServerDataMixin"
],
"injectors": {
"defaultRequire": 1
},
"mixins": [
]
}
@@ -1,14 +0,0 @@
{
"required": true,
"package": "xyz.thewhitedog9487.mixin.client",
"compatibilityLevel": "JAVA_21",
"client": [
"DirectConnectScreenAccessor",
"MixinAddServerScreen",
"MixinDirectConnectScreen",
"MixinServerInfo"
],
"injectors": {
"defaultRequire": 1
}
}
@@ -2,15 +2,16 @@ package xyz.thewhitedog9487;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import org.slf4j.Logger; /**
import org.slf4j.LoggerFactory; * 所有的代码都在client源集内
* @deprecated 目前没有任何用途
* @see ServerAddressSpaceFixClient
*/
@Deprecated @Deprecated
public class ServerAddressSpaceFix implements ModInitializer { public class ServerAddressSpaceFix implements ModInitializer {
// This logger is used to write text to the console and the log file. // 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. // 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. // That way, it's clear which mod wrote info, warnings, and errors.
public static final Logger LOGGER = LoggerFactory.getLogger("twd-sasf");
@Override @Override
public void onInitialize() { public void onInitialize() {
@@ -18,6 +19,5 @@ public class ServerAddressSpaceFix implements ModInitializer {
// However, some things (like resources) may still be uninitialized. // However, some things (like resources) may still be uninitialized.
// Proceed with mild caution. // Proceed with mild caution.
LOGGER.info("Hello Fabric world!");
} }
} }

Before

Width:  |  Height:  |  Size: 453 B

After

Width:  |  Height:  |  Size: 453 B

@@ -0,0 +1,10 @@
{
"modmenu.nameTranslation.serveraddressspacefix": "ServerAddressSpaceFix",
"modmenu.descriptionTranslation.serveraddressspacefix": "Fixed the \"unknown host\" bug caused by the server address containing spaces at the beginning and end of the server address when adding a server or connecting directly\nTip: If you need to use the configuration menu, install the YetAnotherConfigLib mod",
"serveraddressspacefix.bilibili": "Bilibili",
"serveraddressspacefix.blog": "Blog",
"title.serveraddressspacefix.config": "ServerAddressSpaceFix",
"config.serveraddressspacefix.category.general": "General",
"option.serveraddressspacefix.ModEnabled": "Whether To Enable The Mod Feature",
"option.serveraddressspacefix.ModEnabled.description": "There is no need to restart the game, and the modification will take effect immediately after it is saved"
}
@@ -0,0 +1,10 @@
{
"modmenu.nameTranslation.serveraddressspacefix": "服务器地址首尾空格修复",
"modmenu.descriptionTranslation.serveraddressspacefix": "修复添加服务器或直接连接时,服务器地址首尾包含空格导致的“未知的主机”Bug\n提示:如果需要使用配置菜单,请安装YetAnotherConfigLib模组",
"serveraddressspacefix.bilibili": "哔哩哔哩主页",
"serveraddressspacefix.blog": "TheWhiteDog9487的博客",
"title.serveraddressspacefix.config": "服务器地址首尾空格修复",
"config.serveraddressspacefix.category.general": "通用",
"option.serveraddressspacefix.ModEnabled": "是否启用模组功能",
"option.serveraddressspacefix.ModEnabled.description": "无需重启游戏,修改并保存后立刻生效"
}
@@ -1,10 +0,0 @@
{
"modmenu.nameTranslation.twd-sasf": "ServerAddressSpaceFix",
"modmenu.descriptionTranslation.twd-sasf": "Fixed the \"unknown host\" bug caused by the server address containing spaces at the beginning and end of the server address when adding a server or connecting directly\nTip: If you need to use the configuration menu, install the YetAnotherConfigLib mod",
"twd-sasf.bilibili": "Bilibili",
"twd-sasf.blog": "Blog",
"title.twd-sasf.config": "ServerAddressSpaceFix",
"config.twd-sasf.category.general": "General",
"option.twd-sasf.ModEnabled": "Whether To Enable The Mod Feature",
"option.twd-sasf.ModEnabled.description": "There is no need to restart the game, and the modification will take effect immediately after it is saved"
}
@@ -1,10 +0,0 @@
{
"modmenu.nameTranslation.twd-sasf": "服务器地址首尾空格修复",
"modmenu.descriptionTranslation.twd-sasf": "修复添加服务器或直接连接时,服务器地址首尾包含空格导致的“未知的主机”Bug\n提示:如果需要使用配置菜单,请安装YetAnotherConfigLib模组",
"twd-sasf.bilibili": "哔哩哔哩主页",
"twd-sasf.blog": "TheWhiteDog9487的博客",
"title.twd-sasf.config": "服务器地址首尾空格修复",
"config.twd-sasf.category.general": "通用",
"option.twd-sasf.ModEnabled": "是否启用模组功能",
"option.twd-sasf.ModEnabled.description": "无需重启游戏,修改并保存后立刻生效"
}
+17 -11
View File
@@ -1,6 +1,6 @@
{ {
"schemaVersion": 1, "schemaVersion": 1,
"id": "twd-sasf", "id": "serveraddressspacefix",
"version": "${version}", "version": "${version}",
"name": "ServerAddressSpaceFix", "name": "ServerAddressSpaceFix",
"description": "服务器地址首尾空格修复", "description": "服务器地址首尾空格修复",
@@ -13,31 +13,37 @@
"issues": "https://github.com/TheWhiteDog9487/ServerAddressSpaceFix/issues" "issues": "https://github.com/TheWhiteDog9487/ServerAddressSpaceFix/issues"
}, },
"license": "WTFPL", "license": "WTFPL",
"icon": "assets/twd-sasf/icon.png", "icon": "assets/serveraddressspacefix/icon.png",
"environment": "client", "environment": "client",
"entrypoints": { "entrypoints": {
"client": [ "xyz.thewhitedog9487.ServerAddressSpaceFixClient" ], "client": [ "xyz.thewhitedog9487.ServerAddressSpaceFixClient" ],
"modmenu": [ "xyz.thewhitedog9487.ModMenu" ] "modmenu": [ "xyz.thewhitedog9487.ModMenu" ]
}, },
"mixins": [ "mixins": [
"twd-sasf.mixins.json", "serveraddressspacefix.mixins.json",
{ {
"config": "twd-sasf.client.mixins.json", "config": "serveraddressspacefix.client.mixins.json",
"environment": "client" "environment": "client"
} }
], ],
"depends": { "depends": {
"fabricloader": ">=0.15.11", "fabricloader": ">=0.18.4",
"minecraft": ["1.21","1.21.*"], "fabric-api": ">=0.144.0",
"java": ">=21" "minecraft": "26.*",
"java": ">=25"
}, },
"suggests": { "suggests": {
"another-mod": "*" "modmenu": "*",
"yet_another_config_lib_v3": "*"
}, },
"custom": { "custom": {
"modmenu": { "modmenu": {
"links": { "links": {
"twd-sasf.bilibili": "https://space.bilibili.com/401746666", "serveraddressspacefix.bilibili": "https://space.bilibili.com/401746666",
"twd-sasf.blog": "www.thewhitedog9487.xyz"}, "serveraddressspacefix.blog": "https://www.thewhitedog9487.xyz"},
"update_checker": true}} "update_checker": true } },
"contributors": [
"JustAlittleWolf"
],
"accessWidener": "serveraddressspacefix.classtweaker"
} }
@@ -0,0 +1,2 @@
classTweaker v1 official
accessible field net/minecraft/client/gui/screens/multiplayer/JoinMultiplayerScreen editingServer Lnet/minecraft/client/multiplayer/ServerData;
@@ -1,7 +1,7 @@
{ {
"required": true, "required": true,
"package": "xyz.thewhitedog9487.mixin", "package": "xyz.thewhitedog9487.mixin",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_25",
"mixins": [], "mixins": [],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1
+35
View File
@@ -1,3 +1,38 @@
# 0.2.5
时间:2026 06 17
修复Windows文件系统对大小写不敏感导致配置文件迁移会实际上导致原始配置文件被删除的问题
# 0.2.4
时间:2026 06 17
1. 修复未安装YACL会导致游戏出现`NoClassDefFoundError`崩溃的问题
2. 将配置文件名从`serveraddressspacefix.json5`改为`ServerAddressSpaceFix.json5`
3. 为配置文件添加版本号
4. 更改Logger名称
# 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
2. 由于源码变更,更换了一个新的实现方案,稍微测试了一下没太大毛病,应该还行
# 0.2.1
时间:2024 10 30
主要内容:
加大剂量,以前不会对服务器列表中已经保存的服务器地址进行处理,现在只要模组处于启用状态会直接对所有地址进行消除空格替换,确保不留死角。
说人话:未安装或未启用本模组时添加的服务器地址如果有空格,在启用本模组之后会在打开“多人游戏”窗口时被处理掉。
# 0.2.0
时间:2024 06 14
主要内容:
1. 更新适配的游戏版本到1.21/1.21.x
2. 翻译键移除thewhitedog9487的命名空间
# 0.1.4 # 0.1.4
时间:2024 01 15 时间:2024 01 15
主要内容: 主要内容: