GUI
概要
GUI は、TypeWriter の 1 つのエントリ Open GUI を、完全なインベントリメニューに変えます。コンテナの種類(チェスト、金床、行商人ウィンドウ、記入済みの本など)を選び、MiniMessage でタイトルを書き、内容を、エントリの layoutPool に保存されたレイアウトのツリーとして記述します。各レイアウトはアイテムを配置します。アイテムは、素材、名前、ロア、そしてプレイヤーがクリックしたときの動作を持ちます。
すべては Web パネルで編集します。手作業で書くメニューファイルはありません。メニューは他のアクションと同じように、クエストのステップ、NPC のダイアログ、コマンドイベント、または別のメニューから開きます。クリックはコンソールコマンドを実行し、他のエントリをトリガーし、ファクトを変更します。つまりメニューは、TypeWriter のページを動かすもう 1 つの手段です。
GUI は、BTC の他のメニュー拡張機能の基盤でもあります。Shops と Quest Codex は独自のウィンドウを持ちません。open_gui のレイアウトにマーカーアイテムを置くと、拡張機能がそれを商品やクエストで埋めます。
機能
- 10 種類のレイアウト —
simple、flex、paginated、scrollable、frame、composite、book、merchant、storage、leaderboard。 - 24 種類のコンテナ — 9〜54 スロットのチェストサイズのほか、金床、エンチャントテーブル、鍛冶台、石切台、砥石、機織り機、製図台、行商人、本、ホッパー、かまど類など。
- あらゆる場所で MiniMessage — タイトル、アイテム名、ロアで、色、グラデーション、PlaceholderAPI のプレースホルダーを使えます。
- クリックの種類ごとのアクション — 左、右、シフト、中、ダブルクリック、数字キー、ドロップ、オフハンド入れ替え。それぞれに独自のコマンドとトリガーを設定できます。
- スロットの権限 —
viewPermissionでスロットを非表示にしたり、clickPermissionで表示したまま反応しないようにしたりできます。 - スロットの繰り返し — アイテムをコピーする代わりに、
count、direction、gap、repeatYで行やブロックを埋めます。 - ビューとタブ — 1 つのメニューの枠組みで複数の画面を実現します。パンくずリスト形式のタイトルと、点灯するタブに対応します。
- 永続ストレージ — プレイヤーごと、またはグループごとにアイテムを保持するスロット。クォータ、プレースホルダー、閉じたときのドロップ(任意)に対応します。
- リーダーボード — 1 つ以上のファクトに基づいて、プレイヤー、ワールド、グループをランキング化できます(オフラインのプレイヤーも含む)。また、
sourceフィールドを通じて他の拡張機能が供給する行(たとえば Dungeon の統計)も表示できます。 - 拡張インベントリ — プレイヤー自身のインベントリを 4 行分の追加メニュー行に変え、10 行のキャンバスにします。
インストール
- Paper または Folia サーバーに TypeWriter をインストールします。TypeWriter がすでに必要としている PacketEvents が存在している必要があります。
- GUI の GitHub releases から JAR をダウンロードします(上のサマリーパネルにあるボタン)。
plugins/Typewriter/extensions/に置き、サーバーを再起動します。- 任意: タイトルで
<image>または<shift>タグを使ってカスタム背景を描く場合は、CraftEngine をインストールします。
Shops や Quest Codex など、GUI に依存する拡張機能より先に GUI をインストールしてください。
公開版の GUI リリースには、単体のメニューエディタとその Web サーバーは含まれていません。メニューは TypeWriter の Web パネルで編集します。リリースに含まれるのは、パブリッシュ済みの open_gui エントリを読み取り、壊れたメニューをコンソールに報告する起動時チェックだけです(トラブルシューティングを参照)。
はじめに
3 つのボタンを持つ小さなメニューを作ります。
- Web パネルで sequence ページを開き、Open GUI エントリを追加します。名前は
main_menuにします。 guiTypeをCUSTOM、sizeをSIZE_27、titleを<gold>Main menuに設定します。layoutPoolに、タイプsimpleのレイアウトを追加してidをmainにし、mainLayoutIdにmainと入力します。- レイアウトの
itemsに、x4、y1 のアイテムを追加します。itemでDIAMONDを選び、displayNameを<aqua>Rewardsに設定し、loreに<gray>Click to claimの行を追加します。 interactionListに、typeがLEFT_CLICKのインタラクションを追加します。commandsにgive %player% diamond 1のようなコンソールコマンドを追加するか、triggersにエントリをリンクします。クリック後にメニューを閉じるには、closeMenuを有効にします。- 2 つ目の
simpleアイテムを、count9、directionright、灰色のステンドグラス板で追加し、枠線の行を描きます。displayNameは半角スペース 1 つにします。 - Open GUI エントリを、それを発動するもの(たとえばダイアログ選択肢のトリガーやコマンドイベント)にリンクし、Publish します。
frame、scrollable、paginated のレイヤーを追加する前に、1 つの simple レイアウトをゲーム内で動かしてください。すべてのレイアウトは id で指定されるため、メニューが空で開く場合は、まず mainLayoutId の入力ミスを確認してください。
仕組み
アクションが発動すると、拡張機能はそのプレイヤー用のレイアウトツリーを構築し(criteria と権限はこの時点で評価されます)、メニューセッションを登録して、インベントリを表示します。各クリックは、その位置のスロットに対して解決され、対応するインタラクションが実行されます。セッションは前のメニューを記憶しているため、gui:back でプレイヤーが来たメニューに戻れます。
メニュー
コンテナの種類
guiType はウィンドウを選択します。CUSTOM はチェストのような単純なインベントリで、高さは size で選びます。size は CUSTOM にのみ適用され、デフォルトは 6 行です。他の種類は、そのウィンドウのバニラのサイズを使います。
guiType | ウィンドウ |
|---|---|
CUSTOM, CHEST, ENDER_CHEST, BARREL, SHULKER_BOX | チェスト形式のグリッド。CUSTOM の場合、size は SIZE_9、SIZE_18、SIZE_27、SIZE_36、SIZE_45、SIZE_54 のいずれかです。 |
HOPPER, DISPENSER, DROPPER | 固定サイズの小さなコンテナ。 |
FURNACE, BLAST_FURNACE, SMOKER, BREWING_STAND, BEACON | 機械のウィンドウ。 |
CRAFTING_TABLE, ENCHANTING_TABLE, ANVIL, SMITHING_TABLE, GRINDSTONE, LOOM, CARTOGRAPHY_TABLE, STONECUTTER | バニラの作業台。レイアウトがない場合はバニラの画面と同じ動作になり、GUI は開閉のみを管理します。 |
MERCHANT, VILLAGER_TRADE | 村人の取引ウィンドウ。merchant レイアウトで埋めます。 |
BOOK | 記入済みの本。book レイアウトで埋めます。 |
レイアウト
各レイアウトは、layoutPool の名前付きエントリです。mainLayoutId で指定されたものがルートで、その他は参照を通じて到達されます(composite の子、scrollable の innerId、frame の layoutId)。
| レイアウト | 用途 | 主なフィールド |
|---|---|---|
simple | x/y の位置に置く固定ボタンと装飾。 | items |
flex | 行に自動配置されるアイテム。 | justifyContent(START、CENTER、END、SPACE_BETWEEN)、alignItems、wrap、virtualHeight |
paginated | ページに分割された長いリスト。 | itemsPerPage, slots, items, navigationButtons(NEXT、PREVIOUS、BACK、INDICATOR) |
scrollable | ウィンドウより縦または横に大きなコンテンツ。 | innerId, virtualWidth, virtualHeight, buttons(direction、step), showDefaultButtons, defaultStep |
frame | 複数の独立した矩形領域。たとえばタブ、コンテンツ、フッター。 | frames(id、x、y、width、height、layoutId) |
composite | 背景、コンテンツ、ボタンのレイヤーを重ねます。 | children(レイアウト ID。後の子が上に描画されます) |
book | 記入済みの本のページ。 | pages(MiniMessage) |
merchant | カスタムアイテムを使った村人の取引。 | trades(result、costOne、costTwo、maxUses、criteria) |
storage | GUI Storage アーティファクトに支えられた永続スロット。 | entry, groupKey, slots |
leaderboard | ページ付きのランキングの行。ファクト、または他の拡張機能の source から。 | leaderboard, x, y, width, height, previousButton, nextButton |
book または merchant レイアウトは、メインレイアウトとしてのみ動作し、guiType は対応するウィンドウに上書きされます。scrollable レイアウトは、showDefaultButtons が有効な間(デフォルト)、既定の矢印を受け取ります。buttons にエントリがない方向ごとに 1 つ追加されます。レイアウト、フレーム、スロット を参照してください。
各レイアウトの詳しい解説は、レイアウト、フレーム、スロットを参照してください。
アイテムとスロット
レイアウトのすべてのアイテムは、同じフィールドを持つスロットの記述です。
| フィールド | 役割 |
|---|---|
item | 表示するアイテム。空の場合、スロットにはプレイヤーがメインハンドに持っているアイテムが表示されます。 |
displayName, lore | PlaceholderAPI に対応した MiniMessage テキスト。名前はデフォルトで斜体になりません。斜体にしたい場合は <italic> を追加してください。空の displayName は、アイテム名を空の名前で置き換えず、元の名前を保持します。 |
x, y | 列は 0〜8、行は一番上が 0。 |
rollPerSlot | 複数のスロットに繰り返され、item がランダムなアイテム用:オフ(既定)では 1 回だけ抽選され、すべてのスロットが同じ結果を表示します。オンでは、メニューを開くときに各スロットが個別に抽選されます。結果は、liveItem がオンでない限り、メニューが開いている間保持されます。 |
liveItem | オフ(既定):アイテムはメニューを開くときに抽選され、セッション中ずっと保持されます。更新時には名前と説明文だけが追従します。オン:更新のたびにアイテムが再評価され、ランダムなアイテムは毎回抽選し直されます。rollPerSlot がオンなら、繰り返された各スロットが更新ごとに個別に抽選し、オフなら繰り返されたすべてのスロットが更新ごとに 1 回の抽選を共有します。空の名前は引き続き無視されます。 |
count, direction, gap, repeatY | スロットの繰り返し。下記を参照。 |
criteria | 条件に合わないプレイヤーには、スロットが描画されません。 |
viewPermission | スロットを見るために必要な権限。 |
clickPermission | スロットを使うために必要な権限。ない場合、スロットは描画されますが反応しません。 |
allowPickup, isGhost | アイテムをメニューから取り出せるかどうか。どちらもデフォルトではオフです。ゴーストアイテムはクリックできますが、移動やコピーはできません。 |
cooldownTicks | 同じスロットを再びクリックできるようになるまでのティック数。 |
interactionList, triggers, modifiers | クリックしたときの動作。 |
input | クリック時にテキスト入力ダイアログを開きます。 |
storageId | スロットを、storagePool の永続ストレージスロットにします。 |
buttonType, buttonPrefix | スロットを、他の拡張機能が提供するボタンとして印付けします。 |
animation | メニューが開くときに、指定したミリ秒の時間をかけて、スロットを目標位置まで移動させます。 |
スロットの繰り返し。 count は、direction(right、left、down、up)に沿ってアイテムを繰り返します。gap は間隔ではなくステップです。1 は隣接、2 はコピーの間に空きスロットを 1 つ入れ、0 は 1 と同じ動作です。repeatY は、行全体を垂直方向の軸に繰り返します。direction がない場合、count、gap、repeatY は無視され、スロットは 1 つだけ配置されます。これらのフィールドが数えるのはスロットで、アイテムのスタック数ではありません。
重なり。 2 つのスロットが同じマスを共有する場合は、順序に関係なく、何かを行うスロット(クリックアクション、タグ、ストレージスロット)が、純粋な装飾のスロットより優先されます。同じ種類同士では、最後に宣言されたものが優先されます。そのマスを示す警告が一度だけログに記録されます。
クリックアクション
interactionList は、クリックの種類をコマンドとトリガーに対応付けます。使えるタイプは、LEFT_CLICK、RIGHT_CLICK、SHIFT_LEFT_CLICK、SHIFT_RIGHT_CLICK、MIDDLE_CLICK、DOUBLE_CLICK、NUMBER_KEY_1 〜 NUMBER_KEY_9、DROP、DROP_ALL、SWAP_OFFHAND です。
commandsはコンソールから実行されます。%player%はプレイヤー名に置き換えられ、PlaceholderAPI のプレースホルダーが先に解決されます。triggersは、プレイヤーに対して TypeWriter のエントリを発動します。スロット自身のtriggersとmodifiersは、左クリックまたは右クリックのたびに、あるいは特定のインタラクションが一致したときに発動します。closeMenuはアクションの後でウィンドウを閉じます。executeReturnは前のメニューに戻ります。
gui: で始まるコマンドは、GUI 自身が処理します。
| コマンド | 効果 |
|---|---|
gui:close | メニューを閉じます。 |
gui:back | セッションの前のメニューを開き直します。 |
gui:open <entry_id> または gui:action <entry_id> | 別のエントリ(通常は別の Open GUI)をトリガーします。 |
gui:view <view_id> | インベントリを閉じずに、別のビューに切り替えます。 |
gui:page <delta> [layout_id] | ページ付きまたはリーダーボードのレイアウトを、そのページ数だけ移動します。 |
gui:scroll <dx> <dy> [layout_id] | scrollable レイアウトをスクロールします。 |
gui:refresh | メニューを今すぐ再描画します。 |
gui:sound <sound_key> | プレイヤーにサウンドを再生します。 |
開く、戻る、閉じる
別のメニューから開いた Open GUI は、セッションの履歴に積まれるため、gui:back または executeReturn でそこに戻れます。Esc キーで閉じると、セッションが終了します。book レイアウトを開くと、現在のセッションが先に終了します。
audio を設定すると、開く、閉じる、スクロール、クリックのときにサウンドを再生します。autoRefreshTicks を設定すると、メニューが開いている間、N ティックごとに再描画します。これにより、名前やロアのプレースホルダーが、カウンターやタイマーのように更新されます。
ビュー、タブ、継承
views は、1 つの open_gui を、同じ枠組みを共有する複数の画面に変えます。layoutId が @view の frame は、アクティブなビューのレイアウトで埋められます。最初にビューの明示的な frames の対応付け、次に <view id>_<frame id> という名前のレイアウト、最後にビューの parentId に対する同じ検索の順です。タブアイテムに buttonPrefix として view:、buttonType としてビュー ID を設定すると、クリックでビューが切り替わり、アクティブな間は点灯します。ビューのタイトルでは {breadcrumb}、{view}、{root} が使えます。
baseMenuId は別の Open GUI を指し、その layoutPool、views、storagePool を、自分のものの下に統合します。同じ id を持つレイアウトは、継承されたものを置き換えます。詳細は、ビュー、タブ、継承を参照してください。
ストレージスロット
GUI Storage アーティファクトは、プレイヤーごと、またはグループごとにアイテムを保持します。再利用できる設定を、エントリの storagePool で宣言し、アイテムに storageId を付けるか、storage レイアウトを使います。ストレージスロットのアイテム名とロアでは、{stored_name}、{stored_amount}、{stored_max} が使えます。source を使うリーダーボードの行では、{score_raw} と {value_<key>} も使えます。
デフォルトのクリック割り当てです。GUI Global Settings で変更できます。
| アクション | デフォルトのクリック |
|---|---|
| カーソルのアイテムを 1 個置く | 左クリック |
| カーソルのスタック全体を置く | Shift + 左クリック |
| アイテムを 1 個取る | 右クリック |
| すべて取る | 左クリック |
| スタックを取る | Shift + 右クリック |
| インベントリから補充する | オフハンド入れ替え(F) |
| すべてを地面にドロップする | ドロップ(Q) |
dropOnClose は、メニューが本当に閉じられたとき(Esc キーまたは切断時。プレイヤーが別のメニューに移るときは除く)に、まだ保存されているものをプレイヤーの足元にドロップします。
拡張インベントリ
extendToPlayerInventory は、プレイヤー自身の 36 スロットを 4 行の追加行として表示し、10 行(y が 0〜9)のキャンバスにします。これはクライアント側だけの処理です。実際のインベントリは変更されず、メニューを閉じると元に戻り、下の行からアイテムを取り出すことはできません。guiType が CUSTOM で size が SIZE_54 である必要があります。id が _extended で終わるルートレイアウトは、それだけでこの機能を有効にします。
設定
GUI には設定ファイルがありません。任意の 2 つの manifest エントリで調整できます。
- GUI Extension Configuration は、
debugログと、デフォルトでオンのhideVanillaItemStatsオプションを有効にします。後者は、メニューのボタン上の攻撃力、耐久値、エンチャントの行を隠します。 - GUI Global Settings は、ストレージのクリック割り当てと、スキルツリーのコネクターアイテムを設定します。
プレースホルダー
| プレースホルダー | 返す値 |
|---|---|
%typewriter_gui_storage_amount_<entry_id>_<slot_index>% | GUI Storage エントリに、プレイヤーのために保存されているアイテム数。空なら 0。 |
%typewriter_gui_storage_has_<entry_id>_<slot_index>% | スロットにアイテムがあれば true、なければ false。 |
<slot_index> は、ストレージスロットの y * 9 + x です。これらのプレースホルダーは、常にプレイヤー自身のストレージを読み取り、共有されたグループストレージを読み取ることはありません。
メニュー内では、次のトークンが拡張機能によって置き換えられます。{stored_name}、{stored_amount}、{stored_max}(ストレージスロット)、{page}、{next_page}、{prev_page}、{total_pages}、{page_indicator}(ページ付きレイアウトの INDICATOR ボタン)、そして {rank}、{name}、{score}、{group}、{world}、{score_<fact_id>}(リーダーボードの行)です。
エントリ
6 件のエントリー(拡張機能のソースから生成)。
アクション1
- Open GUIOpen a GUI for the player
アーティファクト2
- GUI Leaderboard PopulationOffline population data for GUI leaderboards
- GUI StoragePersistent storage artifact for GUI storage slots
マニフェスト3
- GUI ConfigGUI Extension Configuration
- GUI LeaderboardGUI leaderboard backed by Typewriter facts
- GUI SettingsGUI Global Settings
トラブルシューティング
メニューが空で開く。 mainLayoutId が空であるか、layoutPool のどのレイアウト id とも一致していません(ID は大文字と小文字を区別します)。baseMenuId を使っている場合、空の mainLayoutId は親のものにフォールバックします。起動時チェックは、解決できないメインレイアウトをコンソールに報告します。
スロットが表示されず、コンソールに「falls outside the grid」と出る。 アイテムが、負の x または y、あるいは 8 列目を超えた位置に配置されました。多くの場合、スロット数を数える count が大きすぎることが原因です。ログには、レイアウトと、拒否された座標が示されます。
コンソールに「Slot overlap ... gap」と出る。 2 つのスロットが同じマスを共有しています。gap はステップで、1 は隣接するスロットに配置し、2 はそれぞれの間に空きスロットを 1 つ入れます。そのため、gap: 1 を「間隔 1 つ」と読んだ作成者は、コピーが隣のスロットの上に重なってしまいます。gap を変更するか、スロットの 1 つを移動してください。
管理者にはスロットが見えるが、プレイヤーには見えない。 viewPermission に、オペレーター以外が持っていない権限が指定されています。空の値は無視されますが、タイプミスは、オペレーター専用の本物の権限ノードになってしまいます。ビューの viewPermission にも同じルールが当てはまります。
ボタンは表示されるが、何も起きない。 clickPermission、次に cooldownTicks、次に criteria を確認してください。スロットに buttonType がある場合、その buttonPrefix は、提供する拡張機能と一致している必要があります。どの拡張機能にも引き取られなかったタグは、自分の interactionList は残しますが、それ以外は何も行いません。コマンドはコンソールから実行されるため、プレイヤーを送信者として必要とするコマンドは、何も通知されずに失敗します。
スクロール可能なコンテンツが動かない。 コンテンツがウィンドウより大きいこと(virtualWidth と virtualHeight)を確認してください。矢印は、その方向にスクロールできるものがある間だけ表示されます。showDefaultButtons が無効で buttons もない場合、矢印はまったくありません。既定の矢印は、そのセルにすでにコンテンツのアイテム、ボタン、装飾がある場合にも場所を譲ります。コンソールには何も記録されないため、GUI Settings の scrollArrows で位置を移動するか、スクロールされる領域の外に、direction と step を持つ独自の buttons を追加してください。
リーダーボードにオンラインのプレイヤーしか表示されない。 オフラインのプレイヤーの最後に判明した値を保持するには、GUI Leaderboard Population アーティファクトを、リーダーボードの population フィールドにリンクしてください。
拡張メニューが 10 行で表示されない。 extendToPlayerInventory には、guiType が CUSTOM で、size が SIZE_54 である必要があります。
関連する拡張機能
- Shops — GUI のレイアウトと
shop_button:マーカーを基盤にしたショップメニュー。 - Quest Codex — 同じ
open_guiの土台の上に作られた、クエストログのメニュー。