Roblox Datastores

sentinelcore/roblox-skills/roblox-datastores

作者 sentinelcoref2b1910a7fb898ed35cf2f856e2a2e48e38276bf無授權條款收錄於 2026年10月9日更新於 2026年10月9日

Use when implementing player data persistence in Roblox, saving/loading player stats or inventory, building leaderboards with ordered datastores, handling data migration between versions, diagnosing data loss issues, or adding auto-save and shutdown-safe data handling with DataStoreService.

AI 產生的概覽

Roblox DataStoreService 參考指南:在伺服器端儲存、載入、移轉並保護玩家資料。

功能
提供 Roblox DataStoreService 的參考,涵蓋 GetAsync、SetAsync、UpdateAsync、RemoveAsync 以及有序資料儲存。它說明使用 pcall 載入與儲存玩家資料、重試邏輯、PlayerRemoving 自動儲存、BindToClose 關閉伺服器時刷寫、排行榜,以及帶版本的資料移轉等模式。也列出常見錯誤,例如缺少 pcall、未限流的儲存,以及結構變更後重複使用資料儲存名稱。
適用情境
適用於在 Roblox 中實作玩家資料持續保存、儲存或載入玩家屬性與物品欄、建立有序資料儲存排行榜、在不同結構版本間移轉資料,或診斷資料遺失問題。也適合加入自動儲存與關閉伺服器時的安全處理。
執行需求
此技能未附帶指令碼或資源,僅為說明文件。它假定執行環境為 Roblox 伺服器端,可使用 DataStoreService 與 Players 服務,並已為該體驗啟用 API 存取。

roblox-datastores

Reference for Roblox DataStoreService — saving, loading, and managing player data on the server.

Quick Reference

MethodSignatureNotes
GetDataStoreDSS:GetDataStore(name, scope?)Returns a GlobalDataStore
GetOrderedDataStoreDSS:GetOrderedDataStore(name, scope?)For leaderboards
GetAsyncstore:GetAsync(key)Returns value or nil
SetAsyncstore:SetAsync(key, value)No return value needed
UpdateAsyncstore:UpdateAsync(key, fn)Atomic read-modify-write
RemoveAsyncstore:RemoveAsync(key)Deletes key, returns old value
GetSortedAsyncorderedStore:GetSortedAsync(asc, pageSize)Returns DataStorePages

Basic Setup

lua
-- Server Script (ServerScriptService)local DataStoreService = game:GetService("DataStoreService")local Players = game:GetService("Players")
local playerStore = DataStoreService:GetDataStore("PlayerData_v1")
local DEFAULT_DATA = {    coins = 0,    level = 1,    xp = 0,}

Loading Data (GetAsync + pcall)

Always wrap datastore calls in pcall. They can fail due to network issues or rate limits.

lua
local function loadData(player)    local key = "player_" .. player.UserId    local success, data = pcall(function()        return playerStore:GetAsync(key)    end)
    if success then        local result = {}        for k, v in pairs(DEFAULT_DATA) do result[k] = v end        if data then            for k, v in pairs(data) do result[k] = v end        end        return result    else        warn("Failed to load data for", player.Name, ":", data)        return nil -- signal failure; do not give default data silently    endend

Saving Data (SetAsync vs UpdateAsync)

Use SetAsync for simple overwrites. Use UpdateAsync when the value must be based on the current stored value (e.g., incrementing a counter safely across servers).

lua
-- Simple savelocal function saveData(player, data)    local key = "player_" .. player.UserId    local success, err = pcall(function()        playerStore:SetAsync(key, data)    end)    if not success then        warn("Failed to save data for", player.Name, ":", err)    endend
-- Atomic increment with UpdateAsynclocal function addCoinsAtomic(userId, amount)    local key = "player_" .. userId    pcall(function()        playerStore:UpdateAsync(key, function(current)            current = current or { coins = 0 }            current.coins = current.coins + amount            return current        end)    end)end

Retry Logic

lua
local MAX_RETRIES = 3local RETRY_DELAY = 2
local function safeGet(store, key)    for attempt = 1, MAX_RETRIES do        local success, result = pcall(function()            return store:GetAsync(key)        end)        if success then return true, result end        warn(string.format("GetAsync attempt %d/%d failed: %s", attempt, MAX_RETRIES, result))        if attempt < MAX_RETRIES then task.wait(RETRY_DELAY) end    end    return false, nilend

Auto-Save: PlayerRemoving + BindToClose

Server shutdown without BindToClose silently discards unsaved data.

lua
local sessionData = {} -- [userId] = data table
Players.PlayerAdded:Connect(function(player)    local data = loadData(player)    if data then        sessionData[player.UserId] = data    else        player:Kick("Could not load your data. Please rejoin.")    endend)
Players.PlayerRemoving:Connect(function(player)    local data = sessionData[player.UserId]    if data then        saveData(player, data)        sessionData[player.UserId] = nil    endend)
-- Flush all sessions on server shutdowngame:BindToClose(function()    for userId, data in pairs(sessionData) do        local key = "player_" .. userId        pcall(function()            playerStore:SetAsync(key, data)        end)    endend)

Ordered DataStores (Leaderboards)

Values must be positive integers.

lua
local coinsLeaderboard = DataStoreService:GetOrderedDataStore("Coins_v1")
local function setLeaderboardScore(userId, coins)    pcall(function()        coinsLeaderboard:SetAsync("player_" .. userId, math.floor(coins))    end)end
local function getTopPlayers(count)    local success, pages = pcall(function()        return coinsLeaderboard:GetSortedAsync(false, count) -- false = descending    end)    if not success then return {} end
    local results = {}    for rank, entry in ipairs(pages:GetCurrentPage()) do        table.insert(results, { rank = rank, userId = entry.key, score = entry.value })    end    return resultsend

Data Versioning / Migration

Include a _version field and migrate in the load path.

lua
local CURRENT_VERSION = 2
local function migrateData(data)    local version = data._version or 1    if version < 2 then        data.coins = data.gold or 0  -- renamed field        data.gold = nil        data._version = 2    end    return dataend

Use a versioned datastore name (PlayerData_v2) for breaking schema changes.


Common Mistakes

MistakeConsequenceFix
No pcall around datastore callsUnhandled error crashes the scriptAlways wrap in pcall
Saving on every Changed eventHits rate limits (60 + numPlayers×10 writes/min)Throttle; save on remove + periodic interval
No BindToClose handlerData lost on server shutdownAlways flush all sessions in BindToClose
Giving default data on load failurePlayer silently loses progressReturn nil on failure; kick or retry
SetAsync for atomic countersRace condition across serversUse UpdateAsync for read-modify-write
Storing Instances or functionsData silently dropsStore only strings, numbers, booleans, plain tables
Reusing datastore name after schema changeOld shape clashes with new codeAppend _v2, _v3 to name on breaking changes

來源與署名

來源:sentinelcore/roblox-skills位於roblox-datastores提交f2b1910

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架