使用 Brigadier Command API 重写命令

This commit is contained in:
2025-03-26 00:59:27 +08:00
parent b02e509e1c
commit 95ee3efacb
5 changed files with 274 additions and 3 deletions

View File

@@ -398,6 +398,9 @@ class Console {
scoreboard.getObjective("rule-list")!!.displaySlot = null scoreboard.getObjective("rule-list")!!.displaySlot = null
stage = GameStage.PROCESSING stage = GameStage.PROCESSING
Bukkit.getOnlinePlayers().forEach {
it.updateCommands()
}
} }
/** /**
@@ -476,6 +479,7 @@ class Console {
it.sendMessage(Component.text("没有赢家", NamedTextColor.GOLD)) it.sendMessage(Component.text("没有赢家", NamedTextColor.GOLD))
} }
it.gameMode = GameMode.SURVIVAL it.gameMode = GameMode.SURVIVAL
it.updateCommands()
} }
// 取消剩余的复活任务 // 取消剩余的复活任务
hunterRespawnTasks.forEach { hunterRespawnTasks.forEach {
@@ -578,6 +582,7 @@ class Console {
hunterRespawnTasks.remove(uuid) hunterRespawnTasks.remove(uuid)
}, gameRules.getRuleValue(RuleKey.HUNTER_RESPAWN_CD) * 20L) }, gameRules.getRuleValue(RuleKey.HUNTER_RESPAWN_CD) * 20L)
} }
player.updateCommands()
} }
private fun initScoreboard() { private fun initScoreboard() {
@@ -657,6 +662,11 @@ class Console {
} }
} }
/**
* 判断是否处于倒计时前的开始阶段
*/
fun preparingAndNoCountdown(): Boolean = stage == GameStage.PREPARING && beginningCountdown == null
/** /**
* 游戏阶段 * 游戏阶段
*/ */

View File

