Class PlayerSettingsCache

java.lang.Object
com.enhancedechest.service.PlayerSettingsCache

public final class PlayerSettingsCache extends Object
Write-through read cache of per-player settings, keyed by UUID. Populated on join (preloadSettings(java.util.UUID, java.lang.String)), read by the dialog-open paths, updated in place on change, and evicted on quit (evictSettings(java.util.UUID)) — so it is bounded by the online-player count. Writes go straight to the DB (write-through), so the cache holds no dirty state and needs no shutdown flush. See the leak-free invariant documented on preloadSettings(java.util.UUID, java.lang.String).

preloadSettings(java.util.UUID, java.lang.String) is also where a player's name is recorded, because the settings row it already loads carries the last known username — so the check is free and the write only happens on a first-ever join or a rename. That is what makes PlayerNameIndex complete without ever reading the playerdata folder: every player who joins is in the players table from then on, and admin tab-completion needs no other source. ChestOpener's open prelude does the same check against its own already-loaded row, covering players who were online before this plugin loaded.

  • Constructor Details

  • Method Details

    • preloadSettings

      public void preloadSettings(UUID owner, String currentName)
      Loads a player's settings into the cache on join. This is the cache's only inserter, which keeps the leak-free invariant simple: every entry added here is removed by evictSettings(java.util.UUID) on quit. The post-load online re-check covers the join-then-immediate-quit race — if the player already left while the load was in flight (so evictSettings ran before this put), the entry is dropped right after it is added, so nothing is ever orphaned.

      currentName is the joining player's name, compared against the username on the row that was just loaded. Recording it here rather than only on a chest open is what keeps PlayerNameIndex — and therefore admin tab-completion — complete from the database alone, with no playerdata scan anywhere in the plugin.

    • indexName

      public void indexName(UUID owner, String username)
      Records a name in the in-memory PlayerNameIndex only, with no DB write — called on join, where the name is already in hand, so an admin can tab-complete the player immediately instead of waiting on preloadSettings(java.util.UUID, java.lang.String)'s round trip (or losing the name entirely if the startup index load failed). now as the last-seen time is exactly right: they just joined.
    • evictSettings

      public void evictSettings(UUID owner)
      Evicts a player's cached settings on quit. Paired with preloadSettings(java.util.UUID, java.lang.String) so the cache stays bounded by online players.
    • loadSettingsAsync

      public CompletableFuture<PlayerSettings> loadSettingsAsync(UUID owner)
      Returns the player's settings, served from the cache when present (the common case for an online player). A miss — preload still in flight, or the player was already online before the plugin loaded — falls back to a one-off DB read that is deliberately not cached, so preloadSettings(java.util.UUID, java.lang.String) remains the sole inserter and the leak-free invariant holds.
    • setEditModeAsync

      public CompletableFuture<Void> setEditModeAsync(UUID owner, boolean editMode)
      Persists the player's edit-mode preference with a single targeted upsert (no preceding read), leaving every other setting untouched. Write-through: the cached copy is updated in place first (if present) so the next dialog open reflects the change without a DB read, then the DB is written. Uses computeIfPresent so it never inserts — preserving the leak-free invariant.
    • setAppliedDefaultSizeAsync

      public CompletableFuture<Void> setAppliedDefaultSizeAsync(UUID owner, int size)
      Persists the base-chest size baseline the default-size reconcile just applied, with a single targeted upsert (no preceding read), leaving edit-mode untouched. Write-through: the cached copy is updated in place first (if present) so the next reconcile sees the new baseline without a DB read (and so its fast path holds), then the DB is written. Uses computeIfPresent so it never inserts — preserving the leak-free invariant.
    • markSeenAsync

      public CompletableFuture<Void> markSeenAsync(UUID owner, String username)
      Records that the player is here now: their in-game name (offline /ee view resolution) and last_online, which decides how long they keep showing up in admin name suggestions. Called on join and quit, and by ChestOpener's open prelude when the name it loaded is stale.

      Unconditional, unlike the old name-only write, because last_online changes every time by definition — and it costs no extra statement: CachedStorage only mutates the resident row and marks it dirty, so this rides the next batched flush together with the player's chests.

      Write-through: the cached copy is updated in place first (if present), then the storage layer. Uses computeIfPresent so it never inserts — preserving the leak-free invariant.

    • clear

      public void clear()
      Drops every cached entry on shutdown. The write-through cache holds no dirty state (every change was persisted immediately), so there is nothing to flush — just release the references.