| name | item-data-model |
| description | Use when working on item state, the PDC codec, the ItemView content-hash cache, the stable-key to dense-id map, component stores, the WornState resolver, lore/name rendering, or legacy item migration. |
Item data model
se-item is the one item-state layer. An item carries identity + counters in
PDC under versioned NamespacedKeys; behavior lives in the compiled Snapshot,
never on the item. Lore/name are rendered from state, never parsed back (§4.2):
LoreComposer composes every section in one ordered pass and LoreRenderer is the
Bukkit shell wired by a named-field LoreRenderer.Config record (ADR-0040).
Apply-gesture services mutate PDC/marker state then recompose through the ADR-0040 seam
and report a GestureOutcome (ADR-0041) — never setLore on gear, never raw sendMessage.
Likeness {TOKEN} substitution goes through platform.text.Tokens (underscore-canonical,
hyphen alias); the enchant-book {DESCRIPTION} line-expansion is Tokens.expandLines, while
the crystal block-splice stays bespoke in CrystalService (ADR-0034).
When to use / not
Use for the PDC codec, ItemView caching, stable-key↔dense-id, stores, WornState,
and rendering (legacy NBT item migration is DESCOPED — see the core-rules table).
NOT for ability compilation (effect-engine)
or damage/suppression/soul/slot resolution (feature-interaction-rules). See also
config-and-migration, performance-hot-paths, cross-version-item-api (alias
maps), and folia-scheduling (the cross-region victim read).
Core rules
| Rule | Why | § |
|---|
| PDC = state only (identity + counters), never DSL/behavior | item names which defs by key; programs live in the Snapshot | 4.2 |
| Stable string keys in PDC, never a dense index | dense ids reorder every reload; an old item must still resolve | 4.2, 5.3 |
| Crystals are a list of keys; souls keyed by PDC UUID | fixes a Cosmic Enchants-style last-of-type collapse and slot-reorg loss | 4.2 |
| Cache on the full raw blob string + generation, NOT ItemMeta identity | meta is copy-on-write → misses constantly and can alias (stale view) | 5.2 |
| Key on the whole blob (never a truncated hash), in a per-generation map | a truncated-hash collision could serve a stale view; a fresh per-gen map bounds growth | 5.2 |
| Two records: combat vs economy/identity | identity items (scroll/dust/crate) never decode on the combat hot path | 5.1 |
WornState.activeSets is a SET (BitSet) | multi-set + omni completion is unrepresentable with one activeSetId | 5.5 |
WornState immutable, pre-flattened, swapped by ref | the safe cross-region victim read on Folia — read only this, never the live victim ItemStack | 5.5, 3.6 |
Resolve WornState on equip change, never per hit | event-driven (PlayerArmorChangeEvent + held-item change); debounced per tick | 5.5 |
Migrate legacy NBT lazily in place — DESCOPED | migration is config-only, not item-NBT; there is no lazy in-place item rewrite. See ADR-0005 (updated) | — |
byTrigger / combatAttack / combatDefense are the pre-flattened union over
all active sources (enchants + set + weapon + crystals + heroic + hotbar pets, ADR-0052), ordered — the
hit walks one array and never knows there were five sources (§5.5).
The shape
record WornState(
int gen, // Snapshot generation it was built against (§5.3)
BitSet activeSets,
int[] activeCrystalAbilityIds,
HeroicStat heroic,
int[][] byTrigger,
int[] combatAttack,
int[] combatDefense) {}
ItemView v = cache.of(stack);
ItemViewCache.of reads the item's raw combat blob and uses that full string
as the key into the current generation's ConcurrentHashMap, decoding once on a
miss. Growth is bounded by the distinct gear configs seen within a generation;
reload swaps a fresh per-generation map so every prior view drops atomically —
no stale reads, no cross-reload growth. PDC stays stable-key;
the dense Ability.id is a per-snapshot accelerator resolved through the persistent
stable-key→id map (§5.3), reassigned freely each reload. Inspect with /se item dump.
Component stores (§5.4) hold mutable runtime state — never scattered in
effect objects. Each of the seven (CooldownStore, WornStateStore, ...) is
concurrent, UUID-keyed, TTL-evicting, and cleared on quit + onDisable.