From 6dff863d3f1b6c18cce56cf7e3e23692c8b14388 Mon Sep 17 00:00:00 2001 From: TheWhiteDog9487 Date: Sat, 4 Apr 2026 14:18:40 +0800 Subject: [PATCH] =?UTF-8?q?0.5.2=20=E6=94=AF=E6=8C=81Minecraft=2026.1.1=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=9B=9E=E6=BA=AF=E5=88=B0=E9=9A=8F=E6=9C=BA?= =?UTF-8?q?=E4=BC=A0=E9=80=81=E5=89=8D=E7=9A=84=E4=BD=8D=E7=BD=AE=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20=EF=BC=88=20=E6=84=9A=E4=BA=BA=E8=8A=82OTA?= =?UTF-8?q?=E6=AD=A3=E5=BC=8F=E7=89=88=EF=BC=8C=E9=82=A3=E7=9B=B8=E5=BD=93?= =?UTF-8?q?=E6=9C=89=E6=93=8D=E4=BD=9C=E4=BA=86=20=EF=BC=88=20AI=E5=86=99?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=9C=AA=E5=BF=85=E9=9D=A0=E8=B0=B1=EF=BC=8C?= =?UTF-8?q?=E4=BD=86=E6=98=AF=E7=BF=BB=E8=AF=91=E8=BF=98=E6=98=AF=E5=BE=88?= =?UTF-8?q?=E4=B8=8D=E9=94=99=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 36 ++++-- README_EN.md | 104 ++++++++++++++++++ build.gradle.kts | 2 +- gradle.properties | 8 +- .../xyz/thewhitedog9487/CommandRegister.java | 77 +++++++++++-- .../xyz/thewhitedog9487/RandomTeleporter.java | 1 + .../ServerLifecycleListener.java | 9 ++ .../assets/randomteleporter/lang/en_us.json | 2 + .../assets/randomteleporter/lang/zh_cn.json | 2 + src/main/resources/fabric.mod.json | 8 +- 10 files changed, 220 insertions(+), 29 deletions(-) create mode 100644 README_EN.md create mode 100644 src/main/java/xyz/thewhitedog9487/ServerLifecycleListener.java diff --git a/README.md b/README.md index 070b7ca..efef703 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,18 @@ +
+ 简体中文(GitHub)     + 简体中文(Gitea)     + English(GitHub)     + English(Gitea) +
+ # 介绍 这个模组增加了一个命令 `/rtp`,用于将玩家随机传送到世界的任何一个位置。 # 命令格式 - `/rtp` +- `/rtp back` +- `/rtp back <被传送玩家ID>` +- `/rtp <被传送玩家ID> back` - `/rtp <随机半径>` - `/rtp <被传送玩家ID>` - `/rtp <随机半径> <被传送玩家ID>` @@ -13,22 +23,32 @@ - `/rtp <被传送玩家ID> <随机半径> <作为随机中心的实体>` - `/rtp <被传送玩家ID> <随机半径> <随机中心点坐标>` - `/rtp <随机区域起点坐标> <随机区域终点坐标>` -- `/rtp <被传送玩家ID> <随机区域起点坐标> <随机区域终点坐标>` - `/rtp <随机区域起点坐标> <随机区域终点坐标> <被传送玩家ID>` +- `/rtp <被传送玩家ID> <随机区域起点坐标> <随机区域终点坐标>` - `/rtp <随机区域起点实体> <随机区域终点实体>` - `/rtp <随机区域起点实体> <随机区域终点实体> <被传送玩家ID>` ## 命令示例 - `/rtp` -将执行命令的玩家随机传送到以`(0,0)`为中心点,2.9e7 - 1e4作为随机半径的范围内的随机一点 -2.9e+7 = 2.9 x 10^7 = 29000000 = 两千九百万 -1e4 = 10^4 = 10000 = 一万 +将执行命令的玩家随机传送到以`(0,0)`为中心点,$2.9 \times 10^7 - 10^4$ 作为随机半径的范围内的随机一点 +$2.9 \times 10^7 = 29,000,000$ = 两千九百万 +$10^4 = 10,000$ = 一万 + +- `/rtp back` +将执行命令的玩家传送回最近一次使用随机传送前的位置 +**注意:这个功能保存的上一次随机传送前的位置信息只会在游戏(服务器)运行期间存在,游戏(服务器)关闭后就会丢失** + +- `/rtp back TheWhiteDog9487` +将TheWhiteDog9487传送回其最近一次使用随机传送前的位置 + +- `/rtp TheWhiteDog9487 back` +将TheWhiteDog9487传送回其最近一次使用随机传送前的位置 - `/rtp 1000` 将执行命令的玩家随机传送到以`(0,0)`为中心点,1000作为随机半径的范围内的随机一点 - `/rtp TheWhiteDog9487` -将TheWhiteDog9487随机传送到以`(0,0)`为中心点,2.9e7 - 1e4作为随机半径的范围内的随机一点 +将TheWhiteDog9487随机传送到以`(0,0)`为中心点,$2.9 \times 10^7 - 10^4$ 作为随机半径的范围内的随机一点 - `/rtp TheWhiteDog9487 1000` 将TheWhiteDog9487随机传送到以`(0,0)`为中心点,1000作为随机半径的范围内的随机一点 @@ -51,14 +71,14 @@ - `/rtp TheWhiteDog9487 1000 10000 10000` 将TheWhiteDog9487随机传送到以`(10000,10000)`为中心点,1000作为随机半径的范围内的随机一点 -- `/rtp 10000 10000 20000 20000` +- `/rtp 10000.0 10000.0 20000.0 20000.0` 将执行命令的玩家随机传送到以`(10000,10000)`,`(20000,10000)`,`(20000,20000)`,`(10000,20000)`四个顶点围成的长方形区域内的随机一点 您需要提供的坐标是这个长方形的任意一个顶点和这个顶点对应的斜对角顶点的位置 -- `/rtp TheWhiteDog9487 10000 10000 20000 20000` +- `/rtp TheWhiteDog9487 10000.0 10000.0 20000.0 20000.0` 将TheWhiteDog9487随机传送到以`(10000,10000)`,`(20000,10000)`,`(20000,20000)`,`(10000,20000)`四个顶点围成的长方形区域内的随机一点 -- `/rtp 10000 10000 20000 20000 TheWhiteDog9487` +- `/rtp 10000.0 10000.0 20000.0 20000.0 TheWhiteDog9487` 将TheWhiteDog9487随机传送到以`(10000,10000)`,`(20000,10000)`,`(20000,20000)`,`(10000,20000)`四个顶点围成的长方形区域内的随机一点 - `/rtp TheWhiteDog9487 TheWhiteDog_CN` diff --git a/README_EN.md b/README_EN.md new file mode 100644 index 0000000..fb5a307 --- /dev/null +++ b/README_EN.md @@ -0,0 +1,104 @@ +
+ 简体中文(GitHub)     + 简体中文(Gitea)     + English(GitHub)     + English(Gitea) +
+ +# Introduction +This mod adds a command `/rtp` for randomly teleporting players to any location in the world. + +# Command Formats +- `/rtp` +- `/rtp back` +- `/rtp back ` +- `/rtp back` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` +- `/rtp ` + +## 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$ + +- `/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.** + +- `/rtp back TheWhiteDog9487` +Teleports `TheWhiteDog9487` back to their position before their last random teleport. + +- `/rtp TheWhiteDog9487 back` +Teleports `TheWhiteDog9487` back to their position before their last random teleport. + +- `/rtp 1000` +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)`. + +- `/rtp TheWhiteDog9487 1000` +Teleports `TheWhiteDog9487` to a random point within a radius of `1000` centered at `(0,0)`. + +- `/rtp 1000 TheWhiteDog9487` +Teleports `TheWhiteDog9487` to a random point within a radius of `1000` centered at `(0,0)`. + +- `/rtp 1000 10000 10000` +Teleports the player to a random point within a radius of `1000` centered at `(10000,10000)`. + +- `/rtp 1000 TheWhiteDog9487 TheWhiteDog_CN` +Teleports `TheWhiteDog9487` to a random point within a radius of `1000` centered at `TheWhiteDog_CN`'s location. + +- `/rtp 1000 TheWhiteDog9487 10000 10000` +Teleports `TheWhiteDog9487` to a random point within a radius of `1000` centered at `(10000,10000)`. + +- `/rtp TheWhiteDog9487 1000 TheWhiteDog_CN` +Teleports `TheWhiteDog9487` to a random point within a radius of `1000` centered at `TheWhiteDog_CN`'s location. + +- `/rtp TheWhiteDog9487 1000 10000 10000` +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. + +- `/rtp TheWhiteDog9487 10000.0 10000.0 20000.0 20000.0` +Teleports `TheWhiteDog9487` to a random point within the same rectangular region described above. + +- `/rtp 10000.0 10000.0 20000.0 20000.0 TheWhiteDog9487` +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. + +- `/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. + +### 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. + +# Dependencies +Fabric API + +# 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. + +# 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. + +**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 diff --git a/build.gradle.kts b/build.gradle.kts index bdb6b24..1c174f1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -44,7 +44,7 @@ dependencies { // "modImplementation"("net.fabricmc.fabric-api:fabric-api-deprecated:${project.extra["fabric_version"]}") // ↓ 开发测试用 - runtimeOnly("com.terraformersmc:modmenu:${project.extra["modmenu_version"]}") +// runtimeOnly("com.terraformersmc:modmenu:${project.extra["modmenu_version"]}") } tasks.processResources { diff --git a/gradle.properties b/gradle.properties index f78f073..198d98a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,16 +4,16 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=26.1 -loader_version=0.18.4 +minecraft_version=26.1.1 +loader_version=0.18.6 # Mod Properties -mod_version=0.5.1 +mod_version=0.5.2 maven_group=xyz.thewhitedog9487 archives_base_name=RandomTeleporter # Dependencies -fabric_api_version=0.144.3+26.1 +fabric_api_version=0.145.3+26.1.1 # https://modrinth.com/mod/modmenu/versions # https://maven.terraformersmc.com/releases/com/terraformersmc/modmenu diff --git a/src/main/java/xyz/thewhitedog9487/CommandRegister.java b/src/main/java/xyz/thewhitedog9487/CommandRegister.java index b751923..2e8c651 100644 --- a/src/main/java/xyz/thewhitedog9487/CommandRegister.java +++ b/src/main/java/xyz/thewhitedog9487/CommandRegister.java @@ -18,11 +18,10 @@ 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 java.util.HashSet; -import java.util.Set; -import java.util.SplittableRandom; +import module java.base; import static net.minecraft.commands.Commands.argument; import static net.minecraft.commands.Commands.literal; @@ -68,20 +67,34 @@ public class CommandRegister { /** * 执行命令所需权限等级 * @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 Wiki (新样式,中文) - * @see Fabric Wiki (旧样式,中文) - * @see Fabric Wiki (New style,English) - * @see Fabric Wiki (Old style,English) + * @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) @@ -89,6 +102,25 @@ public class CommandRegister { .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)) @@ -297,7 +329,7 @@ public class CommandRegister { */ if (TargetEntity == null) { Source.sendSuccess(()->{ return Component.translatableWithFallback("error.no_target","不存在被传送目标,由非玩家物体执行命令时请显式指定被传送玩家ID"); }, true); - return -1; } + return CommandExecuteFailure; } int Coordinate_X = 0; int Coordinate_Z = 0; if (RegionFrom == null || RegionTo == null) { // ← 按半径和中心取随机 @@ -313,9 +345,8 @@ public class CommandRegister { catch (IllegalArgumentException e) { // 半径为零 if (Origin == null) { - Source.sendSuccess(() -> { - return Component.translatableWithFallback("warning.radius_equal_zero_no_target", "由于你设置的随机半径为0,并且未设置随机中心点坐标,因此什么都不会发生"); }, true); - return -1; } + Source.sendFailure(Component.translatableWithFallback("warning.radius_equal_zero_no_target", "由于你设置的随机半径为0,并且未设置随机中心点坐标,因此什么都不会发生")); + return CommandExecuteFailure; } else { Coordinate_X = (int) Origin.x; Coordinate_Z = (int) Origin.y; @@ -349,6 +380,7 @@ public class CommandRegister { 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; @@ -356,4 +388,25 @@ public class CommandRegister { 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 index 3bf2d6b..3b48c34 100644 --- a/src/main/java/xyz/thewhitedog9487/RandomTeleporter.java +++ b/src/main/java/xyz/thewhitedog9487/RandomTeleporter.java @@ -19,6 +19,7 @@ public class RandomTeleporter implements ModInitializer { // Proceed with mild caution. ResourceReloaderListener.Register(); + ServerLifecycleListener.Register(); CommandRegister.Register(); LOGGER.info("RandomTeleporter已写入命令注册回调,目标命令将会在该注册的时候被注册"); } diff --git a/src/main/java/xyz/thewhitedog9487/ServerLifecycleListener.java b/src/main/java/xyz/thewhitedog9487/ServerLifecycleListener.java new file mode 100644 index 0000000..ba5e19d --- /dev/null +++ b/src/main/java/xyz/thewhitedog9487/ServerLifecycleListener.java @@ -0,0 +1,9 @@ +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/resources/assets/randomteleporter/lang/en_us.json b/src/main/resources/assets/randomteleporter/lang/en_us.json index cf63b48..ac11b43 100644 --- a/src/main/resources/assets/randomteleporter/lang/en_us.json +++ b/src/main/resources/assets/randomteleporter/lang/en_us.json @@ -2,7 +2,9 @@ "modmenu.nameTranslation.randomteleporter": "RandomTeleporter", "modmenu.descriptionTranslation.randomteleporter": "Added two commands for random teleportation", "info.success": "Teleported %s to %d %d %d", + "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", diff --git a/src/main/resources/assets/randomteleporter/lang/zh_cn.json b/src/main/resources/assets/randomteleporter/lang/zh_cn.json index 63f344a..69ba0b3 100644 --- a/src/main/resources/assets/randomteleporter/lang/zh_cn.json +++ b/src/main/resources/assets/randomteleporter/lang/zh_cn.json @@ -2,7 +2,9 @@ "modmenu.nameTranslation.randomteleporter": "随机传送", "modmenu.descriptionTranslation.randomteleporter": "增加了两个用于随机传送的命令", "info.success": "已将玩家%s传送到%d %d %d", + "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的哔哩哔哩主页", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 7821c8a..19aa72d 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -27,10 +27,10 @@ } ], "depends": { - "fabricloader": ">=0.18.4", - "minecraft": "26.1", + "fabricloader": ">=0.18.6", + "minecraft": "26.1.1", "java": ">=25", - "fabric-api": ">=0.144.3" + "fabric-api": ">=0.145.3" }, "suggests": { "another-mod": "*" @@ -39,5 +39,5 @@ "modmenu": { "links": { "bilibili": "https://space.bilibili.com/401746666"}, - "update_checker": true}} + "update_checker": true } } } \ No newline at end of file