kommand-lib/MIGRATION_GUIDE.md
2025-12-07 06:03:18 +09:00

452 lines
11 KiB
Markdown

# kommand-lib マイグレーションガイド
このガイドでは、旧バージョンの kommand-lib から最新の Brigadier ネイティブ対応バージョンへの移行方法を説明します。
---
## 📋 目次
1. [変更の概要](#変更の概要)
2. [破壊的変更](#破壊的変更)
3. [マイグレーション手順](#マイグレーション手順)
4. [コード例の比較](#コード例の比較)
5. [トラブルシューティング](#トラブルシューティング)
---
## 変更の概要
### 🎯 主な変更点
1. **Brigadier ネイティブ対応**
- Paper 1.21 の Lifecycle API を使用したコマンド登録
- クライアント側での構文ヒントと検証
- より正確な型システム
2. **引数の型変更**
- `coordinates()` の返り値が `Coordinates3` から `io.papermc.paper.math.Position` に変更
- Player/Entity セレクターの内部処理が改善
3. **自動登録**
- `kommand()` 関数の呼び出しで自動的にコマンドが登録されるように変更
---
## 破壊的変更
### 🔴 1. `coordinates()` 引数の型変更
#### 旧バージョン (動作しません)
```kotlin
coordinates("point") {
executes {
val coords = argument<Coordinates3>("point")
val target = coords.resolve(player.location)
// Coordinates3 型は存在しません
}
}
```
#### 新バージョン (正しい方法)
```kotlin
coordinates("point") {
executes {
val position = argument<io.papermc.paper.math.Position>("point")
val location = position.toLocation(player.world)
// Position 型を使用します
}
}
```
**理由**: Paper の Brigadier API は `io.papermc.paper.math.Position` を返します。これは Paper の公式 API に準拠しています。
---
### 🟡 2. Player/Entity セレクターの内部処理
**ユーザーコードに変更は不要です**が、内部的に以下の変更が行われました:
#### 内部処理の改善
```kotlin
// 旧: 直接キャスト (実行時エラーの原因)
val player = context.getArgument("player", Player::class.java)
// 新: Resolver を使用して解決 (正しい方法)
val resolver = context.getArgument("player", PlayerSelectorArgumentResolver::class.java)
val player = resolver.resolve(source).firstOrNull()
```
**影響**: Player/Entity 引数がより安定して動作するようになりました。
---
## マイグレーション手順
### ステップ 1: 依存関係の確認
`build.gradle.kts` で Paper API のバージョンを確認してください:
```kotlin
dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
// 1.21 以降が必要です
}
```
### ステップ 2: import 文の追加
`coordinates()` を使用している場合、import を追加してください:
```kotlin
import io.papermc.paper.math.Position
```
### ステップ 3: コードの更新
以下のパターンを検索して置換してください:
#### パターン 1: coordinates の型指定
**検索**:
```kotlin
argument<Coordinates3>("
```
**置換**:
```kotlin
argument<io.papermc.paper.math.Position>("
```
または、import を追加して:
```kotlin
argument<Position>("
```
#### パターン 2: coordinates の解決方法
**検索**:
```kotlin
val coords = argument<Coordinates3>("pos")
val location = coords.resolve(baseLocation)
```
**置換**:
```kotlin
val position = argument<Position>("pos")
val location = position.toLocation(world)
```
### ステップ 4: ビルドとテスト
```bash
./gradlew build
```
エラーがないことを確認してから、サーバーでテストしてください。
---
## コード例の比較
### 例 1: スポーン地点の設定
#### ❌ 旧バージョン
```kotlin
literal("setspawn") {
coordinates("point") {
executes {
val base = (sender as? Player)?.location ?: return@executes
val coords = argument<Coordinates3>("point")
val target = coords.resolve(base)
plugin.server.worlds.first().setSpawnLocation(target)
sender.sendMessage("Spawn set to ${target.x}, ${target.y}, ${target.z}")
}
}
}
```
#### ✅ 新バージョン
```kotlin
literal("setspawn") {
coordinates("point") {
executes {
val player = sender as? Player ?: return@executes
val position = argument<Position>("point")
val location = position.toLocation(player.world)
player.world.setSpawnLocation(location)
sender.sendMessage("Spawn set to ${location.x}, ${location.y}, ${location.z}")
}
}
}
```
**変更点**:
- `Coordinates3``Position`
- `coords.resolve(base)``position.toLocation(world)`
- より明確な変数名
---
### 例 2: テレポートコマンド
#### ❌ 旧バージョン
```kotlin
literal("tp") {
coordinates("destination") {
executes {
val player = sender as? Player ?: return@executes
val coords = argument<Coordinates3>("destination")
val target = coords.resolve(player.location)
player.teleport(target)
}
}
}
```
#### ✅ 新バージョン
```kotlin
literal("tp") {
coordinates("destination") {
executes {
val player = sender as? Player ?: return@executes
val position = argument<Position>("destination")
val location = position.toLocation(player.world)
player.teleport(location)
}
}
}
```
---
### 例 3: 範囲指定コマンド
#### ❌ 旧バージョン
```kotlin
literal("fill") {
coordinates("pos1") {
coordinates("pos2") {
executes {
val player = sender as? Player ?: return@executes
val base = player.location
val pos1 = argument<Coordinates3>("pos1").resolve(base)
val pos2 = argument<Coordinates3>("pos2").resolve(base)
// 処理...
}
}
}
}
```
#### ✅ 新バージョン
```kotlin
literal("fill") {
coordinates("pos1") {
coordinates("pos2") {
executes {
val player = sender as? Player ?: return@executes
val world = player.world
val pos1 = argument<Position>("pos1").toLocation(world)
val pos2 = argument<Position>("pos2").toLocation(world)
// 処理...
}
}
}
}
```
---
## Position API リファレンス
### Position のメソッド
```kotlin
interface Position {
fun x(): Double
fun y(): Double
fun z(): Double
fun blockX(): Int
fun blockY(): Int
fun blockZ(): Int
fun toLocation(world: World): Location
}
```
### 使用例
```kotlin
val position = argument<Position>("pos")
// 座標の取得
val x = position.x()
val y = position.y()
val z = position.z()
// ブロック座標の取得
val blockX = position.blockX()
val blockY = position.blockY()
val blockZ = position.blockZ()
// Location への変換
val location = position.toLocation(player.world)
```
---
## トラブルシューティング
### 問題 1: `Coordinates3` が見つからない
**エラー**:
```
Unresolved reference: Coordinates3
```
**解決方法**:
`Coordinates3` は存在しません。`io.papermc.paper.math.Position` を使用してください。
```kotlin
// ❌ 間違い
argument<Coordinates3>("pos")
// ✅ 正しい
argument<Position>("pos")
```
---
### 問題 2: `resolve()` メソッドが見つからない
**エラー**:
```
Unresolved reference: resolve
```
**解決方法**:
`Position` には `resolve()` メソッドはありません。`toLocation(world)` を使用してください。
```kotlin
// ❌ 間違い
val location = position.resolve(baseLocation)
// ✅ 正しい
val location = position.toLocation(world)
```
---
### 問題 3: Player セレクターが動作しない
**症状**: Player 引数を使用するとエラーが発生する
**解決方法**:
最新バージョンに更新してください。内部的に `ArgumentResolver` が自動的に処理します。
```kotlin
// これは自動的に動作します
val player = argument<Player>("target")
val players = argument<List<Player>>("targets")
```
---
### 問題 4: コマンドが登録されない
**症状**: `/help` にコマンドが表示されない
**解決方法**:
最新バージョンでは `kommand()` 関数の呼び出しで自動的に登録されます。
```kotlin
class MyPlugin : JavaPlugin() {
private lateinit var commands: KommandLib
override fun onEnable() {
// これだけで自動的に登録されます
commands = kommand(this) {
command("mycommand") {
// ...
}
}
}
}
```
---
## よくある質問 (FAQ)
### Q1: 相対座標 (`~`) は引き続き使えますか?
**A**: はい、引き続き使えます。`Position` は相対座標を完全にサポートしています。
```kotlin
// "~ ~1 ~-2" のような入力が可能
val position = argument<Position>("pos")
```
---
### Q2: 旧バージョンとの互換性はありますか?
**A**: `coordinates()` 引数の型が変更されているため、**互換性はありません**。マイグレーションが必要です。
ただし、`player()`, `players()`, `selector()` などの他の引数は互換性があります。
---
### Q3: マイグレーションにどのくらい時間がかかりますか?
**A**: プロジェクトの規模によりますが、通常は以下の通りです:
- **小規模** (1-5 コマンド): 5-10 分
- **中規模** (5-20 コマンド): 15-30 分
- **大規模** (20+ コマンド): 30-60 分
主な作業は検索と置換なので、比較的短時間で完了します。
---
### Q4: 段階的な移行は可能ですか?
**A**: いいえ、`coordinates()` を使用している場合は一度にすべて移行する必要があります。
ただし、`coordinates()` を使用していないコマンドは変更不要です。
---
## サポート
問題が発生した場合は、以下のドキュメントを参照してください:
- [README.md](./README.md) - 基本的な使い方
- [BRIGADIER_REVIEW.md](./BRIGADIER_REVIEW.md) - 詳細なレビュー
- [Paper API Documentation](https://docs.papermc.io/paper/dev/command-api/arguments/location) - Position API の詳細
---
## まとめ
### ✅ マイグレーションチェックリスト
- [ ] Paper API 1.21 以降を使用していることを確認
- [ ] `Coordinates3``Position` に置換
- [ ] `coords.resolve()``position.toLocation()` に置換
- [ ] 必要な import を追加
- [ ] ビルドが成功することを確認
- [ ] サーバーでテストして動作を確認
### 🎉 完了!
マイグレーションが完了すると、以下のメリットが得られます:
- ✅ クライアント側での構文ヒント
- ✅ より正確な型チェック
- ✅ Paper の公式 API に準拠
- ✅ より安定した動作
ご不明な点がございましたら、お気軽にお問い合わせください。