Skip to main content

๐Ÿ“‚ Stores

Stores are the core of Coppermind โ€” they represent individual data entries that can be loaded, saved, and managed.


๐Ÿ“ฅ Loading a Storeโ€‹

Use loadStore to load data for a specific key:

local store = Coppermind.loadStore(PlayerSchema, tostring(player.UserId), {
sessionLocked = true,
autoSave = 60,
})

Parametersโ€‹

ParameterTypeDescription
schemaSchemaThe registered schema to use
keystringUnique identifier for this data entry
configStoreConfig?Optional configuration

Configuration Optionsโ€‹

{
sessionLocked = true, -- ๐Ÿ”’ Lock data to this server
autoSave = 60, -- โฑ๏ธ Auto-save interval in seconds
}

๐Ÿ“Š Store Propertiesโ€‹

local store = Coppermind.loadStore(schema, key, config)

print(store.key) -- "123456789" (identifier)
print(store.data) -- { coins = 100, ... } (nil while loading)
print(store.state) -- "READY" (current state)
print(store.sessionId) -- "abc-123-def" (if session locked)
print(store.version) -- 2 (migration version)
print(store.lastSaved) -- 1703712000 (timestamp)

๐Ÿšฆ Store Statesโ€‹

StateIconDescription
LOADING๐Ÿ”„Fetching data from DataStore
READYโœ…Data loaded and available for use
SAVING๐Ÿ’พCurrently saving to DataStore
UNLOADING๐Ÿ“คSaving and releasing the store
UNLOADEDโฌœStore has been released
ERRORโŒFailed to load or save
SESSION_LOCKED๐Ÿ”’Another server owns this data

๐Ÿ“ก Store Eventsโ€‹

Each store has its own events:

-- โœ… Fires when data is loaded and ready
store.onReady:Connect(function(store)
print("Store ready:", store.key)
end)

-- ๐Ÿ’พ Fires after each successful save
store.onSaved:Connect(function(store)
print("Store saved:", store.key)
end)

-- โŒ Fires on any error
store.onError:Connect(function(store, errorMessage)
warn("Store error:", store.key, errorMessage)
end)

-- ๐Ÿ’ฑ Fires when a transaction is completed
store.onTransaction:Connect(function(store, transactionId)
print("Transaction completed:", transactionId)
end)

๐Ÿ” Checking Store Statusโ€‹

Is Loadedโ€‹

if Coppermind.isLoaded(PlayerSchema, key) then
print("Store is loaded")
end

Get Store Referenceโ€‹

local store = Coppermind.getStore(PlayerSchema, key)

if store and store.state == "READY" then
print("Store is ready")
end

๐Ÿ’พ Saving a Storeโ€‹

local success = Coppermind.saveStore(PlayerSchema, key)

if success then
print("Save queued")
end

๐Ÿ“ค Unloading a Storeโ€‹

Always Unload

Always unload stores when no longer needed to prevent data loss!

local success = Coppermind.unloadStore(PlayerSchema, key)

Unloading performs these steps:

  1. โน๏ธ Cancels any pending auto-save
  2. ๐Ÿ’พ Saves current data
  3. ๐Ÿ”“ Releases the session lock
  4. ๐Ÿ—‘๏ธ Removes the store from memory

Typical Usageโ€‹

game.Players.PlayerRemoving:Connect(function(player)
local key = tostring(player.UserId)

if Coppermind.isLoaded(PlayerSchema, key) then
Coppermind.unloadStore(PlayerSchema, key)
end
end)

๐Ÿ”’ Session Lockingโ€‹

Session locking prevents multiple servers from modifying the same data:

local store = Coppermind.loadStore(schema, key, {
sessionLocked = true,
})

How It Worksโ€‹

graph LR
A[Server A requests load] --> B{Lock available?}
B -->|Yes| C[Acquire lock]
B -->|No| D[SESSION_LOCKED state]
C --> E[Load data]
E --> F[Use data...]
F --> G[Unload store]
G --> H[Release lock]
  1. When loading, Coppermind checks if another server owns the lock
  2. If locked, the store enters SESSION_LOCKED state
  3. If available, this server acquires the lock
  4. The lock is released when the store is unloaded

โฐ Lock Expirationโ€‹

Automatic Expiration

Locks automatically expire after 30 minutes. This handles cases where a server crashes without properly unloading.

Handling Lock Conflictsโ€‹

store.onError:Connect(function(store, errorMessage)
if store.state == "SESSION_LOCKED" then
warn("Data is locked by another server")
-- Optionally kick the player or retry later
end
end)

๐Ÿ“ Complete Exampleโ€‹

local Coppermind = require(path.to.Coppermind)

local PlayerSchema = Coppermind.registerSchema({
name = "PlayerData",
dataTemplate = {
coins = 0,
playtime = 0,
},
migrations = {},
})

local function onPlayerAdded(player)
local key = tostring(player.UserId)

local store = Coppermind.loadStore(PlayerSchema, key, {
sessionLocked = true,
autoSave = 60,
})

store.onReady:Connect(function()
print(`{player.Name}'s data loaded!`)
end)

store.onError:Connect(function(_, errorMessage)
warn(`Failed to load {player.Name}'s data: {errorMessage}`)
player:Kick("Failed to load your data. Please rejoin.")
end)
end

local function onPlayerRemoving(player)
local key = tostring(player.UserId)

if Coppermind.isLoaded(PlayerSchema, key) then
Coppermind.unloadStore(PlayerSchema, key)
end
end

game.Players.PlayerAdded:Connect(onPlayerAdded)
game.Players.PlayerRemoving:Connect(onPlayerRemoving)

-- Handle existing players (for late script execution)
for _, player in game.Players:GetPlayers() do
task.spawn(onPlayerAdded, player)
end