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 从公开仓库中收录这些内容。

举报或申请下架