Skip to content

GUI System ​

You get GUI templates, open requests, session management, slot control, and click handling from CoreLib: declare your own GUI configuration and CoreLib takes care of opening menus, tracking the player's state, and intercepting stray clicks, so your module never has to implement inventory events from scratch

Used by ​

ModuleUsage
EmakiForgeForge GUI, recipe book
EmakiStrengthenStrengthening GUI, material slots, protection slots
EmakiGemInlay, extraction, socket opening, and upgrade GUI
EmakiSkillsSkill panel and trigger-selection GUI
EmakiCookingSteamer, oven, juicer, and fermentation-barrel GUI
EmakiAttributeAttribute point allocation GUI
EmakiItemItem repair GUI
EmakiLevelLevel panel and leaderboard GUI
EmakiStoragePaged warehouse GUI

gui.backend in plugins/EmakiCoreLib/config.yml decides how every Emaki menu is presented:

ValueDescription
bukkitDefault. Opens a real server-side container and needs no extra plugin
packetCoreLib's built-in packet-based virtual menu. It reuses the same window when the row count changes, so the cursor is not reset. Requires PacketEvents; falls back to bukkit when it is missing
autoUses packet when PacketEvents is installed, otherwise bukkit

The default stays bukkit, so upgrading CoreLib does not change existing menu behaviour. An unknown value logs one warning and falls back to bukkit

FieldTypeRequiredDefaultValuesDescription
gui.backendstringNo"bukkit"bukkit / packet / autoMenu rendering backend; the values are those in the table above. An unknown value falls back to bukkit and logs a warning
gui.click_interval_msintegerNo100≥ 0 (0 means unlimited)Minimum interval between two menu clicks by the same player, in milliseconds; later clicks inside the interval are not handed to the menu business logic. Values below 0 are treated as 0

Shipped defaults:

yaml
gui:
  backend: "bukkit"
  click_interval_ms: 100

Example (enable the packet menu and relax click throttling to 150 ms):

yaml
gui:
  backend: "packet"
  click_interval_ms: 150

Template fields ​

FieldTypeRequiredDescription
idstringYesTemplate id used by the module. A blank id makes the whole template parse as invalid
titlestring/objectNoInventory title. MiniMessage strings and TextConfig objects are supported. Defaults to the literal GUI
gui_typestringNoContainer type, given as a Bukkit InventoryType name. Defaults to CHEST; an invalid value falls back to CHEST silently. When the type does not support custom rows, rows is forced to 0
rowsintegerNoInventory rows. Defaults to 3 and is clamped into 1–6, i.e. 9–54 slots
slotsmapNoSlot definitions keyed by slot name. Omitting it yields an empty map rather than an error

Slot fields ​

FieldTypeDescription
keystringSlot key used by business code
slotslist<number>Inventory indexes covered by this slot definition
typestringBusiness type label, such as input, output, button, or decoration
itemobjectShared item definition containing source, amount, and components. Without source, it can act as a pure patch for a runtime item
soundsmapClick sounds keyed by click type

Unified item structure ​

New configs and bundled defaults only write the nested canonical structure:

yaml
item:
  source: minecraft-anvil
  amount: 1
  components:
    custom_name: '<green>Confirm</green>'
    lore:
      - '<gray>Click to execute</gray>'
    item_model: emaki:confirm
    enchantment_glint_override: true
    $unset:
      - repairable
    $reset:
      - attribute_modifiers
  • source accepts every ItemSource shorthand registered in CoreLib; availability depends on the corresponding resolver/plugin
  • A normal component value means SET; $unset removes a component and $reset restores the material prototype default
  • Component IDs must be valid namespaced keys. IDs without a namespace default to minecraft:, while explicit namespaces are preserved; the same rule applies to $unset / $reset entries. Unknown IDs and invalid values for supported components are configuration errors
  • Known components introduced after the current server version are skipped with a warning without linking newer typed classes
  • Third-party sources are cloned first so source identity, PDC, and unknown components survive; only patches that Paper can safely transfer are applied
  • Legacy item: <source> plus top-level components, display_name, and lore are still readable compatibility inputs. When both forms exist, nested item wins
  • Real player-provided targets, materials, and business outputs remain controlled by session state and are not overwritten by template display items

Automatic migration of legacy GUI item fields has been retired ​

