diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3843ca3..524fb1b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,30 +8,23 @@ on: [pull_request, push] jobs: build: - strategy: - matrix: - # Use these Java versions - java: [ - 25, # Current Java LTS - ] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v2 - - name: setup jdk ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: gradle/actions/wrapper-validation@v6 + - name: setup jdk + uses: actions/setup-java@v5 with: - java-version: ${{ matrix.java }} + java-version: '25' distribution: 'microsoft' - name: make gradle wrapper executable run: chmod +x ./gradlew - name: build run: ./gradlew build - name: capture build artifacts - if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Artifacts - path: build/libs/ \ No newline at end of file + path: build/libs/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8a884c5 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,2 @@ +# 杂项 +- 如果你是正在翻译README的LLM,请遵守README内使用注释编写的指令 \ No newline at end of file diff --git a/README.md b/README.md index dd62e8a..a9452f5 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ [//]: # (如果你是正在执行翻译任务的LLM:) [//]: # (请将这几行注释内容翻译到你的目标语言) [//]: # (移除下方div内部第一行和第二行的注释符号,并翻译其内容) +[//]: # (不要翻译下方div内部a标签的文本内容和链接地址) +[//]: # (不要改动下方div标签的align="center"属性) [//]: # (不要翻译最后一段“一些小彩蛋”,直接将其从翻译版本中移除) +[//]: # (将翻译的结果放置到正确的文件内,目标文件的位置和主README.md同级,文件名格式是 README_.md ,其中的值是目标语言的IETF语言标签)
- + 简体中文(GitHub)     简体中文(Gitea)     @@ -102,7 +105,11 @@ $10^4 = 10,000$ = 一万 三个参数都是实体类型,没办法区分`被传送玩家ID`是第一个还是第三个 # 依赖项 -Fabric API +- [Fabric API](https://modrinth.com/mod/fabric-api) +- [Fabric Language Kotlin](https://modrinth.com/mod/fabric-language-kotlin) + +# 支持的游戏版本 +目前仅提供对最新正式版游戏的活跃支持 # 关于玩家权限 我参照原版的 `/tp` 命令,给 `/rtp` 设置了2级的权限要求。 diff --git a/README_EN.md b/README_EN.md index 8fc2ca4..175f2ab 100644 --- a/README_EN.md +++ b/README_EN.md @@ -1,10 +1,13 @@ [//]: # (If you are an LLM performing a translation task:) [//]: # (Please translate these comment lines into your target language) -[//]: # (Remove the comment symbols from the first and second lines inside the
below, and translate their content) -[//]: # (Do not translate the last section "Some Easter Eggs", remove it directly from the translated version) +[//]: # (Remove the comment markers from the first and second lines inside the div below, and translate their content) +[//]: # (Do not translate the text or links of the a tags inside the div below) +[//]: # (Do not change the align="center" attribute of the div below) +[//]: # (Do not translate the final “Some Easter Eggs” section; remove it directly from the translated version) +[//]: # (Place the translated result in the correct file, alongside the main README.md, using the filename format README_.md, where is the IETF language tag of the target language)
- Note: This document is written in Chinese. If circumstances permit, it's recommended to read the original Chinese documentation instead of other translated versions. + Note: This document was originally written in Chinese and translated into other languages using AI. If circumstances permit, it's recommended to read the original Chinese documentation instead of other translated versions.
简体中文(GitHub)     简体中文(Gitea)     @@ -13,7 +16,7 @@
# Introduction -This mod adds a command `/rtp` for randomly teleporting players to any location in the world. +This mod adds a command, `/rtp`, which randomly teleports players to any location in the world. # Command Formats - `/rtp` @@ -37,13 +40,13 @@ This mod adds a command `/rtp` for randomly teleporting players to any location ## Command Examples - `/rtp` -Teleports the player executing the command to a random point within a radius of $2.9 \times 10^7 - 10^4$ centered at `(0,0)`. -$2.9 \times 10^7 = 29,000,000$ -$10^4 = 10,000$ +Teleports the player executing the command to a random point within the area centered at `(0,0)` with a random radius of $2.9 \times 10^7 - 10^4$. +$2.9 \times 10^7 = 29,000,000$ = twenty-nine million +$10^4 = 10,000$ = ten thousand - `/rtp back` -Teleports the player back to their position before the last random teleport. -**Note: The previous position information is only stored during the game (server) session and will be lost after the game (server) is closed.** +Teleports the player back to their position before the most recent random teleport. +**Note: The previous-position information saved by this feature exists only while the game (server) is running. It will be lost after the game (server) is closed.** - `/rtp back TheWhiteDog9487` Teleports `TheWhiteDog9487` back to their position before their last random teleport. @@ -55,7 +58,7 @@ Teleports `TheWhiteDog9487` back to their position before their last random tele Teleports the player to a random point within a radius of `1000` centered at `(0,0)`. - `/rtp TheWhiteDog9487` -Teleports `TheWhiteDog9487` to a random point within a radius of $2.9 \times 10^7 - 10^4$ centered at `(0,0)`. +Teleports `TheWhiteDog9487` to a random point within the area centered at `(0,0)` with a random radius of $2.9 \times 10^7 - 10^4$. - `/rtp TheWhiteDog9487 1000` Teleports `TheWhiteDog9487` to a random point within a radius of `1000` centered at `(0,0)`. @@ -79,8 +82,8 @@ Teleports `TheWhiteDog9487` to a random point within a radius of `1000` centered Teleports `TheWhiteDog9487` to a random point within a radius of `1000` centered at `(10000,10000)`. - `/rtp 10000.0 10000.0 20000.0 20000.0` -Teleports the player to a random point within a rectangular region formed by vertices `(10000,10000)`, `(20000,10000)`, `(20000,20000)`, and `(10000,20000)`. -You need to provide any vertex and its diagonally opposite vertex of this rectangle. +Teleports the player to a random point within the rectangular region formed by the vertices `(10000,10000)`, `(20000,10000)`, `(20000,20000)`, and `(10000,20000)`. +You only need to provide any one vertex of the rectangle and the diagonally opposite vertex. - `/rtp TheWhiteDog9487 10000.0 10000.0 20000.0 20000.0` Teleports `TheWhiteDog9487` to a random point within the same rectangular region described above. @@ -89,23 +92,34 @@ Teleports `TheWhiteDog9487` to a random point within the same rectangular region Teleports `TheWhiteDog9487` to a random point within the same rectangular region described above. - `/rtp TheWhiteDog9487 TheWhiteDog_CN` -Teleports the command executor to a random point within a rectangular region where `TheWhiteDog9487` and `TheWhiteDog_CN`'s current positions are diagonals. +Teleports the command executor to a random point within a rectangular region whose diagonals are the current positions of `TheWhiteDog9487` and `TheWhiteDog_CN`. - `/rtp TheWhiteDog9487 TheWhiteDog_CN TheWhiteDog4568` -Teleports `TheWhiteDog4568` to a random point within a rectangular region where `TheWhiteDog9487` and `TheWhiteDog_CN`'s current positions are diagonals. +Teleports `TheWhiteDog4568` to a random point within a rectangular region whose diagonals are the current positions of `TheWhiteDog9487` and `TheWhiteDog_CN`. ### Special Notes -The format `/rtp ` does not exist because the second parameter could be either the teleported player's name or the entity serving as the random center. Both are entity types, leading to ambiguity. Similarly, `/rtp ` is also absent as all three parameters are entity types, making it impossible to distinguish the player ID. +The format `/rtp ` does not exist because the second parameter could be either the teleported player's name or the entity used as the random center. Both are entity types, so there is no way to tell which one it is. Likewise, `/rtp ` does not exist either, because all three parameters are entity types, making it impossible to determine which one is the player ID. # Dependencies -Fabric API +- [Fabric API](https://modrinth.com/mod/fabric-api) +- [Fabric Language Kotlin](https://modrinth.com/mod/fabric-language-kotlin) -# Player Permissions -Following the standard `/tp` command, `/rtp` requires a permission level of `2`. For vanilla or vanilla-like servers, players only need "cheats" enabled. For plugin-based servers, specific permission management depends on your setup. +# Supported Game Versions +Currently, only the latest official release is actively supported. -# Installation: Client or Server? -- **Singleplayer**: Install on the client. -- **Singleplayer + Open to LAN**: Install on the host client. Other players do not need to install it. -- **Dedicated Server**: Install on the server. Clients do not strictly need to install it. +# About Player Permissions +Following the vanilla `/tp` command, `/rtp` is set to require permission level `2`. In vanilla or vanilla-like environments, players only need cheat permissions enabled to use it. As for plugin servers, I do not have enough firsthand experience to give specific advice about permission setup. -**Note**: In multiplayer scenarios, if clients do not have the mod installed, they will see command feedback in the server's default language (currently Chinese). Installing the mod on both sides is recommended for full multi-language support. \ No newline at end of file +# Install on the Client or on the Server? +It depends on the case: +1. Singleplayer + 1. There is no physical server, so the server side does not matter. + 2. Installing it on the client is enough. +2. Singleplayer + Open to LAN + 1. This uses the client’s built-in server, so the player who opens the LAN world needs the mod installed on their client. + 2. Other players who join do not need to install it. +3. Dedicated server (something like a `server.jar` file) + 1. The server needs the mod installed. + 2. Clients do not need it. + +**Note: In cases 2 and 3, if other players do not install this mod, they will not be able to see the command feedback in the correct translated language, and the default display in that case is Chinese text. If you need to view multilingual translation text, it is probably best for everyone to install it.** diff --git a/build.gradle.kts b/build.gradle.kts index b194408..8ec05c1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,14 +1,13 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { - id("net.fabricmc.fabric-loom") version "1.16-SNAPSHOT" - id("maven-publish") + id("net.fabricmc.fabric-loom") + `maven-publish` + id("org.jetbrains.kotlin.jvm") version "2.3.21" } -version = project.extra["mod_version"] as String -group = project.extra["maven_group"] as String - -base { - archivesName.set(project.extra["archives_base_name"] as String) -} +version = providers.gradleProperty("mod_version").get() +group = providers.gradleProperty("maven_group").get() repositories { // Add repositories to retrieve artifacts from in here. @@ -25,19 +24,22 @@ loom { splitEnvironmentSourceSets() mods { - val mod = create("randomteleporter") - mod.sourceSet("main") - mod.sourceSet("client") + register("randomteleporter") { + sourceSet(sourceSets.main.get()) + sourceSet(sourceSets.getByName("client")) + } } } dependencies { // To change the versions see the gradle.properties file - minecraft("com.mojang:minecraft:${project.extra["minecraft_version"]}") - implementation("net.fabricmc:fabric-loader:${project.extra["loader_version"]}") + 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. - implementation("net.fabricmc.fabric-api:fabric-api:${project.extra["fabric_api_version"]}") + implementation("net.fabricmc.fabric-api:fabric-api:${providers.gradleProperty("fabric_api_version").get()}") + implementation("net.fabricmc:fabric-language-kotlin:${providers.gradleProperty("fabric_kotlin_version").get()}") // Uncomment the following line to enable the deprecated Fabric API modules. // 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. @@ -47,17 +49,22 @@ dependencies { // runtimeOnly("com.terraformersmc:modmenu:${project.extra["modmenu_version"]}") } + tasks.processResources { - inputs.property("version", project.version) + val version = version + inputs.property("version", version) filesMatching("fabric.mod.json") { - expand("version" to project.version) + expand("version" to version) } } -tasks.withType { - options.release.set(25) -} +tasks.withType().configureEach { + options.release = 25 } + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_25 } } java { // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task @@ -66,23 +73,25 @@ java { withSourcesJar() sourceCompatibility = JavaVersion.VERSION_25 - targetCompatibility = JavaVersion.VERSION_25 -} + targetCompatibility = JavaVersion.VERSION_25 } tasks.jar { + val projectName = project.name + inputs.property("projectName", projectName) + from("LICENSE") { - rename { "${it}_${project.base.archivesName.get()}" } } + rename { "${it}_$projectName" } } // https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:archiveFileName - archiveFileName = "${project.base.archivesName.get()}-${project.version} mc${project.extra["minecraft_version"]}.jar"} + archiveFileName = "RandomTeleporter-${project.version} mc${project.extra["minecraft_version"]}.jar"} tasks.named("sourcesJar") { - archiveFileName = "${project.base.archivesName.get()}-${project.version} mc${project.extra["minecraft_version"]}-sources.jar"} + archiveFileName = "RandomTeleporter-${project.version} mc${project.extra["minecraft_version"]}-sources.jar"} // configure the maven publication publishing { publications { - create("mavenJava") { + register("mavenJava") { from(components["java"]) } } diff --git a/gradle.properties b/gradle.properties index a495230..04e3338 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,11 +6,12 @@ org.gradle.parallel=true # check these on https://fabricmc.net/develop minecraft_version=26.1.2 loader_version=0.18.6 +loom_version=1.16-SNAPSHOT +fabric_kotlin_version=1.13.11+kotlin.2.3.21 # Mod Properties -mod_version=0.5.2 +mod_version=0.5.3 maven_group=xyz.thewhitedog9487 -archives_base_name=RandomTeleporter # Dependencies fabric_api_version=0.145.4+26.1.2 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135..d997cfc 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7eae1dd..1a70468 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https://services.gradle.org/distributions/gradle-9.4.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0adc8e1..739907d 100644 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (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 # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (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/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # 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. MAX_FD=maximum @@ -112,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -145,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # 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 ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # 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" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -170,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 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. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..c4bdd3a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle.kts b/settings.gradle.kts index 6de9537..1b59558 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,4 +6,11 @@ pluginManagement { mavenCentral() gradlePluginPortal() } -} \ No newline at end of file + + plugins { + id("net.fabricmc.fabric-loom") version providers.gradleProperty("loom_version") + } +} + +// Should match your modid +rootProject.name = "randomteleporter" diff --git a/src/client/java/xyz/thewhitedog9487/RandomTeleporterClient.java b/src/client/java/xyz/thewhitedog9487/RandomTeleporterClient.java deleted file mode 100644 index 2bf805e..0000000 --- a/src/client/java/xyz/thewhitedog9487/RandomTeleporterClient.java +++ /dev/null @@ -1,10 +0,0 @@ -package xyz.thewhitedog9487; - -import net.fabricmc.api.ClientModInitializer; - -public class RandomTeleporterClient implements ClientModInitializer { - @Override - public void onInitializeClient() { - // This entrypoint is suitable for setting up client-specific logic, such as rendering. - } -} \ No newline at end of file diff --git a/src/client/java/xyz/thewhitedog9487/mixin/client/ExampleClientMixin.java b/src/client/java/xyz/thewhitedog9487/client/mixin/ExampleClientMixin.java similarity index 91% rename from src/client/java/xyz/thewhitedog9487/mixin/client/ExampleClientMixin.java rename to src/client/java/xyz/thewhitedog9487/client/mixin/ExampleClientMixin.java index ddd1acc..b9e360b 100644 --- a/src/client/java/xyz/thewhitedog9487/mixin/client/ExampleClientMixin.java +++ b/src/client/java/xyz/thewhitedog9487/client/mixin/ExampleClientMixin.java @@ -1,4 +1,4 @@ -package xyz.thewhitedog9487.mixin.client; +package xyz.thewhitedog9487.client.mixin; import net.minecraft.client.Minecraft; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/client/kotlin/xyz/thewhitedog9487/client/RandomTeleporterClient.kt b/src/client/kotlin/xyz/thewhitedog9487/client/RandomTeleporterClient.kt new file mode 100644 index 0000000..9321296 --- /dev/null +++ b/src/client/kotlin/xyz/thewhitedog9487/client/RandomTeleporterClient.kt @@ -0,0 +1,9 @@ +package xyz.thewhitedog9487.client + +import net.fabricmc.api.ClientModInitializer + +object RandomTeleporterClient : ClientModInitializer { + override fun onInitializeClient() { + // This entrypoint is suitable for setting up client-specific logic, such as rendering. + } +} \ No newline at end of file diff --git a/src/client/resources/randomteleporter.client.mixins.json b/src/client/resources/randomteleporter.client.mixins.json index 6386c2b..3e0df76 100644 --- a/src/client/resources/randomteleporter.client.mixins.json +++ b/src/client/resources/randomteleporter.client.mixins.json @@ -1,11 +1,14 @@ { - "required": false, - "package": "xyz.thewhitedog9487.mixin.client", - "compatibilityLevel": "JAVA_21", + "required": true, + "package": "xyz.thewhitedog9487.client.mixin", + "compatibilityLevel": "JAVA_25", "client": [ - + "ExampleClientMixin" ], "injectors": { "defaultRequire": 1 + }, + "overwrites": { + "requireAnnotations": true } } \ No newline at end of file diff --git a/src/main/java/xyz/thewhitedog9487/CommandRegister.java b/src/main/java/xyz/thewhitedog9487/CommandRegister.java deleted file mode 100644 index 2e8c651..0000000 --- a/src/main/java/xyz/thewhitedog9487/CommandRegister.java +++ /dev/null @@ -1,412 +0,0 @@ -package xyz.thewhitedog9487; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.arguments.IntegerArgumentType; -import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; -import net.minecraft.commands.Commands; -import net.minecraft.server.commands.TeleportCommand; -import net.minecraft.server.permissions.PermissionCheck; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.coordinates.Vec2Argument; -import net.minecraft.world.entity.Entity; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.network.chat.Component; -import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.Vec2; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.phys.Vec3; -import org.jspecify.annotations.Nullable; - -import module java.base; - -import static net.minecraft.commands.Commands.argument; -import static net.minecraft.commands.Commands.literal; -import static net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES; -import static xyz.thewhitedog9487.ResourceReloaderListener.*; - -public class CommandRegister { - - /** - * 随机数生成器 - */ - final static SplittableRandom SR = new SplittableRandom(); - - /** - * 传送后用于生成保护平台的方块 - */ - final static Block TargetBlock = Blocks.GLASS; - - /** - * 传送后会被 {@link CommandRegister#TargetBlock} 替换掉的方块 - *
- * 替换中心:被传送目标脚下方块 - *
- * 替换范围:替换中心周围半径为一的正方形区域 - */ - final static Set ReplaceToTargetBlock = Set.of( - Blocks.AIR, - Blocks.VOID_AIR, - Blocks.CAVE_AIR, - Blocks.WATER, - Blocks.LAVA, - Blocks.SHORT_GRASS, - Blocks.VINE ); - - /** - * 世界边界 - *
- * @see Minecraft Wiki (中文) - * @see Minecraft Wiki (English) - */ - final static Integer WorldBorder = (int) 2.9e7; - - /** - * 执行命令所需权限等级 - * @see TeleportCommand - * @see Commands - * @see Minecraft Wiki (中文) - * @see Minecraft Wiki (English) - */ - final static PermissionCheck PermissionLevel = Commands.LEVEL_GAMEMASTERS; - - /** - * 在传送之前记录当前位置,以支持传送回去 - */ - static Map OldPositions = new HashMap<>(); - - /** - * 命令执行失败时的返回值 - * @see Minecraft Wiki (中文) - * @see Minecraft Wiki (English) - */ - final static int CommandExecuteFailure = 0; - - /** - * 使用Fabric API向游戏内注册命令 - * @param Name 根命令名 - *
- * @see Fabric Docs (中文) - * @see Fabric Wiki (中文) - * @see Fabric Docs (English) - * @see Fabric Wiki (English) - */ - public static void Register(String Name){ - CommandRegistrationCallback.EVENT - .register((dispatcher, registryAccess, environment) ->{ - dispatcher.register(literal(Name) - // /rtp - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(),null,null, null, null, null)) - // /rtp back - .then(literal("back") - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> TeleportBack( - context.getSource(), null))) - // /rtp back - .then(literal("back") - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> TeleportBack( - context.getSource(), - EntityArgument.getEntity(context,CommandArgumentName_Target))))) - // /rtp back - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .then(literal("back") - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> TeleportBack( - context.getSource(), - EntityArgument.getEntity(context,CommandArgumentName_Target))))) - // /rtp - .then(argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - IntegerArgumentType.getInteger(context, CommandArgumentName_Radius), - null, - null, - null, - null))) - // /rtp - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - null, - EntityArgument.getEntity(context,CommandArgumentName_Target), - null, - null, - null))) - // /rtp - .then(argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - IntegerArgumentType.getInteger(context, CommandArgumentName_Radius), - EntityArgument.getEntity(context,CommandArgumentName_Target), - null, - null, - null)))) - // /rtp - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .then(argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - IntegerArgumentType.getInteger(context, CommandArgumentName_Radius), - EntityArgument.getEntity(context,CommandArgumentName_Target), - null, - null, - null)))) -// // /rtp -// .then(argument("Radius(半径)", LongArgumentType.longArg()) -// .then(argument("Origin(随机中心)",EntityArgumentType.player()) -// .requires(Commands.hasPermission(PermissionLevel)) -// .executes(context -> execute_command_origin( -// context.getSource(), -// LongArgumentType.getLong(context, "Radius(半径)"), -// null, -// EntityArgumentType.getEntity(context,"Origin(随机中心)"))))) - // /rtp - .then(argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) - .then(argument(CommandArgumentName_OriginPosition, Vec2Argument.vec2()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - IntegerArgumentType.getInteger(context, CommandArgumentName_Radius), - null, - Vec2Argument.getVec2(context,CommandArgumentName_OriginPosition), - null, - null)))) - // /rtp - .then(argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .then(argument(CommandArgumentName_OriginEntity, EntityArgument.entity()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - IntegerArgumentType.getInteger(context, CommandArgumentName_Radius), - EntityArgument.getEntity(context,CommandArgumentName_Target), - new Vec2( (float) EntityArgument.getEntity( context,CommandArgumentName_OriginEntity).position().x, - (float) EntityArgument.getEntity( context,CommandArgumentName_OriginEntity).position().z ), - null, - null))))) - // /rtp - .then(argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .then(argument(CommandArgumentName_OriginPosition, Vec2Argument.vec2()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - IntegerArgumentType.getInteger(context, CommandArgumentName_Radius), - EntityArgument.getEntity(context,CommandArgumentName_Target), - Vec2Argument.getVec2(context,CommandArgumentName_OriginPosition), - null, - null))))) - // /rtp - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .then(argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) - .then(argument(CommandArgumentName_OriginEntity, EntityArgument.entity()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - IntegerArgumentType.getInteger(context, CommandArgumentName_Radius), - EntityArgument.getEntity(context,CommandArgumentName_Target), - new Vec2( (float) EntityArgument.getEntity( context,CommandArgumentName_OriginEntity).position().x, - (float) EntityArgument.getEntity( context,CommandArgumentName_OriginEntity).position().z ), - null, - null))))) - // /rtp - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .then(argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) - .then(argument(CommandArgumentName_OriginPosition, Vec2Argument.vec2()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - IntegerArgumentType.getInteger(context, CommandArgumentName_Radius), - EntityArgument.getEntity(context,CommandArgumentName_Target), - Vec2Argument.getVec2(context,CommandArgumentName_OriginPosition), - null, - null))))) - // /rtp - .then(argument(CommandArgumentName_RegionFromPosition, Vec2Argument.vec2()) - .then(argument(CommandArgumentName_RegionToPosition, Vec2Argument.vec2()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - null, - null, - null, - Vec2Argument.getVec2(context, CommandArgumentName_RegionFromPosition), - Vec2Argument.getVec2(context, CommandArgumentName_RegionToPosition))))) - // /rtp - .then(argument(CommandArgumentName_RegionFromPosition, Vec2Argument.vec2()) - .then(argument(CommandArgumentName_RegionToPosition, Vec2Argument.vec2()) - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - null, - EntityArgument.getEntity(context,CommandArgumentName_Target), - null, - Vec2Argument.getVec2(context, CommandArgumentName_RegionFromPosition), - Vec2Argument.getVec2(context, CommandArgumentName_RegionToPosition)))))) - // /rtp - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .then(argument(CommandArgumentName_RegionFromPosition, Vec2Argument.vec2()) - .then(argument(CommandArgumentName_RegionToPosition, Vec2Argument.vec2()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - null, - EntityArgument.getEntity(context,CommandArgumentName_Target), - null, - Vec2Argument.getVec2(context, CommandArgumentName_RegionFromPosition), - Vec2Argument.getVec2(context, CommandArgumentName_RegionToPosition)))))) - // /rtp - .then(argument(CommandArgumentName_RegionFromEntity, EntityArgument.entity()) - .then(argument(CommandArgumentName_RegionToEntity, EntityArgument.entity()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - null, - null, - null, - new Vec2( (float) EntityArgument.getEntity( context,CommandArgumentName_RegionFromEntity).position().x, - (float) EntityArgument.getEntity( context,CommandArgumentName_RegionFromEntity).position().z ), - new Vec2( (float) EntityArgument.getEntity( context,CommandArgumentName_RegionToEntity).position().x, - (float) EntityArgument.getEntity( context,CommandArgumentName_RegionToEntity).position().z ) ) ))) - // /rtp - .then(argument(CommandArgumentName_RegionFromEntity, EntityArgument.entity()) - .then(argument(CommandArgumentName_RegionToEntity, EntityArgument.entity()) - .then(argument(CommandArgumentName_Target, EntityArgument.entity()) - .requires(Commands.hasPermission(PermissionLevel)) - .executes(context -> ExecuteCommand( - context.getSource(), - null, - EntityArgument.getEntity(context,CommandArgumentName_Target), - null, - new Vec2( (float) EntityArgument.getEntity( context,CommandArgumentName_RegionFromEntity).position().x, - (float) EntityArgument.getEntity( context,CommandArgumentName_RegionFromEntity).position().z ), - new Vec2( (float) EntityArgument.getEntity( context,CommandArgumentName_RegionToEntity).position().x, - (float) EntityArgument.getEntity( context,CommandArgumentName_RegionToEntity).position().z )))))) );});} - - /** - * 向游戏内注册命令 - *
- * 是 {@link CommandRegister#Register(String)} 的包装器 - * @see CommandRegister#Register(String) - */ - public static void Register(){ - Register("随机传送"); - Register("rtp"); - } - - /** - * - * @param Source 命令执行者 - * @param Radius 随机选择的目的坐标距离参数 {@code Origin} 的最大距离 - * @param Entity 被传送的实体 - * @param Origin 随机选择的目的坐标的中心 - * @param RegionFrom 选择随机坐标的范围的起始坐标 - * @param RegionTo 选择随机坐标的范围的结束坐标 - * @return 命令运行是否成功 - */ - static int ExecuteCommand(CommandSourceStack Source, @Nullable Integer Radius, @Nullable Entity Entity, @Nullable Vec2 Origin, @Nullable Vec2 RegionFrom, @Nullable Vec2 RegionTo){ - Entity TargetEntity = Entity == null ? Source.getPlayer() : Entity; - /* - ↑ - Entity TargetEntity = null; - if (TargetEntity == null){ - TargetEntity = Source.getPlayer();} - else{ - TargetEntity = Entity;} - */ - if (TargetEntity == null) { - Source.sendSuccess(()->{ return Component.translatableWithFallback("error.no_target","不存在被传送目标,由非玩家物体执行命令时请显式指定被传送玩家ID"); }, true); - return CommandExecuteFailure; } - int Coordinate_X = 0; - int Coordinate_Z = 0; - if (RegionFrom == null || RegionTo == null) { // ← 按半径和中心取随机 - if (Radius == null) { Radius = (int) (WorldBorder - 1e4); } - // ↑ 远离世界边界 - try { - if (Origin == null) { - Coordinate_X = SR.nextInt(-Radius, Radius + 1); - Coordinate_Z = SR.nextInt(-Radius, Radius + 1); } - else { - Coordinate_X = SR.nextInt((int) Origin.x - Radius, (int) Origin.x + Radius + 1); - Coordinate_Z = SR.nextInt((int) Origin.y - Radius, (int) Origin.y + Radius + 1); } } - catch (IllegalArgumentException e) { - // 半径为零 - if (Origin == null) { - Source.sendFailure(Component.translatableWithFallback("warning.radius_equal_zero_no_target", "由于你设置的随机半径为0,并且未设置随机中心点坐标,因此什么都不会发生")); - return CommandExecuteFailure; } - else { - Coordinate_X = (int) Origin.x; - Coordinate_Z = (int) Origin.y; - int finalCoordinate_X1 = Coordinate_X; - int finalCoordinate_Z1 = Coordinate_Z; - // ↑ "lambda 表达式中使用的变量应为 final 或有效 final" - Source.sendSuccess(() -> { - return Component.translatableWithFallback("warning.radius_equal_zero", "警告:由于你设置的随机半径为0,因此在选择出合适高度之后将直接把你传送至%d %d", finalCoordinate_X1, finalCoordinate_Z1); }, true); } } } - else { // ← 按范围取随机 - Coordinate_X = SR.nextInt( Math.min( (int)RegionFrom.x, (int)RegionTo.x ), Math.max( (int)RegionFrom.x, (int)RegionTo.x ) + 1 ); - Coordinate_Z = SR.nextInt( Math.min( (int)RegionFrom.y, (int)RegionTo.y ), Math.max( (int)RegionFrom.y, (int)RegionTo.y ) + 1 ); } - if (Coordinate_X >= WorldBorder){ Coordinate_X = (int) (WorldBorder - 1e4); } - else if (Coordinate_X <= -WorldBorder){ Coordinate_X = (int) (-WorldBorder + 1e4); } - if (Coordinate_Z >= WorldBorder){ Coordinate_Z = (int) (WorldBorder - 1e4); } - else if (Coordinate_Z <= -WorldBorder){ Coordinate_Z = (int) (-WorldBorder + 1e4); } - // ↑ 远离世界边界 - Level EntityWorld = TargetEntity.level(); - EntityWorld.getChunk(Coordinate_X >> 4, Coordinate_Z >> 4, ChunkStatus.FULL, true); - // ↑ 加载目标区块,不然下面获取到的Coordinate_Y一定是-64 - // 按位右移4和除以16在被除数小于0时的结果不一致,一个是向上取整,一个是向下取整 - // 因此必须是 >> 4 ,不能是 / 16 - int Coordinate_Y = EntityWorld.getHeight(MOTION_BLOCKING_NO_LEAVES, Coordinate_X, Coordinate_Z); - BlockPos.MutableBlockPos BlockPos = new BlockPos.MutableBlockPos(); - for (int x = -1; x <= 1; x++) { - for (int z = -1; z <= 1; z++) { - // 如果传送到的位置周围一圈是ReplaceToTargetBlock的方块,将其替换为TargetBlock - BlockPos.set(Coordinate_X - x, Coordinate_Y - 1, Coordinate_Z - z); - var CurrentBlock = EntityWorld.getBlockState(BlockPos).getBlock(); - if ( ReplaceToTargetBlock.contains(CurrentBlock) ) { - // 只替换ReplaceToTargetBlock内的方块,其余保留 - EntityWorld.setBlockAndUpdate(BlockPos, TargetBlock.defaultBlockState());}}} -// if ( String.valueOf(TargetEntity.getWorld().getBiome(new BlockPos(Math.toIntExact(Coordinate_X), Coordinate_Y, Math.toIntExact(Coordinate_Z))).getKey()).equals("minecraft:the_void") ) { -// Coordinate_Y++;} - OldPositions.put(TargetEntity.getUUID(), TargetEntity.position()); - TargetEntity.teleportTo((ServerLevel) EntityWorld,Coordinate_X + 0.5, Coordinate_Y, Coordinate_Z + 0.5, new HashSet<>(), TargetEntity.getYRot(), TargetEntity.getXRot(), false); - int finalCoordinate_X = Coordinate_X; - int finalCoordinate_Z = Coordinate_Z; - // ↑ "lambda 表达式中使用的变量应为 final 或有效 final" - final var FeedbackFallbackString = String.format("已将玩家%s传送到%d %d %d", TargetEntity.getName().getString(), Coordinate_X, Coordinate_Y, Coordinate_Z); - Source.sendSuccess(()->{ return Component.translatableWithFallback("info.success", FeedbackFallbackString, TargetEntity.getName(), finalCoordinate_X, Coordinate_Y, finalCoordinate_Z); },true); - return Command.SINGLE_SUCCESS; } - - static int TeleportBack(CommandSourceStack Source, @Nullable Entity TargetEntity) { - TargetEntity = TargetEntity != null ? TargetEntity : Source.getPlayer(); - /* - ↑ - if (TargetEntity == null){ - TargetEntity = Source.getPlayer(); } - */ - if (TargetEntity == null) { - Source.sendFailure(Component.translatableWithFallback("error.no_target", "不存在被传送目标,由非玩家物体执行命令时请显式指定被传送玩家ID")); - return CommandExecuteFailure; } - var OldPos = OldPositions.get(TargetEntity.getUUID()); - if (OldPos == null) { - Source.sendFailure(Component.translatableWithFallback("error.no_old_position", "%s还未使用过随机传送,因此无法回溯", TargetEntity.getName().getString())); - return CommandExecuteFailure; } - else { - TargetEntity.teleportTo(( ServerLevel) TargetEntity.level(), OldPos.x, OldPos.y, OldPos.z, new HashSet<>(), TargetEntity.getYRot(), TargetEntity.getXRot(), false); - Entity finalTargetEntity = TargetEntity; - // ↑ "lambda 表达式中使用的变量应为 final 或有效 final" - Source.sendSuccess(() -> Component.translatableWithFallback("info.success.back", "已将玩家%s传送回原位置", finalTargetEntity.getName().getString()), true); - return Command.SINGLE_SUCCESS; } } -} \ No newline at end of file diff --git a/src/main/java/xyz/thewhitedog9487/RandomTeleporter.java b/src/main/java/xyz/thewhitedog9487/RandomTeleporter.java deleted file mode 100644 index 3b48c34..0000000 --- a/src/main/java/xyz/thewhitedog9487/RandomTeleporter.java +++ /dev/null @@ -1,26 +0,0 @@ -package xyz.thewhitedog9487; - -import net.fabricmc.api.ModInitializer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RandomTeleporter 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 MOD_ID = "randomteleporter"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - - @Override - public void onInitialize() { - // This code runs as soon as Minecraft is in a mod-load-ready state. - // However, some things (like resources) may still be uninitialized. - // Proceed with mild caution. - - ResourceReloaderListener.Register(); - ServerLifecycleListener.Register(); - CommandRegister.Register(); - LOGGER.info("RandomTeleporter已写入命令注册回调,目标命令将会在该注册的时候被注册"); - } -} \ No newline at end of file diff --git a/src/main/java/xyz/thewhitedog9487/ResourceReloaderListener.java b/src/main/java/xyz/thewhitedog9487/ResourceReloaderListener.java deleted file mode 100644 index 8352e82..0000000 --- a/src/main/java/xyz/thewhitedog9487/ResourceReloaderListener.java +++ /dev/null @@ -1,44 +0,0 @@ -package xyz.thewhitedog9487; - -import net.fabricmc.fabric.api.resource.v1.ResourceLoader; -import net.fabricmc.fabric.api.resource.v1.reloader.SimpleReloadListener; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.Identifier; -import net.minecraft.server.packs.resources.PreparableReloadListener; -import org.jspecify.annotations.NonNull; - -import static net.minecraft.server.packs.PackType.CLIENT_RESOURCES; -import static xyz.thewhitedog9487.RandomTeleporter.MOD_ID; - -/** - * 在游戏资源重新加载之后刷新翻译文本 - */ -public class ResourceReloaderListener { - public static String CommandArgumentName_Radius = "Radius(半径)"; - public static String CommandArgumentName_Target = "PlayerID(被传送玩家名)"; - public static String CommandArgumentName_OriginPosition = "OriginPos(随机中心,坐标)"; - public static String CommandArgumentName_OriginEntity = "OriginEntity(随机中心,实体)"; - public static String CommandArgumentName_RegionFromPosition = "RegionFrom(随机范围起始位置,坐标)"; - public static String CommandArgumentName_RegionToPosition = "RegionTo(随机范围结束位置,坐标)"; - public static String CommandArgumentName_RegionFromEntity = "RegionFrom(随机范围起始位置,实体)"; - public static String CommandArgumentName_RegionToEntity = "RegionTo(随机范围结束位置,实体)"; - - public static void Register(){ - ResourceLoader.get(CLIENT_RESOURCES).registerReloadListener(Identifier.fromNamespaceAndPath(MOD_ID, "translate_text_apply"), new SimpleReloadListener() { - /** - * 用不到,不用管 - */ - @Override - protected Void prepare(PreparableReloadListener.@NonNull SharedState store) { - return null; } - - @Override - protected void apply(Void prepared, PreparableReloadListener.@NonNull SharedState store) { - CommandArgumentName_Radius = Component.translatableWithFallback("command.argument.radius", "Radius(半径)").getString(); - CommandArgumentName_Target = Component.translatableWithFallback("command.argument.target", "PlayerID(被传送玩家名)").getString(); - CommandArgumentName_OriginPosition = Component.translatableWithFallback("command.argument.origin_pos", "OriginPos(随机中心,坐标)").getString(); - CommandArgumentName_OriginEntity = Component.translatableWithFallback("command.argument.origin_entity", "OriginEntity(随机中心,实体)").getString(); - CommandArgumentName_RegionFromPosition = Component.translatableWithFallback("command.argument.region_from_pos", "RegionFrom(随机范围起始位置,坐标)").getString(); - CommandArgumentName_RegionToPosition = Component.translatableWithFallback("command.argument.region_to_pos", "RegionTo(随机范围结束位置,坐标)").getString(); - CommandArgumentName_RegionFromEntity = Component.translatableWithFallback("command.argument.region_from_entity", "RegionFrom(随机范围起始位置,实体)").getString(); - CommandArgumentName_RegionToEntity = Component.translatableWithFallback("command.argument.region_to_entity", "RegionTo(随机范围结束位置,实体)").getString(); } } ); } } \ No newline at end of file diff --git a/src/main/java/xyz/thewhitedog9487/ServerLifecycleListener.java b/src/main/java/xyz/thewhitedog9487/ServerLifecycleListener.java deleted file mode 100644 index ba5e19d..0000000 --- a/src/main/java/xyz/thewhitedog9487/ServerLifecycleListener.java +++ /dev/null @@ -1,9 +0,0 @@ -package xyz.thewhitedog9487; - -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; - -public class ServerLifecycleListener { - public static void Register() { - ServerLifecycleEvents.SERVER_STARTED.register(server -> { - CommandRegister.OldPositions.clear(); - RandomTeleporter.LOGGER.info("已清空传送历史记录"); } ); } } \ No newline at end of file diff --git a/src/main/kotlin/xyz/thewhitedog9487/CommandRegister.kt b/src/main/kotlin/xyz/thewhitedog9487/CommandRegister.kt new file mode 100644 index 0000000..b1403b8 --- /dev/null +++ b/src/main/kotlin/xyz/thewhitedog9487/CommandRegister.kt @@ -0,0 +1,331 @@ +package xyz.thewhitedog9487 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.arguments.IntegerArgumentType +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback +import net.minecraft.commands.CommandSourceStack +import net.minecraft.commands.Commands +import net.minecraft.commands.arguments.EntityArgument +import net.minecraft.commands.arguments.coordinates.Vec2Argument +import net.minecraft.core.BlockPos +import net.minecraft.network.chat.Component +import net.minecraft.server.commands.TeleportCommand +import net.minecraft.server.level.ServerLevel +import net.minecraft.world.entity.Entity +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.Blocks +import net.minecraft.world.level.chunk.status.ChunkStatus +import net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES +import net.minecraft.world.phys.Vec2 +import net.minecraft.world.phys.Vec3 +import java.util.* +import kotlin.math.absoluteValue +import kotlin.math.max +import kotlin.math.min +import kotlin.random.Random +import kotlin.random.nextInt + +/** + * 传送后用于生成保护平台的方块 + */ +val TargetBlock = Blocks.GLASS + +/** + * 传送后会被 [TargetBlock] 替换掉的方块 + *

+ * 替换中心:被传送目标脚下方块 + *

+ * 替换范围:替换中心周围半径为一的正方形区域 + */ +val ReplaceToTargetBlock = setOf( + Blocks.AIR, + Blocks.VOID_AIR, + Blocks.CAVE_AIR, + Blocks.WATER, + Blocks.LAVA, + Blocks.SHORT_GRASS, + Blocks.VINE ) + +/** + * 世界边界 + *

+ * @see Minecraft Wiki (中文) + * @see Minecraft Wiki (English) + **/ +const val WorldBorder = 2.9e7.toInt() + +/** + * 执行命令所需权限等级 + * @see TeleportCommand + * @see Commands + * @see Minecraft Wiki (中文) + * @see Minecraft Wiki (English) + */ +val PermissionLevel = Commands.LEVEL_GAMEMASTERS + +/** + * 在传送之前记录当前位置,以支持传送回去 + */ +var OldPositions: MutableMap = mutableMapOf() + +/** + * 命令执行失败时的返回值 + * @see Minecraft Wiki (中文) + * @see Minecraft Wiki (English) + */ +const val CommandExecuteFailure = 0 + +/** + * 根命令名 + */ +val CommandRootNodeName = setOf( + "随机传送", + "rtp" ) +/** + * 使用Fabric API向游戏内注册命令 + *
+ * @see Fabric Docs (中文) + * @see Fabric Wiki (中文) + * @see Fabric Docs (English) + * @see Fabric Wiki (English) + */ +fun CommandRegister() { + for (RootNodeName in CommandRootNodeName) { + CommandRegistrationCallback.EVENT.register { dispatcher, context, selection -> + dispatcher.register(Commands.literal(RootNodeName) + // /rtp + .requires(Commands.hasPermission(PermissionLevel)) + .executes{ commandContext -> ExecuteCommand(commandContext.source) } + + // /rtp back + .then(Commands.literal("back") + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> TeleportBack(commandContext.source) } ) + + // /rtp back + .then(Commands.literal("back") + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> TeleportBack(commandContext.source, + EntityArgument.getEntity(commandContext, CommandArgumentName_Target)) } ) ) + + // /rtp back + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .then(Commands.literal("back") + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> TeleportBack(commandContext.source, + EntityArgument.getEntity(commandContext, CommandArgumentName_Target)) } ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius)) } ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target)) } ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius), + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target)) } ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .then(Commands.argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius), + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target)) } ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) + .then(Commands.argument(CommandArgumentName_OriginPosition, Vec2Argument.vec2()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius), + Origin = Vec2Argument.getVec2(commandContext, CommandArgumentName_OriginPosition)) } ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .then(Commands.argument(CommandArgumentName_OriginEntity, EntityArgument.entity()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius), + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target), + Origin = Vec2( + EntityArgument.getEntity(commandContext, CommandArgumentName_OriginEntity).position().x.toFloat(), + EntityArgument.getEntity(commandContext, CommandArgumentName_OriginEntity).position().z.toFloat() ) ) } ) ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .then(Commands.argument(CommandArgumentName_OriginPosition, Vec2Argument.vec2()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius), + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target), + Origin = Vec2Argument.getVec2(commandContext, CommandArgumentName_OriginPosition) ) } ) ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .then(Commands.argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) + .then(Commands.argument(CommandArgumentName_OriginEntity, EntityArgument.entity()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius), + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target), + Origin = Vec2( + EntityArgument.getEntity(commandContext, CommandArgumentName_OriginEntity).position().x.toFloat(), + EntityArgument.getEntity(commandContext, CommandArgumentName_OriginEntity).position().z.toFloat() ) ) } ) ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .then(Commands.argument(CommandArgumentName_Radius, IntegerArgumentType.integer(0)) + .then(Commands.argument(CommandArgumentName_OriginPosition, Vec2Argument.vec2()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius), + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target), + Origin = Vec2Argument.getVec2(commandContext, CommandArgumentName_OriginPosition) ) } ) ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_RegionFromPosition, Vec2Argument.vec2()) + .then(Commands.argument(CommandArgumentName_RegionToPosition, Vec2Argument.vec2()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + RegionFrom = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionFromPosition), + RegionTo = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionToPosition) ) } ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_RegionFromPosition, Vec2Argument.vec2()) + .then(Commands.argument(CommandArgumentName_RegionToPosition, Vec2Argument.vec2()) + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target), + RegionFrom = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionFromPosition), + RegionTo = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionToPosition) ) } ) ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .then(Commands.argument(CommandArgumentName_RegionFromPosition, Vec2Argument.vec2()) + .then(Commands.argument(CommandArgumentName_RegionToPosition, Vec2Argument.vec2()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target), + RegionFrom = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionFromPosition), + RegionTo = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionToPosition) ) } ) ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_RegionFromEntity, EntityArgument.entity()) + .then(Commands.argument(CommandArgumentName_RegionToEntity, EntityArgument.entity()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + RegionFrom = Vec2( + EntityArgument.getEntity(commandContext, CommandArgumentName_RegionFromEntity).position().x.toFloat(), + EntityArgument.getEntity(commandContext, CommandArgumentName_RegionFromEntity).position().z.toFloat() ), + RegionTo = Vec2( + EntityArgument.getEntity(commandContext, CommandArgumentName_RegionToEntity).position().x.toFloat(), + EntityArgument.getEntity(commandContext, CommandArgumentName_RegionToEntity).position().z.toFloat() ) ) } ) ) + + // /rtp + .then(Commands.argument(CommandArgumentName_RegionFromEntity, EntityArgument.entity()) + .then(Commands.argument(CommandArgumentName_RegionToEntity, EntityArgument.entity()) + .then(Commands.argument(CommandArgumentName_Target, EntityArgument.entity()) + .requires(Commands.hasPermission(PermissionLevel)) + .executes { commandContext -> ExecuteCommand(commandContext.source, + Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target), + RegionFrom = Vec2( + EntityArgument.getEntity(commandContext, CommandArgumentName_RegionFromEntity).position().x.toFloat(), + EntityArgument.getEntity(commandContext, CommandArgumentName_RegionFromEntity).position().z.toFloat() ), + RegionTo = Vec2( + EntityArgument.getEntity(commandContext, CommandArgumentName_RegionToEntity).position().x.toFloat(), + EntityArgument.getEntity(commandContext, CommandArgumentName_RegionToEntity).position().z.toFloat() ) ) } ) ) ) + ) } } } + +fun ExecuteCommand( + Source: CommandSourceStack, + Radius: Int = WorldBorder - 1e4.toInt(), + Entity: Entity? = Source.player, + Origin: Vec2? = null, + RegionFrom: Vec2? = null, + RegionTo: Vec2? = null ): Int { + + val TargetEntity = Entity ?: run { + Source.sendFailure( Component.translatableWithFallback("error.no_target","不存在被传送目标,由非玩家物体执行命令时请显式指定被传送玩家ID") ) + return CommandExecuteFailure } + val RandomRadius = Radius.absoluteValue.toFloat() + + var (RandomRegionFrom, RandomRegionTo) = if (RegionFrom == null && RegionTo == null) Pair( + Vec2(-RandomRadius, -RandomRadius), Vec2(RandomRadius, RandomRadius) ) + else Pair( + Vec2(min(RegionFrom!!.x, RegionTo!!.x), min(RegionFrom.y, RegionTo.y)), + Vec2(max(RegionFrom.x, RegionTo.x), max(RegionFrom.y, RegionTo.y))) + + if (Origin != null) { + RandomRegionFrom = Vec2(Origin.x - RandomRadius, Origin.y - RandomRadius) + RandomRegionTo = Vec2(Origin.x + RandomRadius, Origin.y + RandomRadius) } + + var (TargetX, TargetZ) = Pair( + Random.nextInt(RandomRegionFrom.x.toInt() until RandomRegionTo.x.toInt() + 1), + Random.nextInt(RandomRegionFrom.y.toInt() until RandomRegionTo.y.toInt() + 1) ) + TargetX = Math.clamp(TargetX.toLong(), -(WorldBorder - 1e4).toInt(), WorldBorder - 1e4.toInt() ) + TargetZ = Math.clamp(TargetZ.toLong(), -(WorldBorder - 1e4).toInt(), WorldBorder - 1e4.toInt() ) + + val EntityWorld = TargetEntity.level() + EntityWorld.getChunk(TargetX shr 4, TargetZ shr 4, ChunkStatus.FULL, true) + val TargetY = EntityWorld.getHeight(MOTION_BLOCKING_NO_LEAVES, TargetX, TargetZ) + val BlockPosInstance = BlockPos.MutableBlockPos() + for (x in -1..1) { + for (z in -1..1) { + BlockPosInstance.set(TargetX - x, TargetY - 1, TargetZ - z) + val CurrentBlock = EntityWorld.getBlockState(BlockPosInstance).block + if (ReplaceToTargetBlock.contains(CurrentBlock)) { + EntityWorld.setBlockAndUpdate(BlockPosInstance, TargetBlock.defaultBlockState()) } } } + OldPositions[TargetEntity.uuid] = TargetEntity.position() + TargetEntity.teleportTo(EntityWorld as ServerLevel, TargetX + 0.5, TargetY.toDouble(), TargetZ + 0.5, setOf(), TargetEntity.yRot, TargetEntity.xRot, false) + val FeedbackFallbackString = String.format("已将玩家%s传送到%d %d %d", TargetEntity.name.string, TargetX, TargetY, TargetZ) + Source.sendSuccess({ Component.translatableWithFallback("info.success", FeedbackFallbackString, TargetEntity.name, TargetX, TargetY, TargetZ) }, true) + return Command.SINGLE_SUCCESS } + +fun TeleportBack(Source: CommandSourceStack, + TargetEntity: Entity? = Source.player): Int { + + if (TargetEntity == null) { + Source.sendFailure( + Component.translatableWithFallback( + "error.no_target", + "不存在被传送目标,由非玩家物体执行命令时请显式指定被传送玩家ID")) + return CommandExecuteFailure } + OldPositions[TargetEntity.uuid].also { + if (it == null) { + Source.sendFailure( + Component.translatableWithFallback( + "error.no_old_position", + "%s还未使用过随机传送,因此无法回溯", + TargetEntity.name.string ) ) + return@TeleportBack CommandExecuteFailure } + + TargetEntity.teleportTo( + TargetEntity.level() as ServerLevel, + it.x, + it.y, + it.z, + setOf(), + TargetEntity.yRot, + TargetEntity.xRot, + false) + Source.sendSuccess({ + Component.translatableWithFallback( + "info.success.back", + "已将玩家%s传送回原位置", + TargetEntity.name.string ) }, true) + return@TeleportBack Command.SINGLE_SUCCESS } } \ No newline at end of file diff --git a/src/main/kotlin/xyz/thewhitedog9487/RandomTeleporter.kt b/src/main/kotlin/xyz/thewhitedog9487/RandomTeleporter.kt new file mode 100644 index 0000000..e516714 --- /dev/null +++ b/src/main/kotlin/xyz/thewhitedog9487/RandomTeleporter.kt @@ -0,0 +1,26 @@ +package xyz.thewhitedog9487 + +import net.fabricmc.api.ModInitializer +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +const val ModID = "randomteleporter" +const val FriendlyModID = "RandomTeleporter" +val ModLogger: Logger = LoggerFactory.getLogger(FriendlyModID) + +object RandomTeleporter : ModInitializer { + + override fun onInitialize() { + // This code runs as soon as Minecraft is in a mod-load-ready state. + // However, some things (like resources) may still be uninitialized. + // Proceed with mild caution. + + // This code runs as soon as Minecraft is in a mod-load-ready state. + // However, some things (like resources) may still be uninitialized. + // Proceed with mild caution. + + ServerLifecycleListenerRegister() + ResourceReloaderListenerRegister() + CommandRegister() + ModLogger.info("RandomTeleporter已写入命令注册回调,目标命令将会在该注册的时候被注册") } +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/thewhitedog9487/ResourceReloaderListener.kt b/src/main/kotlin/xyz/thewhitedog9487/ResourceReloaderListener.kt new file mode 100644 index 0000000..71c2426 --- /dev/null +++ b/src/main/kotlin/xyz/thewhitedog9487/ResourceReloaderListener.kt @@ -0,0 +1,45 @@ +package xyz.thewhitedog9487 + +import net.fabricmc.fabric.api.resource.v1.ResourceLoader +import net.fabricmc.fabric.api.resource.v1.reloader.SimpleReloadListener +import net.minecraft.network.chat.Component +import net.minecraft.resources.Identifier +import net.minecraft.server.packs.PackType +import net.minecraft.server.packs.resources.PreparableReloadListener + +var CommandArgumentName_Radius = "Radius(半径)" +var CommandArgumentName_Target = "PlayerID(被传送玩家名)" +var CommandArgumentName_OriginPosition = "OriginPos(随机中心,坐标)" +var CommandArgumentName_OriginEntity = "OriginEntity(随机中心,实体)" +var CommandArgumentName_RegionFromPosition = "RegionFrom(随机范围起始位置,坐标)" +var CommandArgumentName_RegionToPosition = "RegionTo(随机范围结束位置,坐标)" +var CommandArgumentName_RegionFromEntity = "RegionFrom(随机范围起始位置,实体)" +var CommandArgumentName_RegionToEntity = "RegionTo(随机范围结束位置,实体)" + +fun ResourceReloaderListenerRegister() { + ResourceLoader.get(PackType.CLIENT_RESOURCES).registerReloadListener( + Identifier.fromNamespaceAndPath(ModID, + "translate_text_apply"), object: SimpleReloadListener() { + override fun prepare(p0: PreparableReloadListener.SharedState) {} + + override fun apply(p0: Unit, p1: PreparableReloadListener.SharedState) { + CommandArgumentName_Radius = + Component.translatableWithFallback("command.argument.radius", "Radius(半径)").string + CommandArgumentName_Target = + Component.translatableWithFallback("command.argument.target", "PlayerID(被传送玩家名)").string + CommandArgumentName_OriginPosition = + Component.translatableWithFallback("command.argument.origin_pos", "OriginPos(随机中心,坐标)").string + CommandArgumentName_OriginEntity = + Component.translatableWithFallback("command.argument.origin_entity", "OriginEntity(随机中心,实体)").string + CommandArgumentName_RegionFromPosition = Component.translatableWithFallback( + "command.argument.region_from_pos", + "RegionFrom(随机范围起始位置,坐标)").string + CommandArgumentName_RegionToPosition = Component.translatableWithFallback( + "command.argument.region_to_pos", + "RegionTo(随机范围结束位置,坐标)").string + CommandArgumentName_RegionFromEntity = Component.translatableWithFallback( + "command.argument.region_from_entity", + "RegionFrom(随机范围起始位置,实体)").string + CommandArgumentName_RegionToEntity = Component.translatableWithFallback( + "command.argument.region_to_entity", + "RegionTo(随机范围结束位置,实体)").string } } ) } \ No newline at end of file diff --git a/src/main/kotlin/xyz/thewhitedog9487/ServerLifecycleListener.kt b/src/main/kotlin/xyz/thewhitedog9487/ServerLifecycleListener.kt new file mode 100644 index 0000000..c1ae6c3 --- /dev/null +++ b/src/main/kotlin/xyz/thewhitedog9487/ServerLifecycleListener.kt @@ -0,0 +1,8 @@ +package xyz.thewhitedog9487 + +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents + +fun ServerLifecycleListenerRegister() { + ServerLifecycleEvents.SERVER_STARTED.register { server -> + OldPositions.clear() + ModLogger.info("已清空传送历史记录") } } \ No newline at end of file diff --git a/src/main/resources/assets/randomteleporter/lang/en_us.json b/src/main/resources/assets/randomteleporter/lang/en_us.json index ac11b43..1306153 100644 --- a/src/main/resources/assets/randomteleporter/lang/en_us.json +++ b/src/main/resources/assets/randomteleporter/lang/en_us.json @@ -5,8 +5,6 @@ "info.success.back": "Teleported %s back to original position", "error.no_target": "There is no teleported target, and the teleported player ID is explicitly specified when executed by a non-player object", "error.no_old_position": "%s has not used random teleport yet, so it cannot be traced back", - "warning.radius_equal_zero": "Warning: Since you set a random radius of 0, selecting the right height will teleport you directly to %d %d", - "warning.radius_equal_zero_no_target": "Warning: Since you set a random radius of 0 and you don't set a random center point coordinates, nothing happens", "bilibili": "Bilibili", "command.argument.radius": "radius", "command.argument.target": "teleported entity", diff --git a/src/main/resources/assets/randomteleporter/lang/zh_cn.json b/src/main/resources/assets/randomteleporter/lang/zh_cn.json index 69ba0b3..90d9cad 100644 --- a/src/main/resources/assets/randomteleporter/lang/zh_cn.json +++ b/src/main/resources/assets/randomteleporter/lang/zh_cn.json @@ -5,8 +5,6 @@ "info.success.back": "已将玩家%s传送回原位置", "error.no_target": "不存在被传送目标,由非玩家物体执行命令时请显式指定被传送玩家ID", "error.no_old_position": "%s还未使用过随机传送,因此无法回溯", - "warning.radius_equal_zero": "警告:由于你设置的随机半径为0,因此在选择出合适高度之后将直接把你传送至%d %d", - "warning.radius_equal_zero_no_target": "警告:由于你设置的随机半径为0,并且未设置随机中心点坐标,因此什么都不会发生", "bilibili": "TheWhiteDog9487的哔哩哔哩主页", "command.argument.radius": "半径", "command.argument.target": "被传送实体", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 833f7b2..26b5d2e 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -17,7 +17,11 @@ "environment": "*", "entrypoints": { "main": [ - "xyz.thewhitedog9487.RandomTeleporter"] + { + "value": "xyz.thewhitedog9487.RandomTeleporter", + "adapter": "kotlin" + } + ] }, "mixins": [ "randomteleporter.mixins.json", @@ -30,7 +34,8 @@ "fabricloader": ">=0.18.6", "minecraft": "26.1.2", "java": ">=25", - "fabric-api": ">=0.145.4" + "fabric-api": ">=0.145.4", + "fabric-language-kotlin": "*" }, "suggests": { "another-mod": "*" diff --git a/src/main/resources/randomteleporter.mixins.json b/src/main/resources/randomteleporter.mixins.json index 5cc4a57..f42f65b 100644 --- a/src/main/resources/randomteleporter.mixins.json +++ b/src/main/resources/randomteleporter.mixins.json @@ -1,11 +1,14 @@ { - "required": false, + "required": true, "package": "xyz.thewhitedog9487.mixin", - "compatibilityLevel": "JAVA_21", + "compatibilityLevel": "JAVA_25", "mixins": [ ], "injectors": { "defaultRequire": 1 + }, + "overwrites": { + "requireAnnotations": true } } \ No newline at end of file