Skip to content

GUI and Display

This page covers what the player sees: the gui and display sections of config.yml, the structure of the gui/storage_gui.yml template, and the click semantics.

For capacity and slot counts see Capacity; for the remaining config.yml keys see Configuration.

gui

yaml
gui:
  storage_rows: 5
  deposit_feedback: actionbar
  require_empty_cursor_for_withdraw: false
FieldTypeDefaultDescription
storage_rowsint5Display row count, valid 1–5. The function row always owns the last row, so the real window height is storage_rows + 1.
deposit_feedbackenumactionbarFeedback channel after a successful deposit: actionbar / message / none.
require_empty_cursor_for_withdrawbooleanfalseWhether withdrawal requires an empty cursor. See the note below.

Setting deposit_feedback to none is not recommended. Under mixed deposit an item lands where the entry order puts it and may end up on another page; with feedback disabled the player will believe the item vanished.

require_empty_cursor_for_withdraw is a misclick guard. When set to true, clicking a display slot while holding an item on the cursor no longer deposits: the click becomes a no-op and reports gui.deposit.cursor_guard. This closes the "meant to withdraw but still had a leftover cursor" mis-click window, at the cost of losing the "click an entry while holding an item to deposit" shortcut. When set to false (the default) that shortcut deposit is kept. Either way the fixed deposit port and deposit_all remain available for depositing.

storage_rows Conversion Table

The slots values in the template file are only placeholders. Real slot numbers are derived from gui.storage_rows at load time:

text
storageRows  = clamp(gui.storage_rows, 1, 5)
totalRows    = storageRows + 1
functionBase = storageRows * 9
display area = 0 .. functionBase - 1
function row = functionBase + offset
storage_rowstotalRowsSlots per pageDisplay slotsFunction slots (offset 0–8)
1290–89–17
23180–1718–26
34270–2627–35
45360–3536–44
56450–4445–53

Clamping rules: a value >= 6 is clamped to 5 with a warning; a value <= 0 is clamped to 1 with a warning. totalRows peaks at 6, which already sits inside CoreLib's 1–6 range.

storage_gui.yml Template Structure

yaml
id: storage_gui
gui_type: CHEST
title: "<gradient:#4DA6FF:#FFD166>绘卷仓库</gradient>"

slots:
  storage_slot:
    type: storage_slot
    slots: [0]
    item:
      source: "gray_stained_glass_pane"

  page_prev:
    type: page_prev
    offset: 0
    slots: [0]
    item:
      source: "arrow"
Top-level keyDescription
idTemplate id. Must be storage_gui; the implementation looks the template up by this id.
gui_typeContainer type, CHEST. The row count is not declared here, it is derived from gui.storage_rows.
titleWindow title, MiniMessage supported.
slotsThe slot entry table, where each key names one entry.

The 9 slot types available under slots:

Slot typePurpose
storage_slotThe display-area prototype. Required: without it the display area cannot be built and the whole template fails to resolve.
deposit_slotThe fixed deposit port. Clicking it with a loaded cursor deposits.
page_prevPrevious page.
page_infoCurrent page information, display only.
page_nextNext page.
searchOpens the search prompt; right-click while searching clears the filter.
sortCycles the sort; shift-click cycles it in reverse.
deposit_allBulk deposit across the 36 main inventory slots.
unlockEntry point for paid expansion.

An entry may declare type explicitly; when omitted it is derived from the lower-cased entry key, so naming an entry after its type is enough.

How offset Relates to slots

Function-row entries only declare offset (valid 0–8). The slots key in the template exists only to satisfy the shared template parser and is overwritten by the conversion at load time, so it must never be read as a real position.

  • When offset is missing, not a number, or outside 0–8, the entry is rejected with a warning.
  • When two entries claim the same offset, the later one is rejected with a warning.
  • When every function entry is rejected, a warning is logged and the paging and deposit buttons become unavailable.

The display area's storage_slot is a prototype: at load time it expands across the whole display area, 0 .. functionBase - 1. The item configured on it only supplies the placeholder appearance of a locked slot and does not affect how unlocked slots render.

Changing gui.storage_rows moves the function row automatically; no slot number needs to be edited by hand.

GUI Click Semantics

LocationActionEffect
Display slotLoaded cursor + left-clickDeposits the whole cursor
Display slotLoaded cursor + right-clickDeposits 1 unit
Display slotEmpty cursor + left / right / shift-left / shift-rightWithdraws per withdraw_amounts
Display slotEmpty cursor + middle-clickOpens the chat prompt for a custom amount (subject to withdraw_prompt_enabled)
deposit_slotLoaded cursorDeposits the whole cursor
deposit_slotEmpty cursorReports that the port is empty
deposit_allClickBulk-deposits across the 36 main inventory slots
sortClick / shift-clickCycles the sort / cycles it in reverse
searchClickOpens the search prompt; right-click while searching clears the filter
page_prev / page_nextClickPages; an empty page cannot be paged into
Player inventory itemShift-clickRedirected into the deposit port logic

Rejected click kinds: double-click, number keys, offhand swap, the drop key and Ctrl + drop. They respectively aggregate across slots, bypass cursor semantics or discard the item outright, so none of them can be given a safe meaning; such clicks report gui.click.unsupported.

While a search filter is active, deposits into the display area are refused (paging follows the filtered result set, so a display slot no longer identifies a real slot number), but the fixed deposit port keeps working.

Withdrawal amounts, the default sort and the deposit filter live in the behavior section, documented in Configuration.

display

yaml
display:
  amount_mode: percent
  percent_scale: 99
  compact_units: ["K", "M", "B", "T", "P", "E"]
  compact_decimals: 2
  show_exact_amount: true
  lore_position: bottom
FieldTypeDefaultDescription
amount_modeenumpercentHow the slot item's amount is expressed: percent shows occupancy as 1–99, one is always 1.
percent_scaleint99Scale ceiling for percent mode; the implementation clamps it into 1–99.
compact_unitslist[K, M, B, T, P, E]Compact amount units. Leave empty to use exact numbers.
compact_decimalsint2Decimal places kept in compact format; trailing zeroes are trimmed.
show_exact_amountbooleantrueWhether to also show the grouped exact amount in lore.
lore_positionenumbottomWhere generated lines go relative to the template lore: top / bottom.

1–99 Scale Rules

The valid range of the max_stack_size component is exactly 1–99, so the implementation never uses 100 or above and no packet trickery is involved. The scale boundaries are deliberate:

CaseDisplayed amount
amount_mode: oneAlways 1
stackLimit unlimited (Long.MAX_VALUE) or <= 0Degrades to 1; a percentage is meaningless for an unlimited ceiling
Stored amount <= 01
Stored amount >= stackLimit (genuinely full)percent_scale (default 99)
Partially filledclamp(round(amount / stackLimit * scale), 1, scale - 1), so at most 98 by default

Without these clamps a nearly-empty slot would render as 0 (invisible) and a nearly-full one would be indistinguishable from full.

The percentage text in lore is computed independently on the real 0–100 range and does not inherit the 1–99 clamping.

Compact Units

compact_units maps in order onto the six thresholds 10³, 10⁶, 10⁹, 10¹², 10¹⁵ and 10¹⁸. Long.MAX_VALUE is roughly 9.22E, so the E unit covers the entire long range. Values below 1000, or an empty unit list, produce the plain number.

  • Configuration: the remaining config.yml sections, including behavior and search.
  • Capacity: slots per page, total pages and the three-level stackLimit.
  • Unlock Costs: the tiers and batch options behind the unlock button.
  • Commands and Permissions: /estorage reload also reloads the GUI template.