Skip to content

EmakiStorage

EmakiStorage is the GUI warehouse module of the Emaki series. It stores player items in logical slots where a single slot can hold a long-scale amount while preserving the original ItemStack in full (components, enchantments and PDC are all kept as-is).

The warehouse window is described by the gui/storage_gui.yml template, capacity comes from config.yml combined with permission tiers, command grants and paid purchases, and deposit/withdraw behaviour is exposed through CoreLib actions, a public API and Bukkit events.

Basic Information

ItemValue
Module version1.0.1
API Jaremaki-storage-api-1.0.1.jar
Main classemaki.jiuwu.craft.storage.EmakiStoragePlugin
Main command/emakistorage
Alias/estorage
Required dependencyEmakiCoreLib
Optional dependencyPlaceholderAPI
Descriptor baselineapi-version: "1.21.8", folia-supported: true
JavaJava 25
Main permissionsemakistorage.use (default true), emakistorage.unlock.purchase (default true), emakistorage.reload (op), emakistorage.debug (op), emakistorage.admin (op)

Feature Pages

PageContents
Commands and PermissionsSubcommands, permission nodes and examples for /emakistorage and /estorage.
ConfigurationThe unlock, behavior, search, persistence and logging keys of config.yml.
CapacityThe capacity section, the four capacity sources, the three-level stackLimit and the overflow policies.
GUI and DisplayThe gui and display sections, the gui/storage_gui.yml template structure and click semantics.
Unlock CostsThe tiers, per-slot pricing and payment ordering of unlock_costs.yml.
CoreLib ActionsThe 5 actions EmakiStorage registers into the CoreLib ActionRegistry.
API and IntegrationCalling the warehouse through emaki-storage-api and the result model.
Event APIThe StorageDepositEvent, StorageWithdrawEvent and StorageUnlockEvent Bukkit events.
PlaceholderAPI PlaceholdersThe 10 placeholders of the emakistorage extension and their resolution constraints.

Core Capabilities

  • long-scale per-slot storage: one logical slot holds one kind of item, and its ceiling comes from the three-level stackLimit configuration rather than the vanilla 64/99 stack size.
  • Original item preserved in full: deduplication uses full ItemStack#equals (components, enchantments and custom PDC all take part). No hash signature layer is introduced, so two items of the same material with different components are never merged into one entry.
  • Slot count is the single source of truth for capacity: effectiveSlots is the sum of base_slots, the permission tier, command grants and paid purchases, then clamped. Page count is derived from it (ceil(effectiveSlots / slots per page)); there is no reverse derivation from a configured page count.
  • Mixed deposit: clicking any display slot with a loaded cursor and using the fixed deposit_slot port both funnel into one transaction implementation. Capacity checks, the filter, event publication and log emission exist exactly once.
  • 1–99 occupancy rendering: with display.amount_mode: percent, the item amount field expresses occupancy as 1–99 and the exact figure goes into lore. The valid range of the max_stack_size component is exactly 1–99, so no packet trickery is involved.
  • Search and sort: search is substring matching and never compiles a regular expression; sorting is an explicit "tidy up" action that rewrites entry order.
  • Zero-loss shrinking: when lowered capacity leaves occupancy over the limit, four policies are available and none of them causes irreversible data loss. There is no drop or delete option.
  • Write-only flow log: business logic never reads the log files, and the three admin operation kinds ADMIN_SET / ADMIN_GIVE / ADMIN_CLEAR are always recorded.

Persistence Design

TopicImplementation
Entry dataSingle binary file storage.dat, file magic EMSTOR, format version 1.
Write strategyFull rewrite, not append. Every save produces an already-compact file, so there is no compactor, no garbage-ratio bookkeeping and no dangling-id repair.
Write orderingWrite a sibling .tmp first, re-read and validate the record count, then replace atomically. A failed write keeps the previous file and removes the tmp.
Per-record framingEach record is framed separately using Paper's ItemStack#serializeAsBytes() / deserializeBytes(byte[]), which carry DataVersion and run through the DataFixer on read.
Corruption isolationRecords that fail to decode are written to corrupt/<uuid>-<timestamp>.dat and the remaining records load normally.
Hand-editable dataSlot counts, stackLimit values and the sort mode live in meta.yml (text YAML). Entry payloads stay binary because YAML cannot express a full ItemStack.

File Structure

After the server runs, EmakiStorage mainly uses the following files:

text
plugins/EmakiStorage/
├─ config.yml
├─ unlock_costs.yml
├─ gui/
│  └─ storage_gui.yml
├─ lang/
│  ├─ zh_CN.yml
│  └─ en_US.yml
├─ data/
│  └─ <uuid>/
│     ├─ storage.dat
│     └─ meta.yml
├─ logs/
│  └─ <uuid>/
│     └─ <yyyy-MM-dd>.log
├─ corrupt/
└─ exports/
PathDescription
config.ymlMain configuration: GUI, capacity, unlock/overflow, display, behaviour, search, persistence, logging.
unlock_costs.ymlPaid expansion tiers. A business data file, released only when missing; version upgrades never overwrite admin content.
gui/storage_gui.ymlWarehouse window template. The function row only declares offset; slot numbers are derived from gui.storage_rows.
lang/*.ymlGUI, command, unlock and console message text.
data/<uuid>/storage.datThat player's entry data, binary, rewritten in full.
data/<uuid>/meta.ymlThat player's slot counts, stackLimit values and sort mode; hand-editable.
logs/<uuid>/<yyyy-MM-dd>.logFlow log, one directory per player and one file per day, write-only.
corrupt/Quarantine directory for records that failed to decode.
exports/Readable YAML dumps produced by /estorage export.

Quick Start

  1. Place EmakiCoreLib-*.jar and EmakiStorage-*.jar into the server's plugins/.
  2. Do not place emaki-storage-api-*.jar into plugins/; the API Jar is a compile dependency for developers only.
  3. After the first start, review plugins/EmakiStorage/config.yml and unlock_costs.yml.
  4. Open your own warehouse:
text
/estorage
  1. After editing configuration, reload config, language and GUI templates:
text
/estorage reload
  1. Grant slots to an online player and inspect the capacity breakdown:
text
/estorage slot grant Steve 10
/estorage info Steve

Usage Notes

  • Setting gui.deposit_feedback to none is not recommended. Under mixed deposit an item lands where the entry order puts it, possibly on another page; without feedback the player will believe the item vanished.
  • emakistorage.slots.<n> and emakistorage.stacklimit.<n> take the highest matching tier and do not support wildcards.
  • Lowering capacity.base_slots never consumes slots a player was granted or purchased; the three sources are persisted separately.
  • Overflow state is not persisted. It is derived from capacity versus occupancy and recomputed on login, reload, permission change and command grant.
  • Write-type admin commands require the target player to be online, see Commands and Permissions.