Class ChestSpillService

java.lang.Object
com.enhancedechest.service.ChestSpillService

public final class ChestSpillService extends Object
Item-moving chest operations: shrink-spill, delete (spill or force), bulk delete, and the reverse move that pulls a temp chest back into a newly granted chest (reclaimTempInto(java.util.UUID, int)). Each first force-closes every viewer's GUI via ChestSessionManager.forceCloseAll(java.util.UUID, int) (flushing the live session), then runs the load-decode-split exclusively per (owner, index) via ChestSessionManager.runExclusive(java.util.UUID, int, java.util.function.Supplier<T>) so no concurrent open sees a half-applied state — keeping the swaps dupe-safe even with multiple concurrent viewers. Drives /ee resize, /ee delete, and the expiry sweeper.
  • Constructor Details

  • Method Details

    • setTempConfig

      public void setTempConfig(long tempExpiryMillis, boolean autoReclaim)
      Re-applies the runtime-tunable temp-chest settings after a /ee reload. Only affects temp chests stamped (and reclaims started) after this call, so it is dupe-safe to set on the main thread while async storage work is pending.
    • resizeOrSpill

      public CompletableFuture<Void> resizeOrSpill(UUID owner, int index, int newSize)
      Resizes a chest, spilling any cut-off items into a temp chest if it is shrunk below its used slots. Force-closes every viewer's GUI first (flushing the live session), then runs the load-decode-split exclusively per (owner, index) so no concurrent open sees a half-applied state. A grow, or a shrink that loses no items, is a plain resize.
    • removeChest

      public CompletableFuture<Void> removeChest(UUID owner, int index, boolean force)
      Removes a chest. With force the row is hard-deleted (items lost immediately); otherwise any items are spilled into a temp chest first. Force-closes every viewer's GUI, then performs the delete exclusively per (owner, index) so the swap is dupe-safe. Used by /ee delete and by the expiry sweeper (NORMAL → spill, TEMP → force).
    • reclaimTempInto

      public CompletableFuture<Boolean> reclaimTempInto(UUID owner, int targetIndex)
      The inverse of a spill: moves one temp chest's items whole into the freshly created, still-empty chest at targetIndex, then deletes the temp chest. Called right after a new chest is granted (a permission reconcile, /ee add), so a player who lost a chest and got its items parked in a temp chest gets them back automatically when a chest of at least that size comes back. A no-op (completing false) when the feature is off, when the target is gone or is itself a temp chest, or when no temp chest fits.

      One temp chest, one target, no repacking. Only a temp chest whose slot count is <= the target's is eligible, and its stored bytes are copied verbatim, so every item lands on the exact slot it already occupied. Items are never split across several chests and an existing layout is never reshuffled — a partially fitting temp chest is left alone rather than merged in. When several temp chests fit, the one expiring soonest is taken first: it is the one closest to being lost.

      A move that actually happened is announced to the owner through TempReclaimNotifier (temp-enderchest.reclaim-notify), so items do not silently change chest number under them.

      Dupe-safety follows the same model as the spills above, widened to the two chests involved: both GUIs are force-closed (flushing any live session), then the swap runs behind the pending saves of both keys via ChestSessionManager.runExclusiveAcross(java.util.List<com.enhancedechest.service.ChestSessionManager.ChestRef>, java.util.function.Supplier<T>), and the storage call re-checks every precondition under the cache lock.

    • clearChest

      public CompletableFuture<Void> clearChest(UUID owner, int index)
      Empties a chest's contents (admin "clear chest" action), keeping the chest itself (size, name, icon, kind). Force-closes every viewer's GUI first so the live session can't re-save the old contents over the wipe, then clears exclusively per (owner, index) so the swap is dupe-safe.
    • sortChest

      public CompletableFuture<Void> sortChest(UUID owner, int index)
      Sorts a chest's contents in place: identical items are merged into full stacks and everything is reordered by item type (then by descending stack size), packed from the first slot. Force-closes every viewer's GUI first (so the live session can't re-save the old order over the sort), then runs the load-sort-save exclusively per (owner, index) so the swap is dupe-safe. A no-op for a missing or empty chest. The chest's size, name, icon and kind are untouched — only the item layout changes.
    • removeNewestChests

      public CompletableFuture<Integer> removeNewestChests(UUID owner, int count, boolean force)
      Bulk-removes the count highest-numbered NORMAL chests a player owns, spilling (or force-discarding) each, and completes with the number actually removed. The player's first chest — the lowest-indexed NORMAL chest — is always protected, so a player can never be left with no chests; deleting fewer than count when that is all that is eligible is not an error. Temp chests are ignored (they are transient and expire on their own).

      Targets are snapshotted up front, then deleted sequentially: a spilling delete creates a fresh temp chest at a higher index, but those are not in the target list so they are never re-touched. Each per-index delete still serializes behind its own pending saves and force-closes open GUIs, so the bulk op is dupe-safe.