# 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 ` | プレイヤー視点の約 1.5 ブロック先に TextDisplay を生成し、即座にチャット編集モードへ。次に送信したメッセージ(または `cancel`)が内容になります。 | | `/ghostdisplay create block ` | BlockDisplay を生成します。`oak_planks[facing=north]` のような `BlockData` 文字列を指定してください。 | | `/ghostdisplay create item ` | ItemDisplay を生成します。`minecraft:stick` などのアイテム ID を受け付けます。 | | `/ghostdisplay text set ` | TextDisplay のテキストを即時更新します。`_` はスペースに、`\n` は改行に変換されます。 | | `/ghostdisplay viewer add|remove ` | 任意のプレイヤーまたはセレクターを表示対象に追加/削除します。`/ghostdisplay viewer clear ` で全員解除。 | | `/ghostdisplay audience permission add ` | 指定パーミッションを持つプレイヤーに自動表示 (`remove` で解除)。 | | `/ghostdisplay audience near set ` | Display 周囲の半径プレイヤーへ自動表示 (`audience clear` で全自動表示を解除)。 | | `/ghostdisplay list` / `/ghostdisplay info ` | 登録済み Display の一覧、情報(座標 / Viewers / Audiences / 内容)を表示。 | | `/ghostdisplay delete ` | 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` 時に一緒にコンパイルされます。