170 lines
8.6 KiB
Markdown
170 lines
8.6 KiB
Markdown
# Kommand Lib
|
|
|
|
Paper/Bukkit サーバー向けのコマンド定義を DSL で記述するためのライブラリです。ルート定義から引数の型、補完、パーミッション伝播までを宣言的に表現でき、手続き的な `CommandExecutor` 実装を大きく簡略化します。
|
|
|
|
## 特徴
|
|
|
|
- Kotlin DSL で `command { literal { argument { ... } } }` のようにネストを表現
|
|
- 型付き引数 (`string`, `integer`, `float`, `player`, `selector`, `coordinates` など) と検証ロジックを組み込み
|
|
- 1 つの定義から実行とタブ補完の両方を生成
|
|
- パーミッションや条件をノード単位で宣言し、子ノードへ自動伝播
|
|
- `suggests {}` で引数ごとの補完候補を柔軟に制御
|
|
- `permits-lib` との連携により、コマンドツリーから Bukkit パーミッションを自動生成し、`compileOnly` 依存として参照可能
|
|
|
|
## 依存関係
|
|
|
|
`build.gradle.kts` では Paper API と Kotlin 標準ライブラリのみを `compileOnly` に追加しています。Paper 1.21.10 対応の API を利用しています。
|
|
|
|
```kotlin
|
|
plugins {
|
|
kotlin("jvm") version "2.2.21"
|
|
id("de.eldoria.plugin-yml.paper") version "0.8.0"
|
|
id("com.gradleup.shadow") version "9.2.2"
|
|
}
|
|
|
|
dependencies {
|
|
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
|
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib")
|
|
// ../permits-lib を includeBuild しているので module 参照でOK
|
|
compileOnly("net.hareworks.hcu:permits-lib:1.0")
|
|
}
|
|
```
|
|
|
|
## 使い方
|
|
|
|
1. プラグインの `onEnable` などで `kommand(plugin) { ... }` DSL を呼び出します。
|
|
2. `command("root", "alias") { ... }` でコマンドを宣言し、`literal` や `string`/`integer` 引数を追加します。
|
|
3. `executes { ... }` 内で `string("player")` や `int("amount")` を使ってパース済みの値を取得します。
|
|
|
|
### サンプル: 経済コマンド
|
|
|
|
```kotlin
|
|
class EconomyPlugin : JavaPlugin() {
|
|
private lateinit var commands: KommandLib
|
|
|
|
override fun onEnable() {
|
|
commands = kommand(this) {
|
|
command("eco", "economy") {
|
|
description = "Economy management"
|
|
permission = "example.eco"
|
|
|
|
literal("give") {
|
|
player("target") // プレイヤー名 or セレクター (@p 等)
|
|
integer("amount", min = 1)
|
|
|
|
executes {
|
|
val target = player("target")
|
|
val amount = int("amount")
|
|
sender.sendMessage("Giving $amount to ${target.name}")
|
|
}
|
|
}
|
|
|
|
literal("speed") {
|
|
players("targets") // @a, プレイヤー名, などをまとめて取得
|
|
float("value", min = 0.1, max = 5.0)
|
|
|
|
executes {
|
|
val targets = players("targets")
|
|
val speed = float("value")
|
|
targets.forEach { it.walkSpeed = speed.toFloat() / 5.0f }
|
|
sender.sendMessage("Updated ${targets.size} players")
|
|
}
|
|
}
|
|
|
|
literal("setspawn") {
|
|
coordinates("point") // "~ ~1 ~-2" のような入力を受け付ける
|
|
|
|
executes {
|
|
val base = (sender as? Player)?.location ?: return@executes
|
|
val target = location("point", base)
|
|
plugin.server.worlds.first().setSpawnLocation(target)
|
|
sender.sendMessage("Spawn set to ${target.x}, ${target.y}, ${target.z}")
|
|
}
|
|
}
|
|
|
|
literal("inspect") {
|
|
selector("entities")
|
|
|
|
executes {
|
|
val entities = selector("entities")
|
|
sender.sendMessage("Selector resolved ${entities.size} entities")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onDisable() {
|
|
commands.unregister()
|
|
}
|
|
}
|
|
```
|
|
|
|
### DSL 構文のポイント
|
|
|
|
- `literal("sub") { ... }` は固定語句を表すノードです。`requires("permission.node")` でその枝のみにパーミッションを設定できます。
|
|
- `string("name")` や `integer("value", min = 0)` は値をパースし、成功すると `KommandContext` に記憶されます。
|
|
- `float("speed")` は倍精度を、`player("target")`/`players("targets")`/`selector("entities")` は Minecraft の標準セレクター (`@p`, `@a`, `@s` など) やプレイヤー名を型付きで扱えます。
|
|
- `suggests { prefix -> ... }` を指定すると、タブ補完時に任意の候補リストを返せます。
|
|
- `coordinates("pos")` は `x y z` をまとめて 1 つの引数として受け取り、`location("pos", player.location)` で現在位置を基準に解決できます (`~` を使用した相対座標に対応)。
|
|
- `command` や各ノードの `condition { sender -> ... }` で実行条件 (例: コンソール禁止) を追加できます。
|
|
- ルートレベルで `executes { ... }` を指定すると、引数なしで `/eco` を実行した場合に呼び出されます。
|
|
|
|
## 自動パーミッション生成 (`permits-lib`)
|
|
|
|
`permits-lib` を `compileOnly` で参照している場合、DSL から Bukkit パーミッションツリーを自動生成できます。
|
|
|
|
```kotlin
|
|
commands = kommand(this) {
|
|
permissions {
|
|
namespace = "hareworks"
|
|
rootSegment = "command"
|
|
defaultDescription { ctx ->
|
|
"Allows /${ctx.commandName} (${ctx.path.joinToString(" ")})"
|
|
}
|
|
}
|
|
|
|
command("eco") {
|
|
permission {
|
|
description = "Allows /eco"
|
|
tags("economy")
|
|
}
|
|
|
|
literal("give") {
|
|
permission {
|
|
description = "Allows /eco give"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
- `permissions { ... }` で名前空間やルートセグメント (`rootSegment = "command"`) を定義すると、`hareworks.command.eco`, `hareworks.command.eco.give` のような ID が自動生成され、`permits-lib` の `MutationSession` を使って Bukkit に適用されます。
|
|
- `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 は登録対象外になります)。
|
|
- `KommandLib` のライフサイクルに合わせて `MutationSession` が適用/解除されるため、プラグインの有効化・無効化に伴い Bukkit のパーミッションリストも最新状態に保たれます。
|
|
|
|
## 組み込み引数の一覧
|
|
|
|
| DSL | 返り値 | 補足 |
|
|
| --- | --- | --- |
|
|
| `string("name")` | `String` | 任意のトークン。`suggests {}` で補完可 |
|
|
| `integer("value", min, max)` | `Int` | 範囲チェック付き |
|
|
| `float("speed", min, max)` | `Double` | 小数/指数表記に対応 |
|
|
| `player("target", allowSelectors = true)` | `Player` | `@p` などのセレクターまたはプレイヤー名を 1 人に解決 |
|
|
| `players("targets")` | `List<Player>` | `@a`/`@r` など複数指定、プレイヤー名入力も可 |
|
|
| `selector("entities")` | `List<Entity>` | Bukkit の `Bukkit.selectEntities` をそのまま利用 |
|
|
| `coordinates("pos")` | `Coordinates3` | `~` 相対座標を含む 3 軸をまとめて扱う |
|
|
|
|
`Coordinates3` は `coordinates("pos") { ... }` 直後のコンテキストで `coordinates("pos")` もしくは `location("pos", baseLocation)` として取得できます。
|
|
|
|
## ビルドとテスト
|
|
|
|
```bash
|
|
./gradlew build
|
|
```
|
|
|
|
ShadowJar タスクが実行され、`build/libs` に出力されます。Paper サーバーに配置して動作確認してください。
|