Shared gui/*.{yml,yaml} files are no longer migrated automatically before loading: CoreLib has removed the item.migration.configureditem package and the runtime LegacyConfiguredItemConverter, and GuiTemplateLoader no longer attaches a migration entry point. Item definitions in GUI templates must use the canonical structure directly: item.source for the source (for example minecraft-diamond_sword), item.amount for the count, and item.components for names, lore, model data, and components

Legacy fields (material, item_source / item_sources, scalar item, display_name, item_name, lore, custom_model_data, enchantments, item_flags, hidden_components, unbreakable, and related fields) are no longer converted or filled in, and no migration-backups/configured-item-format/ backup is produced any more. Rewrite them by hand and back up the full configuration directory before upgrading

Click types ​

Click typesounds keyDescription
CLICKclickGeneric click, used as the fallback when no specific type matches
LEFTCLICKleft_clickLeft click
RIGHTCLICKright_clickRight click
SHIFT_LEFTCLICKshift_left_clickShift + left click
SHIFT_RIGHTCLICKshift_right_clickShift + right click
MIDDLECLICKmiddle_clickMiddle click
DOUBLECLICKdouble_clickDouble click
NUMBER_KEYnumber_keyNumber-key hotbar swap
SWAP_OFFHANDswap_offhandOffhand swap key (F by default)
DROPdropDrop key (Q by default)
CONTROL_DROPcontrol_dropCtrl + drop key

A sounds entry must use the lowercase key from the sounds key column (parsing is case-insensitive); the enum name (such as LEFTCLICK) does not match, is treated as an unknown key, and is ignored with a warning. Sound lookup has three levels: an exact match on the current click type first; then one retry through the legacy mapping (SHIFT_LEFTCLICK and DOUBLECLICK fall back to LEFTCLICK, SHIFT_RIGHTCLICK falls back to RIGHTCLICK); only then does it fall back to CLICK. An unregistered key produces an issue such as Unknown gui sound key '...' ignored.

Full GUI configuration examples ​

Strengthening GUI example ​

yaml
id: strengthen_gui
title: '<dark_gray>Gear Strengthening'
rows: 6
slots:
  background:
    slots: [0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,50,51,52,53]
    type: decoration
    item:
      source: minecraft-black_stained_glass_pane
      components:
        minecraft:custom_name: ' '
        minecraft:tooltip_display:
          hide_tooltip: true
  target:
    slots: [13]
    type: input
    item:
      source: minecraft-air
      components:
        minecraft:custom_name: '<gray>Insert target gear'
        minecraft:lore:
          - '<dark_gray>Place the gear you want to strengthen here'
  confirm:
    slots: [49]
    type: button
    item:
      source: minecraft-anvil
      components:
        minecraft:custom_name: '<green>Start strengthening'
        minecraft:lore:
          - '<gray>Insert gear and materials, then click'
          - ''
          - '<yellow>Left-click to start strengthening'
        minecraft:enchantments:
          minecraft:unbreaking: 1
        minecraft:tooltip_display:
          hidden_components:
            - minecraft:enchantments
    sounds:
      left_click:
        sound: minecraft:block.anvil.use
        volume: 0.8
        pitch: 1.0

Forge GUI example ​

yaml
id: forge_gui
title: '<dark_gray>Forge'
rows: 6
slots:
  background:
    slots: [0,1,2,3,4,5,6,7,8,9,17,18,26,27,35,36,44,45,46,47,48,49,50,51,52,53]
    type: decoration
    item:
      source: minecraft-gray_stained_glass_pane
      components:
        minecraft:custom_name: ' '
  blueprint_slot:
    slots: [10]
    type: input
    item:
      components:
        minecraft:custom_name: '<aqua>Blueprint slot'
        minecraft:lore:
          - '<gray>Insert a forge blueprint'
  material_slots:
    slots: [11,12,13,14,15,16,19,20,21,22,23,24,25]
    type: input
    item:
      components:
        minecraft:custom_name: '<yellow>Material slot'
        minecraft:lore:
          - '<gray>Insert forge materials'
  target_slot:
    slots: [28]
    type: input
    item:
      components:
        minecraft:custom_name: '<gold>Target gear'
        minecraft:lore:
          - '<gray>Insert the gear to forge'
  result_preview:
    slots: [34]
    type: output
    item:
      components:
        minecraft:custom_name: '<green>Result preview'
  confirm:
    slots: [43]
    type: button
    item:
      source: minecraft-smithing_table
      components:
        minecraft:custom_name: '<green>Confirm forging'
    sounds:
      left_click:
        sound: minecraft:block.anvil.use
        volume: 1.0
        pitch: 1.2

GUI sessions ​

A GUI session records the state of the menu a player currently has open. CoreLib manages sessions itself; business modules handle interaction logic through the GuiSessionHandler interface

A session tracks:

  • Which recipe or flow the player is working on
  • Which slots are input slots (items may be placed) and which forbid taking items out
  • Which business flow a button click should invoke
  • Whether input items must be returned when the menu closes
  • Temporary state data for the current menu

Sessions exist so players cannot duplicate items or bypass a flow through rapid clicking, shift-clicking, dragging, or an abnormal close

Slot index reference ​

Slot indexes for a six-row inventory:

text
Row 1:  0  1  2  3  4  5  6  7  8
Row 2:  9 10 11 12 13 14 15 16 17
Row 3: 18 19 20 21 22 23 24 25 26
Row 4: 27 28 29 30 31 32 33 34 35
Row 5: 36 37 38 39 40 41 42 43 44
Row 6: 45 46 47 48 49 50 51 52 53

Frequently used positions:

  • Centre of a six-row menu: 22 (middle of row 3) or 31 (middle of row 4)
  • Bottom centre: 49
  • Corners: 0, 8, 45, 53

MiniMessage and colours ​

Use MiniMessage consistently for GUI text:

yaml
item:
  source: minecraft-smithing_table
  components:
    minecraft:custom_name: '<gold>Legendary Forge'
    minecraft:lore:
      - '<gray>Insert the blueprint, materials, and target gear.'
      - '<yellow>Click to start forging.'
      - ''
      - '<dark_gray>Cost: <white>500 coins'

Common MiniMessage tags:

TagEffect
<red>Red text
<green>Green text
<gold>Gold text
<gray>Grey text
<dark_gray>Dark grey text
<yellow>Yellow text
<aqua>Aqua text
<bold>Bold
<italic>Italic
<strikethrough>Strikethrough
<gradient:gold:yellow>Gradient

Where a module still accepts legacy colour codes (&a, §b), migrate to MiniMessage over time to keep one style

Editing advice ​

  1. Change display text first
  2. Then move decorative slots
  3. Adjust functional slots only after confirming the layout
  4. Test shift-click, drag, double-click, close handling, and full-inventory cases after each GUI change