Astral Realms Documentation Help

Menu Input Slots

A menu normally owns every one of its slots: the click listener cancels anything it did not explicitly allow, so a player can never take an icon out or drop an item in. Input slots are the documented exception — a group of slots left to vanilla, where the player may deposit, take, swap and drag their own items. The blueprint only decides what may go in (requirements) and reacts to what changed (add-actions/remove-actions).

This is the building block for deposit boxes, repair/upgrade stations, trade-in counters, and any menu that has to receive an item rather than merely display one.

Declaring input slots

Add an input-slots: map to the menu blueprint. Each key is the input's id; the slots it lists become player-owned for the lifetime of the menu.

id: "deposit" title: "<bold>Deposit" size: 27 input-slots: deposit: slots: [11, 12, 13, 14, 15] requirements: - "[compare] %item_material% == DIAMOND" add-actions: - "[message] <green>Deposited %item_amount%x into slot %parameter_slot%." remove-actions: - "[message] <red>Took %item_amount%x back." return-on-close: true

Field

Type

Description

slot

int (placeholder)

A single input slot. Mutually exclusive with slots; one of the two is required.

slots

List<int> (placeholder)

Several input slots. Takes precedence over slot when both are set.

item

ItemStackWrapper

Optional. An item the slots start out holding — see Starting item.

requirements

List<Requirement>

Optional. Evaluated before an item is allowed in. Absent or empty means the input takes anything.

add-actions

List<Action>

Optional. Run after items were added to the slot.

remove-actions

List<Action>

Optional. Run after items were taken out of the slot.

return-on-close

boolean

Whether items left in the slots are handed back when the menu goes away. Default true — see return-on-close.

Slots are resolved from a placeholder wrapper, so slots: "%parameters_slots%" works the same way it does on a menu item.

Placeholders inside requirements and actions

Both the requirement list and the action lists run against the menu's own placeholder container, plus two extras scoped to the change being reported:

Placeholder

Resolves to

%item%

The ItemStack being inserted, taken or moved. Drills into the usual sub-keys — %item_material%, %item_name%, %item_amount%, %item_lore%, %item_durability%, %item_damage%, %item_custom-model-data%, %item_enchantment_<key>_level%, … See item sub-keys.

%parameter_slot%

The raw slot index the change concerns.

Note that %item% in an add-actions/remove-actions list is the difference, not the slot's whole content: dropping 16 more of a stack the slot already holds reports an addition of 16.

How changes are detected

Nothing about an input slot is driven per click type. An accepted click is simply left to vanilla and the result is read afterwards — one diff covers placing, taking, swapping, dropping and dragging:

  1. The click (or drag) is vetted and, if allowed, applied by vanilla as usual.

  2. A single reconcile pass is queued for the next tick — vanilla only applies the move after the event returns, so the outcome cannot be read any earlier.

  3. Each input slot's current content is compared against the baseline the previous pass recorded, and the change is reported.

Reporting rules:

Change

Reported as

Slot was empty, now holds an item

add-actions with the new stack

Slot held an item, now empty

remove-actions with the old stack

Same item, larger amount

add-actions with the difference only

Same item, smaller amount

remove-actions with the difference only

Item swapped for a different one

remove-actions with the old stack, then add-actions with the new one

"Same item" is a strict isSimilar comparison, so a genuinely different item is never mistaken for an amount change.

Baselines are updated before the actions run, and an action that throws is logged without costing the remaining slots their diff.

What is refused

Clicks the menu turns down are cancelled and the window is resent, so the client's optimistic prediction is corrected:

  • Double click and any COLLECT_TO_CURSOR action — they reach past the clicked slot and would sweep the menu's own icons onto the cursor.

  • Middle click and creative click — cloning.

  • Any click bringing in an item the input's requirements reject. The incoming item is the cursor, the hotbar item for a number-key swap, or the off-hand item for a swap-offhand; a shift click out of an input slot brings nothing in and is never vetted this way.

  • A drag that touches any menu slot which is not an input slot, or where any input slot it reaches refuses the dragged item. A drag confined to the player's own inventory is left alone.

A requirement that throws refuses the item — the check fails closed, because letting the exception escape would leave the move to be applied by vanilla with nothing having vetted it.

Shift-clicking from the player inventory

A vanilla shift click would scatter the stack over every free slot of the menu, the gaps between icons included. The menu cancels it and performs the move itself, during the click, into the input slots only: matching stacks are topped up first, then empty input slots are filled, and whatever does not fit stays in the player's inventory. Slots whose requirements refuse the stack are skipped.

This does not apply when use-player-inventory is on — the bottom inventory is then a packet overlay and the stack the player sees is not the one they would be moving.

Starting item

item seeds the input's slots with an item when the menu is computed. It is a starting point, not a deposit: the add actions do not run for it, but taking it back out reports as a removal like any other.

The typical use is a repair or upgrade station that opens on an item the player already owns — seed it with copy-from so the slot shows the item the menu was opened for:

input-slots: target: slot: 13 item: copy-from: "%parameters_item%" return-on-close: false

An input that merely mirrors something the player already holds wants return-on-close: false, otherwise closing the menu hands them a second copy. Seeding the same item into several slots with return-on-close: true logs a warning for the same reason: the player walks away with one copy per slot.

return-on-close

By default whatever the player left in the input slots is handed back when the menu goes away — those items are theirs and the inventory is about to be discarded. Items that do not fit are dropped at the player's feet, and a player who logged out in the meantime gets them dropped in the world.

Each returned item is reported through remove-actions, because giving it back undoes the deposit. Set return-on-close: false when the add actions already took ownership of what is dropped in — a deposit that credits the player would otherwise pay out and refund the item.

The close diff is settled synchronously rather than waiting for the queued reconcile: a click applied in the same tick the menu closes would otherwise never be reported.

Interaction with the rest of the menu

  • Nothing renders into an input slot. Items and layouts skip them entirely; a slot the player owns is never overwritten, cleared or refreshed by a render pass, and no MenuItem becomes clickable there.

  • A layout never wastes entries on them. Input slots are resolved before layouts, so an item carrying a layout taint that lands on an input slot does not contribute a slot to that layout.

  • use-player-inventory and input slots do not mix. The player-inventory region is a packet overlay whose slots only exist client-side and can never hold a real item; declaring both logs a warning and the input stays confined to the menu inventory.

Warnings and validation

These are logged and skipped rather than failing the menu:

Condition

Behaviour

Slot index below 0 or beyond the menu size

The slot is ignored.

Two inputs declaring the same slot

The first one to claim it keeps it.

use-player-inventory together with input-slots

Warning; the player inventory cannot take input.

One item seeded into several slots with return-on-close: true

Warning; the player gets one copy back per slot.

A failure to resolve the slots placeholder, or to build the starting item, aborts the compute and the menu does not open.

Last modified: 03 September 2026