diff --git a/build.gradle.kts b/build.gradle.kts index 29b1c533..c103ebca 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -72,7 +72,7 @@ subprojects { disableOnSkippedVersion = false } version { - taboolib = "6.2.4-abd325ee" + taboolib = "6.2.4-65252583" coroutines = null } } diff --git a/common/src/main/kotlin/trplugins/menu/util/conf/Property.kt b/common/src/main/kotlin/trplugins/menu/util/conf/Property.kt index a8d453db..4c102888 100644 --- a/common/src/main/kotlin/trplugins/menu/util/conf/Property.kt +++ b/common/src/main/kotlin/trplugins/menu/util/conf/Property.kt @@ -271,7 +271,12 @@ enum class Property(val default: String, val regex: Regex) { /** * 菜单内置国际化 */ - LANG("Lang", "lang(uage)?|internationalization|i18n"); + LANG("Lang", "lang(uage)?|internationalization|i18n"), + + /** + * 菜单内虚拟OP命令 + */ + COMMAND_FAKE_OP("Command-Fake-Op", "command-?fake-?op"); constructor(default: String, regex: String) : this(default, Regex("(?i)$regex")) diff --git a/gradle.properties b/gradle.properties index 115c165a..50c841e5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=me.arasple.mc.trmenu -version=3.9.12 \ No newline at end of file +version=3.9.14 \ No newline at end of file diff --git a/plugin/src/main/kotlin/trplugins/menu/api/action/impl/send/CommandOp.kt b/plugin/src/main/kotlin/trplugins/menu/api/action/impl/send/CommandOp.kt index facb7b36..78d85060 100644 --- a/plugin/src/main/kotlin/trplugins/menu/api/action/impl/send/CommandOp.kt +++ b/plugin/src/main/kotlin/trplugins/menu/api/action/impl/send/CommandOp.kt @@ -7,6 +7,7 @@ import taboolib.expansion.dispatchCommandAsOp import trplugins.menu.api.action.ActionHandle import trplugins.menu.api.action.base.ActionBase import trplugins.menu.api.action.base.ActionContents +import trplugins.menu.module.display.session /** * TrMenu @@ -20,9 +21,23 @@ class CommandOp(handle: ActionHandle) : ActionBase(handle) { override val regex = "op(erator)?s?".toRegex() override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { + val fakeOp = player.session().menu?.settings?.commandFakeOp ?: true contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { submit(async = false) { - player.cast().dispatchCommandAsOp(it) + if (fakeOp) { + player.cast().dispatchCommandAsOp(it) + } else { + player.isOp.let { isOp -> + player.isOp = true + try { + player.performCommand(it) + } catch (e: Throwable) { + e.printStackTrace() + } finally { + player.isOp = isOp + } + } + } } } } diff --git a/plugin/src/main/kotlin/trplugins/menu/module/conf/MenuSerializer.kt b/plugin/src/main/kotlin/trplugins/menu/module/conf/MenuSerializer.kt index d6d52778..7f863280 100644 --- a/plugin/src/main/kotlin/trplugins/menu/module/conf/MenuSerializer.kt +++ b/plugin/src/main/kotlin/trplugins/menu/module/conf/MenuSerializer.kt @@ -168,6 +168,7 @@ object MenuSerializer : ISerializer { val eventOpen = Property.EVENT_OPEN.ofList(events) val eventClose = Property.EVENT_CLOSE.ofList(events) val eventClick = Property.EVENT_CLICK.ofList(events) + val commandFakeOp = Property.COMMAND_FAKE_OP.ofBoolean(options, true) val settings = MenuSettings( CycleList(title), @@ -199,7 +200,8 @@ object MenuSerializer : ISerializer { ) } }, - funs.map { ScriptFunction(it.key, it.value.toString()) }.toSet() + funs.map { ScriptFunction(it.key, it.value.toString()) }.toSet(), + commandFakeOp ) // i18n diff --git a/plugin/src/main/kotlin/trplugins/menu/module/display/MenuSettings.kt b/plugin/src/main/kotlin/trplugins/menu/module/display/MenuSettings.kt index 7ae3f021..8518a861 100644 --- a/plugin/src/main/kotlin/trplugins/menu/module/display/MenuSettings.kt +++ b/plugin/src/main/kotlin/trplugins/menu/module/display/MenuSettings.kt @@ -33,7 +33,8 @@ class MenuSettings( val closeEvent: Reactions, val clickEvent: Reactions, val tasks: List, - val internalFunctions: Set + val internalFunctions: Set, + val commandFakeOp: Boolean = true, ) { companion object { diff --git a/plugin/src/main/kotlin/trplugins/menu/module/internal/service/RegisterCommands.kt b/plugin/src/main/kotlin/trplugins/menu/module/internal/service/RegisterCommands.kt index 14f83b1b..6c14366b 100644 --- a/plugin/src/main/kotlin/trplugins/menu/module/internal/service/RegisterCommands.kt +++ b/plugin/src/main/kotlin/trplugins/menu/module/internal/service/RegisterCommands.kt @@ -1,9 +1,11 @@ package trplugins.menu.module.internal.service +import org.bukkit.Bukkit import org.bukkit.entity.Player import taboolib.common.platform.command.PermissionDefault import taboolib.common.platform.command.command import taboolib.common.platform.function.adaptPlayer +import taboolib.common.platform.function.submit import taboolib.common.platform.function.unregisterCommand import trplugins.menu.TrMenu import trplugins.menu.TrMenu.actionHandle @@ -24,9 +26,12 @@ object RegisterCommands { } fun load() { - registered.removeIf { - unregisterCommand(it) - true + submit { + registered.removeIf { + unregisterCommand(it) + true + } + } TrMenu.SETTINGS.getConfigurationSection("RegisterCommands")?.let { it -> @@ -72,6 +77,13 @@ object RegisterCommands { } } } - } + // 延迟同步命令到所有在线玩家,避免与 Paper 异步命令发送线程冲突 + // Paper 的 sendAsync 会在异步线程遍历命令树,直接调用 updateCommands 可能触发 ConcurrentModificationException + submit(delay = 1) { + try { + Bukkit.getOnlinePlayers().forEach { it.updateCommands() } + } catch (_: Throwable) {} + } + } } \ No newline at end of file