Class Database
Manages the full lifecycle of Bag objects in memory and on disk/database:
loading on startup, dirty-tracking via changedBags, periodic auto-saving,
and shutdown persistence. Supports four storage backends selected at runtime via
save-type in config.yml:
DatabaseType.FILES– one YML file per bagDatabaseType.SQLITE– single SQLite database fileDatabaseType.MYSQL– remote MySQL database (batched saves)DatabaseType.MYSQLPLUS– remote MySQL with real-time per-bag saves (auto-save timer is disabled)
Bag instances are stored in a UUID-keyed in-memory map and are considered the
single source of truth for runtime state. Mutating a bag through the public API
(e.g. updateBag(java.lang.String, java.util.List<org.bukkit.inventory.ItemStack>, valorless.havenbags.Database.UpdateSource...),
invalid reference
#addTrustedchangedBags so it is included in the next auto-save cycle.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classLightweight view of a bag item paired with its current content list.static enumDetermines how a bag retrieval or update should be treated at the call site. -
Field Summary
FieldsModifier and TypeFieldDescriptionBags that have been mutated since the last save cycle.static longAuto-save interval in server ticks, derived fromauto-save.intervalinconfig.yml(seconds × 20). -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionstatic BooleanReturnstrueif a bag with the given UUID exists in the in-memory map.static org.bukkit.entity.PlayerReturns thePlayercurrently viewing the bag, ornullif it is not open.static voidchangeDatabase(DatabaseType type) Switches the active storage backend totypeat runtime.static BooleanClears the contents of every bag currently loaded in memory.static BooleanclearBagContent(String uuid) Clears the contents of the bag with the given UUID.static BooleanclearBagContentPlayer(String playeruuid) Clears the contents of all bags owned by the specified player.static booleanReturnstrueif a bag with the given UUID is present in the in-memory map.static BagcreateBag(String uuid, String owner, List<org.bukkit.inventory.ItemStack> content, org.bukkit.entity.Player creator, org.bukkit.inventory.ItemStack bag) Creates a new bag, stores it in memory, and persists it immediately for MYSQLPLUS.static BagRegisters an already-constructedBaginto memory and persists it immediately for MYSQLPLUS.static BooleanPermanently deletes a bag from both the storage backend and the in-memory map.static List<com.google.gson.JsonObject> Deserialises a JSON array string into a list ofJsonObjectelements.static voidDiscards the current in-memory bag map and reloads all bags from the storage backend vialoadData().static BaggetBag(String uuid, Database.UpdateSource... source) Retrieves a loadedBagby UUID.Returns a list of all player UUID strings that own at least one bag.Returns a list of all bag UUID strings owned by the specified player.getBagsData(String playerUUID) Returns a list of allBaginstances owned by the specified player.static DatabaseTypeReturns the currently activeDatabaseType.static MySQLgetMysql()Returns the activeMySQLconnection wrapper, ornullif the current backend is not MySQL-based.Returns all bags that are currently marked as open (i.e.static voidinit()Initialises the database layer on plugin enable.static booleanChecks whether the bag with the given UUID is currently open.static booleanisBagOpen(org.bukkit.inventory.ItemStack bagItem) Checks whether the bag represented by the givenItemStackis currently open, using the UUID stored in its PDC.static booleanisReady()ReturnstrueonceloadData()has completed successfully and the in-memory bag map is available for use.static voidloadData()Loads all bags from the active storage backend into the in-memory map.static voidmarkBagClosed(String uuid) Marks the bag as closed and clears the viewer and GUI references.static voidmarkBagOpen(String uuid, org.bukkit.inventory.ItemStack bagItem, org.bukkit.entity.Player player) Marks the bag as open and records the viewing player.static voidmarkBagOpen(String uuid, org.bukkit.inventory.ItemStack bagItem, org.bukkit.entity.Player player, BagGUI gui) Marks the bag as open, records the viewing player, and attaches the associatedBagGUIinstance.static voidreload()Performs a lightweight config reload (interval only).static voidRemoves the bag with the given UUID from the in-memory map and thechangedBagsdirty set.static voidReset the tooltip-styles of ALL bags to the default one specified in the config.
This is used when the tooltip-style is changed in the config, to update all bags to the new style.static voidsaveData(boolean shutdown, boolean... conversion) Persists all dirty bags to the active storage backend.protected static voidsetDatabaseType(DatabaseType databaseType) Sets the activeDatabaseType.protected static voidSets the activeMySQLconnection wrapper.static voidshutdown()Closes all active database connections cleanly.static voidupdateBag(String uuid, List<org.bukkit.inventory.ItemStack> content, Database.UpdateSource... source) Updates a bag's content by UUID and marks it dirty for the next save cycle.static voidupdateBag(org.bukkit.inventory.ItemStack bagItem, List<org.bukkit.inventory.ItemStack> content, Database.UpdateSource... source) Updates a bag's content and visual metadata (texture, model data, item model) from the given bagItemStack, then marks it dirty for the next save cycle.
-
Field Details
-
changedBags
Bags that have been mutated since the last save cycle.Populated by
Bag.setChanged(boolean)(called withtrue) and by the various Database mutator methods. Drained and cleared on eachsaveData(boolean, boolean...)call. MarkedInternal— external code should not manipulate this map directly; use the provided API methods instead. -
interval
public static long intervalAuto-save interval in server ticks, derived fromauto-save.intervalinconfig.yml(seconds × 20).
-
-
Constructor Details
-
Database
public Database()
-
-
Method Details
-
isReady
public static boolean isReady()ReturnstrueonceloadData()has completed successfully and the in-memory bag map is available for use.- Returns:
trueif the database layer is ready
-
init
Initialises the database layer on plugin enable.Steps performed:
- Determines and sets the active
DatabaseTypefrom config. - Opens the appropriate connection (MySQL / SQLite) if required.
- Calls
loadData()to populate the in-memory bag map. - Schedules the repeating auto-save task (skipped for MYSQLPLUS).
save-typeis configured. - Determines and sets the active
-
shutdown
Closes all active database connections cleanly. Should be called fromonDisableaftersaveData(boolean, boolean...)to ensure connections are released before the plugin unloads. -
changeDatabase
Switches the active storage backend totypeat runtime.Disconnects/closes the current backend, cancels the existing auto-save task, then starts a new auto-save timer for the new backend. For
DatabaseType.MYSQLandDatabaseType.MYSQLPLUSthe timer is immediately cancelled since those backends use real-time or per-call saving.- Parameters:
type- the newDatabaseTypeto switch to
-
reload
public static void reload()Performs a lightweight config reload (interval only).Note: bag data is not reloaded. Use
forceReload()to fully reload bag data from the storage backend, at the cost of losing any unsaved in-memory changes. -
forceReload
public static void forceReload()Discards the current in-memory bag map and reloads all bags from the storage backend vialoadData().Warning: any unsaved changes will be lost. Call
saveData(boolean, boolean...)first if persistence is required. -
contains
Returnstrueif a bag with the given UUID is present in the in-memory map.- Parameters:
uuid- the bag UUID string to look up- Returns:
trueif the bag is loaded
-
bagExists
Returnstrueif a bag with the given UUID exists in the in-memory map.Unlike
contains(String), this method validates the UUID format and returnsfalse(rather than throwing) for"null"or malformed strings.- Parameters:
uuid- the bag UUID string to check- Returns:
trueif the bag exists,falsefor invalid/missing UUIDs
-
getBag
Retrieves a loadedBagby UUID.If
sourceisDatabase.UpdateSource.PLAYER, the bag is also marked as open (Bag.setOpen(boolean)) to reflect that a player is actively using it. Returnsnulland logs a debug message if the bag is not found.- Parameters:
uuid- the bag UUID stringsource- optional — passDatabase.UpdateSource.PLAYERto mark the bag openbagItem- theItemStackrepresenting the bag (used for context; may benull)- Returns:
- the
Baginstance, ornullif not found
-
updateBag
public static void updateBag(@NotNull String uuid, @NotNull List<org.bukkit.inventory.ItemStack> content, @Nullable Database.UpdateSource... source) Updates a bag's content by UUID and marks it dirty for the next save cycle.If
sourceisDatabase.UpdateSource.PLAYER, the bag is also marked as closed after the content update.- Parameters:
uuid- the bag UUID stringcontent- the new content list to storesource- optional — passDatabase.UpdateSource.PLAYERto also mark the bag closed
-
updateBag
public static void updateBag(@NotNull org.bukkit.inventory.ItemStack bagItem, @NotNull List<org.bukkit.inventory.ItemStack> content, Database.UpdateSource... source) Updates a bag's content and visual metadata (texture, model data, item model) from the given bagItemStack, then marks it dirty for the next save cycle.This overload reads the UUID from the item's PDC. If
capacity-based-texturesis enabled in config, the bag's texture is also updated to reflect fill level. IfsourceisDatabase.UpdateSource.PLAYER, the bag is marked as closed.- Parameters:
bagItem- the bagItemStackto read UUID and visual data fromcontent- the new content list to storesource- optional — passDatabase.UpdateSource.PLAYERto also mark the bag closed
-
createBag
public static Bag createBag(@NotNull String uuid, @NotNull String owner, @NotNull List<org.bukkit.inventory.ItemStack> content, org.bukkit.entity.Player creator, org.bukkit.inventory.ItemStack bag) Creates a new bag, stores it in memory, and persists it immediately for MYSQLPLUS. Fires aBagCreateEvent.Visual data (texture, model data, item model) and metadata (autopickup, blacklist, tooltip-style, etc.) are extracted from
bag's PDC and applied to the newBaginstance.- Parameters:
uuid- UUID string to assign to the new bagowner- UUID string of the owning playercontent- initial content listcreator- thePlayercreating the bag, ornullbag- the bagItemStackto read visual/PDC data from- Returns:
- the newly created
Baginstance
-
createBag
Registers an already-constructedBaginto memory and persists it immediately for MYSQLPLUS. Fires aBagCreateEvent.- Parameters:
dat- the pre-builtBagto register; must not benull- Returns:
- the same
Baginstance - Throws:
IllegalArgumentException- ifdatisnull
-
loadData
Loads all bags from the active storage backend into the in-memory map.Clears the ready flag for the duration of the load, then sets it back to
trueon completion. Existing in-memory data is replaced. Called automatically byinit()andforceReload(). -
saveData
public static void saveData(boolean shutdown, boolean... conversion) Persists all dirty bags to the active storage backend.Bags are collected for saving from two sources:
- Full dump — all bags in memory are included when
shutdownistrueor when a non-emptyconversionarray is supplied (e.g. during a database conversion command). - Dirty-only — on a normal auto-save tick (
saveData(false)), only bags registered inchangedBagsare saved. The map is drained as part of this process.
SQLite and MYSQL saves run asynchronously during normal auto-save to avoid blocking the main thread; synchronous writes are used on shutdown and conversion to guarantee completion before the plugin unloads.
- Parameters:
shutdown-trueto perform a full synchronous save of all bags (used on plugin disable)conversion- optional flag — passtrueto include all bags in a synchronous save for database conversion purposes
- Full dump — all bags in memory are included when
-
removeBag
Removes the bag with the given UUID from the in-memory map and thechangedBagsdirty set. Does not delete data from the storage backend — usedeleteBag(String, Player...)for that.- Parameters:
uuid- the bag UUID string to remove
-
deleteBag
Permanently deletes a bag from both the storage backend and the in-memory map. Fires aBagDeleteEvent.- Parameters:
uuid- the bag UUID string to deleteplayer- optional — thePlayerresponsible for the deletion (attached to the fired event)- Returns:
trueif deletion succeeded,falseif the bag was not found or a storage error occurred
-
getBags
Returns a list of all bag UUID strings owned by the specified player.- Parameters:
playerUUID- the player's UUID string- Returns:
- unmodifiable list of bag UUID strings; empty if the player owns none
-
getBagsData
Returns a list of allBaginstances owned by the specified player.- Parameters:
playerUUID- the player's UUID string- Returns:
- unmodifiable list of
Bagobjects; empty if the player owns none
-
getBagOwners
Returns a list of all player UUID strings that own at least one bag.For the FILES backend this is derived from the bag directory structure; for SQL backends it is queried directly from the database.
- Returns:
- list of owner UUID strings; empty if none found or on error
-
isBagOpen
Checks whether the bag with the given UUID is currently open. Removes the bag item from the world (amount = 0) if the bag is not found.- Parameters:
uuid- the bag UUID stringbagItem- the bagItemStack(cleared if bag not found); may benull- Returns:
trueif the bag is open
-
isBagOpen
public static boolean isBagOpen(org.bukkit.inventory.ItemStack bagItem) Checks whether the bag represented by the givenItemStackis currently open, using the UUID stored in its PDC.- Parameters:
bagItem- the bagItemStack- Returns:
trueif the bag is open;falseif not found or the item is not a used bag
-
bagOpenBy
public static org.bukkit.entity.Player bagOpenBy(@NotNull String uuid, org.bukkit.inventory.ItemStack bagItem) Returns thePlayercurrently viewing the bag, ornullif it is not open.- Parameters:
uuid- the bag UUID stringbagItem- the bagItemStack(cleared if bag not found); may benull- Returns:
- the viewing
Player, ornull
-
markBagOpen
public static void markBagOpen(@NotNull String uuid, org.bukkit.inventory.ItemStack bagItem, org.bukkit.entity.Player player) Marks the bag as open and records the viewing player. For MYSQLPLUS, the updated state is persisted immediately.- Parameters:
uuid- the bag UUID stringbagItem- the bagItemStack(cleared if bag not found); may benullplayer- thePlayeropening the bag
-
markBagOpen
public static void markBagOpen(@NotNull String uuid, org.bukkit.inventory.ItemStack bagItem, org.bukkit.entity.Player player, BagGUI gui) Marks the bag as open, records the viewing player, and attaches the associatedBagGUIinstance. For MYSQLPLUS, the updated state is persisted immediately.- Parameters:
uuid- the bag UUID stringbagItem- the bagItemStack(cleared if bag not found); may benullplayer- thePlayeropening the baggui- theBagGUIinstance managing the bag's inventory UI
-
markBagClosed
Marks the bag as closed and clears the viewer and GUI references. For MYSQLPLUS, the updated state is persisted immediately.- Parameters:
uuid- the bag UUID string
-
getOpenBags
Returns all bags that are currently marked as open (i.e. being viewed by a player).- Returns:
- unmodifiable list of open
Baginstances
-
deserializeItemStackList
Deserialises a JSON array string into a list ofJsonObjectelements.nullJSON elements are preserved asnullentries in the list to maintain slot alignment.- Parameters:
json- JSON array string produced by the bag content serialiser- Returns:
- list of
JsonObjectentries, withnullfor empty slots
-
clearAllBagContents
Clears the contents of every bag currently loaded in memory.Each bag's slots are replaced with
nullvalues. This is a destructive operation — use with caution.- Returns:
trueif all bags were cleared successfully,falseif an exception occurred
-
clearBagContentPlayer
Clears the contents of all bags owned by the specified player.- Parameters:
playeruuid- the owning player's UUID string- Returns:
trueif all bags were cleared successfully,falseif an exception occurred
-
clearBagContent
Clears the contents of the bag with the given UUID.If the bag has an open
BagGUI, it is force-closed first. Slots are replaced withnullvalues to preserve the bag's size.- Parameters:
uuid- the bag UUID string- Returns:
trueif the bag was found and cleared,falseotherwise
-
getDatabaseType
Returns the currently activeDatabaseType.- Returns:
- the active database type
-
setDatabaseType
@DoNotCall("Meant to be called by HavenBags only.") @Internal protected static void setDatabaseType(DatabaseType databaseType) Sets the activeDatabaseType. Internal use only — callchangeDatabase(DatabaseType)for a safe runtime switch.- Parameters:
databaseType- the new database type
-
getMysql
Returns the activeMySQLconnection wrapper, ornullif the current backend is not MySQL-based.- Returns:
- the
MySQLinstance, ornull
-
setMysql
@DoNotCall("Meant to be called by HavenBags only.") @Internal protected static void setMysql(MySQL mysql) Sets the activeMySQLconnection wrapper. Internal use only.- Parameters:
mysql- theMySQLinstance to use
-
resetTooltipStyles
@DoNotCall("This method is used internally to reset the tooltip-styles of all bags to the value in config.yml. It should not be called outside of HavenBags.") public static void resetTooltipStyles()Reset the tooltip-styles of ALL bags to the default one specified in the config.
This is used when the tooltip-style is changed in the config, to update all bags to the new style.If the server is a version that does not support TooltipStyle, then all are set null.
-