@@ -1,7 +1,9 @@
package xyz.fortern.minehunt package xyz.fortern.minehunt
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.plugin.java.JavaPlugin import org.bukkit.plugin.java.JavaPlugin
import xyz.fortern.minehunt.command.MhCommand
import xyz.fortern.minehunt.command.MinehuntCommand import xyz.fortern.minehunt.command.MinehuntCommand
import xyz.fortern.minehunt.command.TestCommand import xyz.fortern.minehunt.command.TestCommand
import xyz.fortern.minehunt.listener.PlayerListener import xyz.fortern.minehunt.listener.PlayerListener
@@ -30,6 +32,10 @@ class Minehunt : JavaPlugin() {
Bukkit.getPluginCommand("test")!!.setExecutor(TestCommand()) Bukkit.getPluginCommand("test")!!.setExecutor(TestCommand())
Bukkit.getPluginCommand("minehunt")!!.setExecutor(MinehuntCommand(console)) Bukkit.getPluginCommand("minehunt")!!.setExecutor(MinehuntCommand(console))
this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS) {
it.registrar().register(MhCommand(console).createCommand().build())
}
} }
override fun onDisable() { override fun onDisable() {

View File

@@ -0,0 +1,212 @@
package xyz.fortern.minehunt.command
import com.mojang.brigadier.Command
import com.mojang.brigadier.builder.LiteralArgumentBuilder
import io.papermc.paper.command.brigadier.CommandSourceStack
import io.papermc.paper.command.brigadier.Commands
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.NamedTextColor
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import xyz.fortern.minehunt.Console
import xyz.fortern.minehunt.Console.GameStage
import xyz.fortern.minehunt.Minehunt
import xyz.fortern.minehunt.rule.RuleKey
class MhCommand(
private val console: Console
) {
private val helpMessages = listOf(
Component.text("Minehunt v${Minehunt.instance().pluginMeta.version}", NamedTextColor.GREEN),
Component.text("/minehunt help ", NamedTextColor.GOLD)
.append(Component.text("帮助信息", NamedTextColor.WHITE)),
Component.text("/minehunt join (hunter|speedrunner|audience) ", NamedTextColor.GOLD)
.append(Component.text("加入一个阵营", NamedTextColor.WHITE)),
Component.text("/minehunt leave ", NamedTextColor.GOLD)
.append(Component.text("加入观察者阵营", NamedTextColor.WHITE)),
Component.text("/minehunt rule <ruleKey> ", NamedTextColor.GOLD)
.append(Component.text("查看或修改游戏规则", NamedTextColor.WHITE)),
Component.text("/minehunt start ", NamedTextColor.GOLD)
.append(Component.text("开始游戏", NamedTextColor.WHITE)),
Component.text("/minehunt stop ", NamedTextColor.GOLD)
.append(Component.text("进行中止游戏的投票", NamedTextColor.WHITE)),
Component.text("/minehunt give ", NamedTextColor.GOLD)
.append(Component.text("给予游戏中所需的特殊物品", NamedTextColor.WHITE)),
)
private val ruleHelpMessages = listOf(
Component.text("/minehunt rule <ruleItem> ", NamedTextColor.GREEN)
.append(Component.text("查看一项规则的详情", NamedTextColor.WHITE)),
Component.text("/minehunt rule <ruleItem> <value> ", NamedTextColor.GREEN)
.append(Component.text("为一项规则设置新的值", NamedTextColor.WHITE)),
)
fun createCommand(): LiteralArgumentBuilder<CommandSourceStack> =
Commands.literal("hunt")
.then(help())
.then(join())
.then(leave())
.then(rule())
.then(start())
.then(stop())
.then(give())
private fun help(): LiteralArgumentBuilder<CommandSourceStack> {
return Commands.literal("help").executes { sendHelp(it.source.sender) }
}
private fun join(): LiteralArgumentBuilder<CommandSourceStack> {
return Commands.literal("join")
.requires {
it.sender is Player && console.preparingAndNoCountdown()
}.then(
Commands.literal("hunter").executes {
console.joinHunter(it.source.sender as Player)
Command.SINGLE_SUCCESS
}
).then(
Commands.literal("speedrunner").executes {
console.joinSpeedrunner(it.source.sender as Player)
Command.SINGLE_SUCCESS
}
).then(
Commands.literal("audience").executes {
console.joinAudience(it.source.sender as Player)
Command.SINGLE_SUCCESS
}
)
}
private fun leave(): LiteralArgumentBuilder<CommandSourceStack> {
return Commands.literal("leave")
.requires { it.sender is Player && console.preparingAndNoCountdown() }
.executes {
console.joinAudience(it.source.sender as Player)
Command.SINGLE_SUCCESS
}
}
private fun rule(): LiteralArgumentBuilder<CommandSourceStack> {
val ruleNode = Commands.literal("rule").requires {
console.preparingAndNoCountdown()
}
console.gameRules.getAllRules().forEach { (k, v) ->
ruleNode.then(
// 定义ruleKey节点 在 minehunt -> rule -> ruleKey
Commands.literal(k.name)
.then(
// 定义value节点 在 minehunt -> rule -> ruleKey -> value
Commands.argument("value", k.type)
// 执行修改规则的命令
.executes {
modifyGameRule(k, it.getArgument("value", k.clazz)!!, it.source.sender)
}
)
// 执行查询规则的命令
.executes { sendRuleInfo(it.source.sender, k) }
)
}
ruleNode.executes {
sendHelpRule(it.source.sender)
}
return ruleNode
}
/**
* 游戏开始
*/
private fun start(): LiteralArgumentBuilder<CommandSourceStack> {
return Commands.literal("start")
.requires { console.preparingAndNoCountdown() }
.executes {
val result = console.tryStart()
if (result.isNotEmpty()) {
it.source.sender.sendMessage(Component.text("游戏开始失败,原因:${result}", NamedTextColor.RED))
}
Command.SINGLE_SUCCESS
}
}
/**
* 投票结束游戏
*/
private fun stop(): LiteralArgumentBuilder<CommandSourceStack> {
return Commands.literal("stop")
.requires {
if (console.stage != GameStage.PROCESSING) return@requires false
val sender = it.sender
if (sender !is Player) return@requires false
console.isHunter(sender) || console.isSpeedrunner(sender)
}
.executes {
console.voteForStop(it.source.sender as Player)
Command.SINGLE_SUCCESS
}
}
/**
* 给予玩家特殊物品
*/
private fun give(): LiteralArgumentBuilder<CommandSourceStack> {
return Commands.literal("give")
.requires { it.sender is Player && console.stage == GameStage.PROCESSING }
.then(
Commands.literal("compass")
.requires {
val sender = it.sender
sender is Player && console.isHunter(sender)
}
)
}
/**
* 修改某项游戏规则
*/
private fun modifyGameRule(ruleKey: RuleKey<*>, value: Any, sender: CommandSender): Int {
if (console.gameRules.setGameRuleValue(ruleKey, value)) {
sender.sendMessage(
Component.text(sender.name, NamedTextColor.YELLOW)
.append(Component.text("修改规则项", NamedTextColor.WHITE))
.append(Component.text(ruleKey.name, NamedTextColor.GOLD))
.append(Component.text("值为", NamedTextColor.WHITE))
.append(
Component.text(
console.gameRules.getRuleValue(ruleKey).toString(),
NamedTextColor.GREEN
)
)
)
console.refreshEntry(ruleKey)
} else {
sender.sendMessage(Component.text("不合适的值", NamedTextColor.RED))
}
return Command.SINGLE_SUCCESS
}
/**
* 发送规则详情
*/
private fun sendRuleInfo(sender: CommandSender, ruleKey: RuleKey<*>): Int {
sender.sendMessage(Component.text("游戏规则: ${ruleKey.name}"))
sender.sendMessage(Component.text("描述: ${ruleKey.info}"))
sender.sendMessage(Component.text("值类型: ${ruleKey.typeInfo}"))
sender.sendMessage(Component.text("数值: ${console.gameRules.getRuleValue(ruleKey)}"))
return Command.SINGLE_SUCCESS
}
/**
* 发送帮助信息
*/
private fun sendHelp(sender: CommandSender): Int {
helpMessages.forEach { sender.sendMessage(it) }
return Command.SINGLE_SUCCESS
}
/**
* 发送rule子命令的帮助信息
*/
private fun sendHelpRule(sender: CommandSender): Int {
ruleHelpMessages.forEach { sender.sendMessage(it) }
return Command.SINGLE_SUCCESS
}
}

View File

@@ -25,6 +25,19 @@ class GameRules internal constructor() {
return true return true
} }
/**
* 设置一项游戏规则
*/
@Suppress("UNCHECKED_CAST")
fun <T> setGameRuleValue(rule: RuleKey<T>, value: Any): Boolean {
return try {
setRuleValue(rule, value as T)
true
} catch (e: ClassCastException) {
false
}
}
private fun <T> setRuleValue(rule: RuleKey<T>, value: T) { private fun <T> setRuleValue(rule: RuleKey<T>, value: T) {
map[rule] = value!! map[rule] = value!!
} }

View File

@@ -1,5 +1,9 @@
package xyz.fortern.minehunt.rule package xyz.fortern.minehunt.rule
import com.mojang.brigadier.arguments.ArgumentType
import com.mojang.brigadier.arguments.BoolArgumentType
import com.mojang.brigadier.arguments.IntegerArgumentType
/** /**
* 描述每一个规则项的类 * 描述每一个规则项的类
*/ */
@@ -14,10 +18,15 @@ class RuleKey<T> private constructor(
*/ */
val info: String, val info: String,
/**
* 这项规则值的参数类型
*/
val type: ArgumentType<*>,
/** /**
* 这项规则值的类型 * 这项规则值的类型
*/ */
val type: Class<T>, val clazz: Class<T>,
/** /**
* 值类型的描述信息 * 值类型的描述信息
@@ -47,7 +56,14 @@ class RuleKey<T> private constructor(
} }
val HUNTER_READY_CD = val HUNTER_READY_CD =
RuleKey("hunter_ready_cd", "猎人出生倒计时(秒)", Int::class.java, "Integer", listOf("0", "15", "30")) { RuleKey(
"hunter_ready_cd",
"猎人出生倒计时(秒)",
IntegerArgumentType.integer(0, 120),
Int::class.java,
"Integer",
listOf("0", "15", "30")
) {
try { try {
val i = it.toInt() val i = it.toInt()
if (i in 0..120) i else null if (i in 0..120) i else null
@@ -56,7 +72,14 @@ class RuleKey<T> private constructor(
} }
} }
val HUNTER_RESPAWN_CD = val HUNTER_RESPAWN_CD =
RuleKey("hunter_respawn_cd", "猎人重生倒计时(秒)", Int::class.java, "Integer", listOf("0, 15, 30")) { RuleKey(
"hunter_respawn_cd",
"猎人重生倒计时(秒)",
IntegerArgumentType.integer(0, 120),
Int::class.java,
"Integer",
listOf("0, 15, 30")
) {
try { try {
val i = it.toInt() val i = it.toInt()
if (i in 0..120) i else null if (i in 0..120) i else null
@@ -67,10 +90,17 @@ class RuleKey<T> private constructor(
val FRIENDLY_FIRE = RuleKey( val FRIENDLY_FIRE = RuleKey(
"friendly_fire", "friendly_fire",
"队友之间是否有伤害", "队友之间是否有伤害",
BoolArgumentType.bool(),
Boolean::class.java, Boolean::class.java,
"Boolean", "Boolean",
listOf("true", "false"), listOf("true", "false"),
boolValidate boolValidate
) )
val map: Map<String, RuleKey<*>> = mapOf(
"hunter_ready_cd" to HUNTER_READY_CD,
"hunter_respawn_cd" to HUNTER_RESPAWN_CD,
"friendly_fire" to FRIENDLY_FIRE
)
} }
} }