跳到主要内容

Interactions

Every item in a layout can react to clicks. There are three levels, from simplest to most precise:

FieldWhen it firesUse for
commandsLeft or right click (when no specific interaction matches)Simple buttons
interactionsThe exact click type it's bound toDifferent actions per click type
triggersAlongside the aboveFiring Typewriter entries (quests, dialogs, other menus)
{
"x": 4, "y": 1,
"item": { "material": "EMERALD" },
"displayName": "<green>Shop",
"commands": ["shop open %player%"],
"triggers": ["<entry id of a sequence>"],
"interactions": [
{ "type": "RIGHT", "commands": ["shop sell-all %player%"] },
{ "type": "SHIFT_LEFT", "commands": [], "closeMenu": true }
]
}

Rules:

  • A matching interactions entry takes precedence over commands for that click type.
  • %player% is replaced by the player name; commands run from console.
  • closeMenu: true and executeReturn: true on an interaction append the internal gui:close / gui:back actions.
  • Slot-level triggers fire on primary clicks and together with any matched interaction; interaction-level triggers fire only for their click type.

Click types

interactions[].type accepts:

KeysType
LEFT, RIGHTPrimary clicks
SHIFT_LEFT, SHIFT_RIGHTShift-clicks
MIDDLE, DOUBLEMiddle / double click
KEY_1KEY_9 (or 19)Hotbar number keys
KEY_Q / Q (DROP), DROP_ALLDrop keys
KEY_F / F (SWAP_OFFHAND)Swap-offhand key
SCROLL_UP, SCROLL_DOWNMouse wheel (where supported)

Internal gui: actions

Any command starting with gui: is handled by the menu engine instead of the console:

ActionEffect
gui:scroll <dx> <dy> [layoutId]Scroll a viewport by slots. gui:scroll 0 1 my_list = one row down. Without layoutId, scrolls the focused/first scrollable
gui:page \\<±n> [layoutId]Change page of a paginated layout
gui:backReopen the previous menu (session history)
gui:closeClose the menu
gui:open <entryId> / gui:action <entryId>Fire another Typewriter entry (e.g. open a sub-menu)
gui:inputOpen the slot's input dialog

Extensions can register their own prefixes (e.g. btcsky:) via MenuSessionService.registerCustomCommandHandler.

Cooldowns

Prevent click spam per slot:

{ "x": 4, "y": 1, "item": { "material": "CLOCK" }, "cooldownTicks": 40 }

Clicks during the cooldown window (here 2 s) are silently ignored.

Input dialogs

A slot can prompt the player for text input (Paper dialog API — the native 1.21+ dialog screen):

{
"x": 4, "y": 1,
"item": { "material": "NAME_TAG" },
"displayName": "<yellow>Rename island",
"input": {
"enabled": true,
"title": "<yellow>New name",
"placeholder": "Type the new island name…",
"onInputCommands": ["island rename %player% {input}"],
"onInputTriggers": []
}
}
  • When enabled, clicking opens the dialog immediately (takes precedence over commands/triggers).
  • {input} is replaced by the typed text in onInputCommands; onInputTriggers fire after confirmation.
  • The menu re-renders automatically afterwards.

Ghost slots

"isGhost": true makes a click copy the item to the cursor instead of interacting — useful for creative-style palettes.

注意

Ghost slots hand out a real ItemStack copy. Only use them with items players are allowed to obtain.

Item display options

FieldEffect
displayName, loreMiniMessage, with PlaceholderAPI placeholders resolved per player
criteriaTypewriter facts criteria — the slot only renders when they match
allowPickupLet the player take the item out (default false)
animationTween the slot to targetX/targetY over duration ms (linear, ease_in, ease_out)
buttonType / buttonPrefixTags the slot for extension-specific resolvers (e.g. dungeon buttons)

Sounds

Menu-level audio is configured on the entry (audio.onOpen, onClose, onScroll, onClick) — see gui_settings for global defaults.

Keyboard & scroll navigation

While a menu is open, scroll-wheel and movement-key events (where captured) map to viewport scrolling of the focused scrollable — the one the player last clicked in. Multiple scroll areas each keep their own position.