feat: パーミッションの扱いのアップデート

This commit is contained in:
Keisuke Hirata 2025-12-04 05:53:00 +09:00
parent 54392b21e8
commit 91dbd240b5
7 changed files with 42 additions and 13 deletions

View File

@ -140,7 +140,9 @@ commands = kommand(this) {
``` ```
- `permissions { ... }` で名前空間やルートセグメント (`rootSegment = "command"`) を定義すると、`hareworks.command.eco`, `hareworks.command.eco.give` のような ID が自動生成され、`permits-lib` の `MutationSession` を使って Bukkit に適用されます。 - `permissions { ... }` で名前空間やルートセグメント (`rootSegment = "command"`) を定義すると、`hareworks.command.eco`, `hareworks.command.eco.give` のような ID が自動生成され、`permits-lib` の `MutationSession` を使って Bukkit に適用されます。
- 各 `command`/`literal`/`argument` ブロック内で `permission { ... }` を宣言すると、説明文・デフォルト値・タグ・パスの上書きを細かく制御できます。`skipPermission()` を呼び出せば、そのノードだけ自動生成から除外されます。 - `literal``command` ノードはデフォルトで Bukkit パーミッションとして登録されます。`string` や `integer` などの引数ノードは、`requires("permission.id")` もしくは `permission { id = ... }` を記述した場合のみ登録され、それ以外は構造上のノードに留まります。これにより `/money give <player> <amount>` では `...money.give` だけ付与すれば実行できます。
- 各ブロック内の `permission { ... }` で説明文・デフォルト値 (`PermissionDefault.TRUE/FALSE/OP/NOT_OP`)・タグ・パスを細かく制御できます。`requires(...)` を使うと DSL での検証と permits 側の登録が同じ ID になります。
- 引数ノードを明示的に登録したい場合は `permission { id = "example.money.give.amount" }``requires("example.money.give.amount")` を設定してください。逆にリテラルでも不要なら `skipPermission()` で除外できます。
- `requires("custom.id")` を指定した場合も、同じ ID が DSL の実行と `permits-lib` への登録の両方で利用されます (名前空間外の ID は登録対象外になります)。 - `requires("custom.id")` を指定した場合も、同じ ID が DSL の実行と `permits-lib` への登録の両方で利用されます (名前空間外の ID は登録対象外になります)。
- `KommandLib` のライフサイクルに合わせて `MutationSession` が適用/解除されるため、プラグインの有効化・無効化に伴い Bukkit のパーミッションリストも最新状態に保たれます。 - `KommandLib` のライフサイクルに合わせて `MutationSession` が適用/解除されるため、プラグインの有効化・無効化に伴い Bukkit のパーミッションリストも最新状態に保たれます。

@ -1 +1 @@
Subproject commit 29dc1f10dda3c24992796788f126fb457c8f6261 Subproject commit 58ad0e67c9b4c46a74019d4de11c0b72a37e3db7

View File

@ -126,6 +126,7 @@ abstract class BranchScope internal constructor(
val node = ValueNode(name, type) val node = ValueNode(name, type)
node.permission = inheritedPermission node.permission = inheritedPermission
node.condition = inheritedCondition node.condition = inheritedCondition
node.permissionOptions.preferSkipByDefault = true
children += node children += node
ValueBuilder(node).apply(block) ValueBuilder(node).apply(block)
} }

View File

