Class ChestActivityLogger
The Bukkit-thread side captures each occupied slot into immutable strings/numbers exactly once.
No ItemStack, ItemMeta, Bukkit registry lookup or component serializer crosses the
thread boundary. Diffing, grid rendering, rotation and all file I/O happen on one dedicated worker.
The queue is bounded so a stalled disk can never grow the heap without limit.
Item identity is derived in memory. The diff only ever compares the OPEN and CLOSE halves
of the same cycle, so identity needs no cross-cycle, cross-server or on-disk stability — only
"same item content produces the same string". Material plus
ItemMeta.hashCode()
gives that without cloning the stack or serializing its data components, which is what makes the
capture cheap enough to sit on a region thread. Two different stacks of the same material whose
metadata hashes collide would be totalled as one line in a single cycle; that is an acceptable
trade for a human-readable log and cannot affect stored chest contents.
Container contents are rendered, not accounted. A shulker box is still one entry in
a snapshot; what it holds is spelled out in the text of that entry only. That placement is the whole
reason the feature is affordable: the text is built inside buildMetaId(org.bukkit.inventory.ItemStack, org.bukkit.Material, org.bukkit.inventory.meta.ItemMeta, int), which runs on a
META_CACHE miss and never again for that exact shulker, whereas folding the inner items
into ChestActivityLogger.Snapshot.totals() would have to unpack every container on every capture — up to 27
items per occupied slot, on a region thread. The diff still sees a repacked shulker change, because
ItemMeta.hashCode() already covers the container component.
-
Constructor Summary
ConstructorsConstructorDescriptionChestActivityLogger(Path dataFolder, org.slf4j.Logger logger, Telemetry telemetry, boolean enabled, boolean logUnchanged, boolean containerContents, boolean chestContents, int queueCapacity, int maxFileSizeMb, int retentionDays) -
Method Summary
Modifier and TypeMethodDescriptionvoidclosed(String actorName, UUID actor, UUID owner, int chestIndex, org.bukkit.inventory.ItemStack[] contents) Captures CLOSE on the Bukkit-owned thread and offers immutable work to the bounded async queue.voidopened(String actorName, UUID actor, UUID owner, int chestIndex, org.bukkit.inventory.ItemStack[] contents) Captures OPEN on the Bukkit-owned thread.voidsetChestContents(boolean chestContents) When true, each entry also carries a HAVE line under both headers listing what the chest held at that moment.voidsetContainerContents(boolean containerContents) When true, a shulker box's line also spells out what it holds.voidsetEnabled(boolean enabled) voidsetLogUnchanged(boolean logUnchanged) When false, a visit whose CLOSE contents are identical to its OPEN contents is discarded instead of written.voidshutdown()Stops accepting new cycles, drains the bounded queue, flushes and closes the active log.
-
Constructor Details
-
ChestActivityLogger
-
-
Method Details
-
setEnabled
public void setEnabled(boolean enabled) -
setLogUnchanged
public void setLogUnchanged(boolean logUnchanged) When false, a visit whose CLOSE contents are identical to its OPEN contents is discarded instead of written. Most visits change nothing, and those entries otherwise bury the ones that matter. -
setContainerContents
public void setContainerContents(boolean containerContents) When true, a shulker box's line also spells out what it holds. Flipping this dropsMETA_CACHE, whose detail strings were rendered under the old setting — the identities in a snapshot taken before the flip still compare by value, so a visit straddling a reload is diffed correctly, it just loses the reference-equality shortcut for one cycle. -
setChestContents
public void setChestContents(boolean chestContents) When true, each entry also carries a HAVE line under both headers listing what the chest held at that moment. Purely a formatting choice: both snapshots are captured and queued either way, so this costs nothing on a Bukkit thread and everything on disk. -
opened
public void opened(String actorName, UUID actor, UUID owner, int chestIndex, org.bukkit.inventory.ItemStack[] contents) Captures OPEN on the Bukkit-owned thread. -
closed
public void closed(String actorName, UUID actor, UUID owner, int chestIndex, org.bukkit.inventory.ItemStack[] contents) Captures CLOSE on the Bukkit-owned thread and offers immutable work to the bounded async queue. Under extreme sustained disk failure the newest cycle is dropped instead of blocking a server tick or allowing an unbounded queue to exhaust heap; the worker writes an explicit SYSTEM line with the number dropped as soon as it can make progress again. -
shutdown
public void shutdown()Stops accepting new cycles, drains the bounded queue, flushes and closes the active log.
-