GhostDisplays/README.md
2026-03-31 10:40:46 +09:00

73 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GhostDisplays
Paper 1.21.10 向けの不可視ディスプレイ制御ライブラリです。TextDisplay / BlockDisplay / ItemDisplay をプレイヤー単位で表示・クリック検知できるようにし、ゴースト化した UI やガイドラインをサーバー側で柔軟に提供できます。
## 提供機能
- `DisplayService` による Text/Block/Item Display の生成 API
- `DisplayController` を介したパケットベースの表示・非表示制御(参照カウント管理)
- `AudiencePredicate`/`AudiencePredicates` による可視対象の自動同期(ログイン・ワールド移動・リスポーンで再評価)
- FakeInteraction エンティティを用いたクリック判定サポートと、優先度付きクリックハンドラー
- まとめて `destroyAll()` できるリソース管理
## スタンドアロンでの使い方
プラグインを `plugins/` に配置して起動すると `/ghostdisplay` コマンドが利用できます。デフォルトで OP のみ実行可能ですが、`ghostdisplays.command.*` を付与すると通常権限でも操作できます。
| コマンド | 説明 |
| --- | --- |
| `/ghostdisplay create text <id>` | プレイヤー視点の約 1.5 ブロック先に TextDisplay を生成し、即座にチャット編集モードへ。次に送信したメッセージ(または `cancel`)が内容になります。 |
| `/ghostdisplay create block <id> <blockstate>` | BlockDisplay を生成します。`oak_planks[facing=north]` のような `BlockData` 文字列を指定してください。 |
| `/ghostdisplay create item <id> <material>` | ItemDisplay を生成します。`minecraft:stick` などのアイテム ID を受け付けます。 |
| `/ghostdisplay text set <id> <content>` | TextDisplay のテキストを即時更新します。`_` はスペースに、`\n` は改行に変換されます。 |
| `/ghostdisplay viewer add|remove <id> <player/@a>` | 任意のプレイヤーまたはセレクターを表示対象に追加/削除します。`/ghostdisplay viewer clear <id>` で全員解除。 |
| `/ghostdisplay audience permission add <id> <permission>` | 指定パーミッションを持つプレイヤーに自動表示 (`remove` で解除)。 |
| `/ghostdisplay audience near set <id> <radius>` | Display 周囲の半径プレイヤーへ自動表示 (`audience clear` で全自動表示を解除)。 |
| `/ghostdisplay list` / `/ghostdisplay info <id>` | 登録済み Display の一覧、情報(座標 / Viewers / Audiences / 内容)を表示。 |
| `/ghostdisplay delete <id>` | Display を完全に削除します。 |
## 技術的ポイント
- **NMS パケットベースの FakeEntity 方式** — サーバー上に実エンティティを生成せず、クライアントへのパケット送信のみで表示を実現。エンティティティック・コリジョン・永続化のオーバーヘッドがゼロ
- パケット送信はスレッドセーフなため、Folia のリージョンスケジューリングに依存しないシンプルな設計
- クリック検知は Netty パイプラインで `ServerboundInteractPacket` を傍受し、FakeInteraction の entityId にマッチしたらハンドラーを発火
- Predicate ごとにアクティブなプレイヤー集合を持つため、複数条件での重複表示にも対応
- `paperweight-userdev` による NMS アクセス1.21.11 対応)
## API 利用例
```kotlin
val service: DisplayService = GhostDisplaysPlugin.service()
// TextDisplay を生成
val controller = service.createTextDisplay(location) {
text = Component.text("Hello")
billboard = Display.Billboard.CENTER
viewRange = 0.5f
}
controller.show(player)
// テキスト更新
controller.updateText { it.text = Component.text("Updated") }
// 共通プロパティ更新
controller.updateDisplay { it.billboard = Display.Billboard.FIXED }
// テレポート
controller.teleport(newLocation)
// Audience ルール
controller.addAudienceRule(AudiencePredicates.near(location, 30.0), AudienceAction.ADD)
// クリックハンドラー
controller.onClick { ctx -> ctx.player.sendMessage("Clicked!") }
// 破棄
controller.destroy()
```
## 同梱ライブラリ
- コマンド定義は `kommand-lib`Kotlin DSLを使用し、`permits-lib` と連携して `ghostdisplays.command.*` のパーミッションツリーを自動生成しています。
- どちらも本リポジトリの `kommand-lib/` 以下にサブモジュールとして含まれており、`./gradlew build` 時に一緒にコンパイルされます。