@ -10,6 +10,7 @@ class PermissionOptions {
val tags: MutableSet<String> = linkedSetOf() val tags: MutableSet<String> = linkedSetOf()
var skip: Boolean = false var skip: Boolean = false
private var customPath: MutableList<String>? = null private var customPath: MutableList<String>? = null
internal var preferSkipByDefault: Boolean = false
internal var resolvedId: String? = null internal var resolvedId: String? = null
private set private set

View File

@ -1,5 +1,6 @@
package net.hareworks.kommand_lib.permissions package net.hareworks.kommand_lib.permissions
import net.hareworks.permits_lib.domain.NodeRegistration
import org.bukkit.permissions.PermissionDefault import org.bukkit.permissions.PermissionDefault
data class PermissionPlan( data class PermissionPlan(
@ -17,5 +18,6 @@ data class PlannedPermission(
val description: String?, val description: String?,
val defaultValue: PermissionDefault, val defaultValue: PermissionDefault,
val wildcard: Boolean, val wildcard: Boolean,
val tags: Set<String> val tags: Set<String>,
val registration: NodeRegistration
) )

View File

@ -4,6 +4,7 @@ import net.hareworks.kommand_lib.CommandDefinition
import net.hareworks.kommand_lib.nodes.KommandNode import net.hareworks.kommand_lib.nodes.KommandNode
import net.hareworks.kommand_lib.nodes.LiteralNode import net.hareworks.kommand_lib.nodes.LiteralNode
import net.hareworks.kommand_lib.nodes.ValueNode import net.hareworks.kommand_lib.nodes.ValueNode
import net.hareworks.permits_lib.domain.NodeRegistration
import org.bukkit.plugin.java.JavaPlugin import org.bukkit.plugin.java.JavaPlugin
internal class PermissionPlanner( internal class PermissionPlanner(
@ -18,7 +19,8 @@ internal class PermissionPlanner(
val entry = createEntry( val entry = createEntry(
options = PermissionOptions().apply { id = buildId(path) }, options = PermissionOptions().apply { id = buildId(path) },
pathSegments = path, pathSegments = path,
context = PermissionContext(commandName = "", path = path, kind = PermissionNodeKind.LITERAL) context = PermissionContext(commandName = "", path = path, kind = PermissionNodeKind.LITERAL),
registration = NodeRegistration.STRUCTURAL
) )
if (entry != null) entries[entry.id] = entry if (entry != null) entries[entry.id] = entry
path path
@ -59,14 +61,20 @@ internal class PermissionPlanner(
entries: MutableMap<String, PlannedPermission>, entries: MutableMap<String, PlannedPermission>,
commandName: String commandName: String
) { ) {
if (node.permissionOptions.skip) { val rawOverride = node.permissionOptions.pathOverride()
val shouldSkip =
node.permissionOptions.skip ||
(node.permissionOptions.preferSkipByDefault &&
node.permissionOptions.id.isNullOrBlank() &&
rawOverride == null)
if (shouldSkip) {
node.children.forEach { child -> node.children.forEach { child ->
planNode(child, basePath, entries, commandName) planNode(child, basePath, entries, commandName)
} }
return return
} }
val segment = node.segment()?.let { sanitize(it) } val segment = node.segment()?.let { sanitize(it) }
val pathAddition = node.permissionOptions.pathOverride()?.let { normalizeSegments(it) } val pathAddition = rawOverride?.let { normalizeSegments(it) }
val path = when { val path = when {
pathAddition != null -> basePath + pathAddition pathAddition != null -> basePath + pathAddition
segment != null -> basePath + segment segment != null -> basePath + segment
@ -100,7 +108,8 @@ internal class PermissionPlanner(
private fun createEntry( private fun createEntry(
options: PermissionOptions, options: PermissionOptions,
pathSegments: List<String>, pathSegments: List<String>,
context: PermissionContext context: PermissionContext,
registration: NodeRegistration = NodeRegistration.PERMISSION
): PlannedPermission? { ): PlannedPermission? {
val finalId = (options.id?.takeIf { it.isNotBlank() } ?: buildId(pathSegments)).trim() val finalId = (options.id?.takeIf { it.isNotBlank() } ?: buildId(pathSegments)).trim()
if (finalId.isEmpty()) return null if (finalId.isEmpty()) return null
@ -124,7 +133,8 @@ internal class PermissionPlanner(
description = description, description = description,
defaultValue = defaultValue, defaultValue = defaultValue,
wildcard = wildcard, wildcard = wildcard,
tags = tags tags = tags,
registration = registration
) )
} }

View File

@ -2,6 +2,7 @@ package net.hareworks.kommand_lib.permissions
import net.hareworks.permits_lib.bukkit.MutationSession import net.hareworks.permits_lib.bukkit.MutationSession
import net.hareworks.permits_lib.domain.MutablePermissionTree import net.hareworks.permits_lib.domain.MutablePermissionTree
import net.hareworks.permits_lib.domain.NodeRegistration
import org.bukkit.plugin.java.JavaPlugin import org.bukkit.plugin.java.JavaPlugin
internal class PermissionRuntime( internal class PermissionRuntime(
@ -15,8 +16,18 @@ internal class PermissionRuntime(
if (plan.isEmpty()) return if (plan.isEmpty()) return
val mutable = MutablePermissionTree.create(plan.config.namespace) val mutable = MutablePermissionTree.create(plan.config.namespace)
val sorted = plan.entries.sortedBy { it.relativePath.size } val sorted = plan.entries.sortedBy { it.relativePath.size }
val registrations = sorted
.mapNotNull { entry ->
entry.relativePath.takeIf { it.isNotEmpty() }?.joinToString(".")?.let { it to entry.registration }
}
.toMap()
sorted.forEach { entry -> sorted.forEach { entry ->
mutable.node(entry.relativePath.joinToString(".")) { if (entry.relativePath.isEmpty()) {
plugin.logger.warning("Skipping permission '${entry.id}' because it resolved to the namespace root.")
return@forEach
}
val nodeId = entry.relativePath.joinToString(".")
mutable.node(nodeId, entry.registration) {
entry.description?.let { description = it } entry.description?.let { description = it }
defaultValue = entry.defaultValue defaultValue = entry.defaultValue
wildcard = entry.wildcard wildcard = entry.wildcard
@ -24,7 +35,9 @@ internal class PermissionRuntime(
} }
val parent = entry.parentPath val parent = entry.parentPath
if (parent != null && parent.isNotEmpty()) { if (parent != null && parent.isNotEmpty()) {
mutable.node(parent.joinToString(".")) { val parentId = parent.joinToString(".")
val parentRegistration = registrations[parentId] ?: NodeRegistration.STRUCTURAL
mutable.node(parentId, parentRegistration) {
child(entry.relativePath.last()) child(entry.relativePath.last())
} }
} }