Compatibility
Minecraft: Java Edition
Platforms
Tags
Creators
Details
CustomGuiReworked — Skeleton GUI Framework for Paper
Visual in-game editor · 5 storage types · ItemsAdder & CraftEngine blocks · High-performance storage · Library-ready API
CustomGuiReworked is a modern, skeleton-based GUI framework for Paper 26.2+ (Java 25). Create fully persistent custom inventories in-game, bind them to custom blocks, and use them as a library from your own plugins. No flicker, no data loss, no dupe.
Paper: 26.2.build.123+ | Java: 25 | License: MIT
✨ Why CustomGuiReworked?
- 🎮 True in-game editor —
/gui create <name>→ size, skeleton, design, title, storage, block bindings, live preview. Everything saves instantly. - 🧩 Skeleton system — every slot has a type that defines behavior, not heuristics.
- 💾 5 storage engines — block, personal, global, team, temporary. From personal vaults to shared banks.
- ⚡ Zero-lag storage — in-memory cache, async coalesced writes (1000ms), per-slot diff, atomic
tmp + ATOMIC_MOVE, autosave + guaranteed save on close/quit/shutdown. - 🧱 Custom blocks — right-click ItemsAdder or CraftEngine block to open GUI. Breaking drops contents and closes viewers. No hard dependencies.
- 📦 Smart item codec —
n1:NBTAPI (full fidelity) /b2:PaperserializeAsBytes()+ Base64 (fallback) /b1:legacy read-only. Tagged payloads survive installing/removing NBTAPI. - 🔌 Library-ready API —
GuiServicevia Bukkit Services +GuiBuilder+ events. Use ascompileOnly, never shade. - 📜 Skript & Denizen —
on cgui open/close/click/drag, conditions, expressions,<cgui.*>tags.
🎮 Visual Editor
/gui create <name> # create + open editor
/gui edit <name> # edit existing
/gui open <name> # open as player
/gui # management menu with pagination & chat search
Editor screens:
- Size — 9 / 18 / 27 / 36 / 45 / 54, existing slots survive resize
- Skeleton — click cycles
Design → Container → Craft → Result → Fuel, shift-click forces Design - Design — drag items from your inventory, shift-click, right-click clears, double-click blocked to prevent theft
- Title — chat prompt,
/cancelto abort - Storage — choose type
- Custom blocks — bind/unbind
my_blockorcraftengine:my_block - Preview / Delete — instant preview as player sees it
No window flicker — all updates are in-place.
💾 Data Storage
| Type | Scope | Where it lives | Use case |
|---|---|---|---|
BLOCK |
one block | <world>/CustomGuiReworked/blocks/<x/16>_<z/16>.json |
chests, furnaces, ATMs |
PERSONAL |
per-player | data/players/<player>_<table>.json |
personal vaults, settings |
GLOBAL |
server-wide | data/globals/<table>.json |
global bank, auction |
TEAM |
per scoreboard team | data/teams/<team>_<table>.json |
clan storages |
TEMPORARY |
session | nowhere, items returned on close | forms, temporary menus |
How it saves:
- Write is diff-based — only touched slots are re-serialized (1 NBT call, not 54)
- Burst of clicks → one disk write (coalesce
storage.coalesce-ms: 1000) saveNow()on close / quit / WorldUnload / shutdown — never lost- Failed write stays dirty and retries after 5s
- Region files for blocks are cached, flushed on
WorldUnloadEvent
🎯 Slot Skeleton
| Type | Player can | Persisted | Purpose |
|---|---|---|---|
DESIGN |
only click (button) | ❌ | decoration, PDC-marked to block double-click theft |
CONTAINER |
put / take | ✅ | storage |
CRAFT |
put / take | ✅ | recipe ingredient (semantic) |
RESULT |
only take | ❌ | result / shop product — cannot be inserted by any method (cursor, number keys, offhand swap, drag) |
FUEL |
put / take | ✅ | fuel (semantic) |
Shift-click is vanilla-like but safe: from GUI → player inventory is native; from player → GUI fills only CONTAINER/CRAFT/FUEL, skips DESIGN/RESULT.
Double-click collects similar items normally, but DESIGN items are isSimilar == false due to hidden PDC marker and maxStackSize == amount.
🔧 Commands
| Command | Permission |
|---|---|
/gui — management menu |
cgui.command |
/gui create <name> |
cgui.create |
/gui edit <name> |
cgui.edit |
/gui open <name> [player] |
cgui.open |
/gui delete <name> |
cgui.delete |
/gui list |
— |
/gui command add <slot> <gui> [delay] <command...> |
cgui.command |
/gui command get <slot> <gui> [index] |
cgui.command |
/gui command delete <slot> <gui> <index> |
cgui.command |
/gui reload |
cgui.reload |
Placeholders in slot commands: %player%, %slot%
Example in tables/shop.yml:
commands:
- slot: 10
command: "give %player% diamond 1"
delay: 5
🧱 Custom Blocks — ItemsAdder & CraftEngine
- Bind via editor or API:
myblocks:shop,craftengine:atm - Right-click block → opens GUI with
BLOCKstorage (world:x,y,z) - Break block → open GUIs are synced to region cache first (anti-dupe: item on cursor won't drop twice) → items drop → region data deleted
- Lookup O(1), case-insensitive, suffix fallback after
: - Hooks loaded reflectively — no hard dependency, no crash if plugin missing
CustomGuiAPI.registerBlockGui("itemsadder:ruby_ore", "shop");
CustomGuiAPI.registerBlockGui("craftengine:atm", "bank");
⚡ Performance & Safety
- <50ms GUI open (async preload, stale request race fixed)
- ~2-5KB per GUI in memory
- 1000+ concurrent viewers (each has own inventory instance, diff-based saves don't overwrite each other's slots)
- No dupe: DESIGN protected by PDC + maxStackSize + rescue on next tick, RESULT blocked from all directions, block break syncs viewers before drop, all menus closed on shutdown before final flush
- No corruption: all files written via unique
.tmp-<uuid>+ATOMIC_MOVE, orphaned tmps swept on startup - No lag: single
CguiStorageIOthread, main thread never touches disk
Config plugins/CustomGuiReworked/config.yml:
storage:
autosave-ticks: 600
max-cached-views: 10000
coalesce-ms: 1000
commands:
execute-as-op: false
integration:
skript: true
denizen: true
🔌 Developer API
Full guide: GitHub API.md and MECHANICS.md
Gradle (Kotlin)
repositories {
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://jitpack.io")
}
dependencies {
compileOnly("io.papermc.paper:paper-api:26.2.build.123-stable")
compileOnly("com.github.amper24:CustomGuiReworked:2.3.0")
}
Gradle (Groovy)
repositories {
maven { url = 'https://repo.papermc.io/repository/maven-public/' }
maven { url = 'https://jitpack.io' }
}
dependencies {
compileOnly 'io.papermc.paper:paper-api:26.2.build.123-stable'
compileOnly 'com.github.amper24:CustomGuiReworked:2.3.0'
}
Maven
<repositories>
<repository><id>papermc</id><url>https://repo.papermc.io/repository/maven-public/</url></repository>
<repository><id>jitpack.io</id><url>https://jitpack.io</url></repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.amper24</groupId>
<artifactId>CustomGuiReworked</artifactId>
<version>2.3.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
plugin.yml:
softdepend: [CustomGuiReworked]
Usage
// Fluent builder
Gui gui = GuiBuilder.named("shop")
.title("§6Shop")
.size(27)
.storage(StorageType.PERSONAL)
.slot(10, SlotType.CONTAINER)
.slots(List.of(11,12,13), SlotType.CONTAINER)
.slot(22, SlotType.RESULT)
.design(0, new ItemStack(Material.BLACK_STAINED_GLASS_PANE))
.command(22, "give %player% diamond 1", 5)
.blockId("myblocks:shop")
.build();
CustomGuiAPI.registerGui(gui, true); // custom/shop.yml, survives restart
// Open
CustomGuiAPI.openGui(player, "shop");
CustomGuiAPI.openGui(player, "shop", StorageType.TEMPORARY); // override
CustomGuiAPI.openGui(player, "shop", blockLocation); // BLOCK
// Storage without GUI
List<ItemStack> items = CustomGuiAPI.readStorage(StorageType.GLOBAL, "", "shop.yml");
CustomGuiAPI.writeStorage(StorageType.GLOBAL, "", "shop.yml", items);
// Events
@EventHandler
public void onOpen(GuiOpenEvent e) {
if (!e.getPlayer().hasPermission("shop.use")) e.setCancelled(true);
}
@EventHandler
public void onClick(GuiSlotClickEvent e) {
if (e.getSlotType() == SlotType.RESULT && e.getClick().isRightClick()) {
e.setInteractionCancelled(true); // cancel both commands and vanilla click
}
}
API surface: GuiService, CustomGuiAPI, Gui, GuiBuilder, SlotType, StorageType, SlotCommand, GuiOpenEvent, GuiCloseEvent, GuiSlotClickEvent, GuiDragEvent, block API, storage API.
📜 Skript & Denizen
Skript:
on cgui open:
broadcast "%event-player% opened %event-string%"
on cgui click:
if event-string is "shop":
if event-number is 22:
cancel event
open cgui "shop" to player with storage temporary
close cgui of player
Denizen:
on cgui click:
- if <context.gui> == shop:
- if <context.slot> == 22:
- determine cancelled
on cgui drag:
- announce "drag over <context.slots>"
Tags: <cgui.guis>, <cgui.exists[shop]>, <cgui.size[shop]>, <cgui.title[shop]>, <cgui.storage[shop]>, <cgui.open_of[<player>]>
📦 Requirements
| Plugin | Version | Required |
|---|---|---|
| Paper | 26.2+ (Java 25) | ✅ |
| NBTAPI | 2.16+ | ❌ recommended for full NBT |
| ItemsAdder | 4.x | ❌ for custom blocks |
| CraftEngine | 26.x | ❌ for custom blocks |
| Skript | 2.14+ | ❌ |
| Denizen | 1.3.x | ❌ |
📥 Installation
- Download
CustomGuiReworked-x.y.z.jarfrom Modrinth / GitHub Releases - (Recommended) Install NBTAPI
- Put into
plugins/and start server - Config auto-creates:
plugins/CustomGuiReworked/config.ymllang/en.yml,ru.ymltables/(editor GUIs),custom/(API GUIs),data/(players/teams/globals)<world>/CustomGuiReworked/blocks/(block regions)
🔗 Links
- GitHub: https://github.com/amper24/CustomGuiReworked
- Full API Guide: https://github.com/amper24/CustomGuiReworked/blob/main/API.md
- Mechanics Deep Dive: https://github.com/amper24/CustomGuiReworked/blob/main/MECHANICS.md
- Issues: https://github.com/amper24/CustomGuiReworked/issues
- JitPack: https://jitpack.io/#amper24/CustomGuiReworked
📄 License
MIT — see LICENSE file.


