package xyz.thewhitedog9487
import com.mojang.brigadier.Command
import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.arguments.IntegerArgumentType
import com.mojang.brigadier.tree.LiteralCommandNode
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.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" )
val CommandNodes: MutableSet> = mutableSetOf()
/**
* 是否注册过Fabric API的命令注册回调监听器
*/
var CommandRegistrationCallbackEventHasBeenRegistered = false
val CommandArgumentName_Radius = Component.translatableWithFallback("command.argument.radius", "Radius(半径)")
val CommandArgumentName_Target = Component.translatableWithFallback("command.argument.target", "PlayerID(被传送玩家名)")
val CommandArgumentName_OriginPosition = Component.translatableWithFallback("command.argument.origin_pos", "OriginPos(随机中心,坐标)")
val CommandArgumentName_OriginEntity = Component.translatableWithFallback("command.argument.origin_entity", "OriginEntity(随机中心,实体)")
val CommandArgumentName_RegionFromPosition = Component.translatableWithFallback(
"command.argument.region_from_pos",
"RegionFrom(随机范围起始位置,坐标)")
val CommandArgumentName_RegionToPosition = Component.translatableWithFallback(
"command.argument.region_to_pos",
"RegionTo(随机范围结束位置,坐标)")
val CommandArgumentName_RegionFromEntity = Component.translatableWithFallback(
"command.argument.region_from_entity",
"RegionFrom(随机范围起始位置,实体)")
val CommandArgumentName_RegionToEntity = Component.translatableWithFallback(
"command.argument.region_to_entity",
"RegionTo(随机范围结束位置,实体)")
/**
* 使用Fabric API向游戏内注册命令
*
* @see Fabric Docs (中文)
* @see Fabric Docs (English)
*/
fun CommandRegister(InGameCommandDispatcherInstance: CommandDispatcher? = null) {
val Register: (CommandDispatcherInstance: CommandDispatcher, NodeName: String) -> Unit = { CommandDispatcherInstance, NodeName ->
val Node = CommandDispatcherInstance.register(Commands.literal(NodeName)
// /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.string, EntityArgument.entity())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> TeleportBack(commandContext.source,
EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string)) } ) )
// /rtp back
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.then(Commands.literal("back")
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> TeleportBack(commandContext.source,
EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string)) } ) )
// /rtp
.then(Commands.argument(CommandArgumentName_Radius.string, IntegerArgumentType.integer(0))
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius.string)) } )
// /rtp
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string)) } )
// /rtp
.then(Commands.argument(CommandArgumentName_Radius.string, IntegerArgumentType.integer(0))
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius.string),
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string)) } ) )
// /rtp
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.then(Commands.argument(CommandArgumentName_Radius.string, IntegerArgumentType.integer(0))
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius.string),
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string)) } ) )
// /rtp
.then(Commands.argument(CommandArgumentName_Radius.string, IntegerArgumentType.integer(0))
.then(Commands.argument(CommandArgumentName_OriginPosition.string, Vec2Argument.vec2())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius.string),
Origin = Vec2Argument.getVec2(commandContext, CommandArgumentName_OriginPosition.string)) } ) )
// /rtp
.then(Commands.argument(CommandArgumentName_Radius.string, IntegerArgumentType.integer(0))
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.then(Commands.argument(CommandArgumentName_OriginEntity.string, EntityArgument.entity())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius.string),
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string),
Origin = Vec2(
EntityArgument.getEntity(commandContext, CommandArgumentName_OriginEntity.string).position().x.toFloat(),
EntityArgument.getEntity(commandContext, CommandArgumentName_OriginEntity.string).position().z.toFloat() ) ) } ) ) )
// /rtp
.then(Commands.argument(CommandArgumentName_Radius.string, IntegerArgumentType.integer(0))
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.then(Commands.argument(CommandArgumentName_OriginPosition.string, Vec2Argument.vec2())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius.string),
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string),
Origin = Vec2Argument.getVec2(commandContext, CommandArgumentName_OriginPosition.string) ) } ) ) )
// /rtp
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.then(Commands.argument(CommandArgumentName_Radius.string, IntegerArgumentType.integer(0))
.then(Commands.argument(CommandArgumentName_OriginEntity.string, EntityArgument.entity())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius.string),
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string),
Origin = Vec2(
EntityArgument.getEntity(commandContext, CommandArgumentName_OriginEntity.string).position().x.toFloat(),
EntityArgument.getEntity(commandContext, CommandArgumentName_OriginEntity.string).position().z.toFloat() ) ) } ) ) )
// /rtp
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.then(Commands.argument(CommandArgumentName_Radius.string, IntegerArgumentType.integer(0))
.then(Commands.argument(CommandArgumentName_OriginPosition.string, Vec2Argument.vec2())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Radius = IntegerArgumentType.getInteger(commandContext, CommandArgumentName_Radius.string),
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string),
Origin = Vec2Argument.getVec2(commandContext, CommandArgumentName_OriginPosition.string) ) } ) ) )
// /rtp
.then(Commands.argument(CommandArgumentName_RegionFromPosition.string, Vec2Argument.vec2())
.then(Commands.argument(CommandArgumentName_RegionToPosition.string, Vec2Argument.vec2())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
RegionFrom = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionFromPosition.string),
RegionTo = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionToPosition.string) ) } ) )
// /rtp
.then(Commands.argument(CommandArgumentName_RegionFromPosition.string, Vec2Argument.vec2())
.then(Commands.argument(CommandArgumentName_RegionToPosition.string, Vec2Argument.vec2())
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string),
RegionFrom = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionFromPosition.string),
RegionTo = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionToPosition.string) ) } ) ) )
// /rtp
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.then(Commands.argument(CommandArgumentName_RegionFromPosition.string, Vec2Argument.vec2())
.then(Commands.argument(CommandArgumentName_RegionToPosition.string, Vec2Argument.vec2())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string),
RegionFrom = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionFromPosition.string),
RegionTo = Vec2Argument.getVec2(commandContext, CommandArgumentName_RegionToPosition.string) ) } ) ) )
// /rtp
.then(Commands.argument(CommandArgumentName_RegionFromEntity.string, EntityArgument.entity())
.then(Commands.argument(CommandArgumentName_RegionToEntity.string, EntityArgument.entity())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
RegionFrom = Vec2(
EntityArgument.getEntity(commandContext, CommandArgumentName_RegionFromEntity.string).position().x.toFloat(),
EntityArgument.getEntity(commandContext, CommandArgumentName_RegionFromEntity.string).position().z.toFloat() ),
RegionTo = Vec2(
EntityArgument.getEntity(commandContext, CommandArgumentName_RegionToEntity.string).position().x.toFloat(),
EntityArgument.getEntity(commandContext, CommandArgumentName_RegionToEntity.string).position().z.toFloat() ) ) } ) )
// /rtp
.then(Commands.argument(CommandArgumentName_RegionFromEntity.string, EntityArgument.entity())
.then(Commands.argument(CommandArgumentName_RegionToEntity.string, EntityArgument.entity())
.then(Commands.argument(CommandArgumentName_Target.string, EntityArgument.entity())
.requires(Commands.hasPermission(PermissionLevel))
.executes { commandContext -> ExecuteCommand(commandContext.source,
Entity = EntityArgument.getEntity(commandContext, CommandArgumentName_Target.string),
RegionFrom = Vec2(
EntityArgument.getEntity(commandContext, CommandArgumentName_RegionFromEntity.string).position().x.toFloat(),
EntityArgument.getEntity(commandContext, CommandArgumentName_RegionFromEntity.string).position().z.toFloat() ),
RegionTo = Vec2(
EntityArgument.getEntity(commandContext, CommandArgumentName_RegionToEntity.string).position().x.toFloat(),
EntityArgument.getEntity(commandContext, CommandArgumentName_RegionToEntity.string).position().z.toFloat() ) ) } ) ) ) )
CommandNodes.add(Node) }
for (RootNodeName in CommandRootNodeName) {
InGameCommandDispatcherInstance?.let {
Register(it, RootNodeName) } }
if (CommandRegistrationCallbackEventHasBeenRegistered) return
for (RootNodeName in CommandRootNodeName) {
CommandRegistrationCallback.EVENT.register { dispatcher, context, selection ->
Register(dispatcher, RootNodeName) } }
CommandRegistrationCallbackEventHasBeenRegistered = true }
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 } }