DataStoreService 允许您存储需要在会话之间持久化的数据,例如玩家库存中的物品或技能点。数据存储在每个游戏中都是一致的,因此游戏中的任何地方都可以访问和更改相同的数据,包括不同服务器上的地方。
如果您想为数据存储添加细粒度的权限控制并在 Studio 或 Roblox 服务器之外访问它们,可以使用 数据存储的开放云 API。
要通过 Creator Hub 查看和监控游戏中的所有数据存储,请使用 数据存储管理器。
对于需要频繁更新或访问的临时数据,请使用 内存存储。
启用 Studio 访问
默认情况下,在 Studio 中测试的游戏无法访问数据存储,因此您必须首先启用它们。在 Studio 中访问数据存储对于实时游戏可能是危险的,因为 Studio 访问与客户端应用程序相同的数据存储。为了避免覆盖生产数据,请不要为实时游戏启用此设置。相反,请为游戏的单独测试版本启用它。
要在 已发布 的游戏中启用 Studio 访问:
- 打开 Studio 的 文件 ⟩ 体验设置 窗口。
- 导航到 安全性。
- 启用 启用 Studio 访问 API 服务 切换。
- 点击 保存。
访问数据存储
要在游戏中访问数据存储:
- 将 DataStoreService 添加到服务器端的 Script。
- 使用 GetDataStore() 函数并指定您要使用的数据存储的名称。如果数据存储不存在,Studio 会在您第一次保存游戏数据时创建一个。
local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")创建数据
数据存储本质上是一个字典,类似于 Luau 表。每个值在数据存储中都有一个唯一的 键 索引,例如用户的唯一 Player.UserId 或游戏促销的命名字符串。
| 用户数据键 | 值 |
|---|---|
| 31250608 | 50 |
| 351675979 | 20 |
| 505306092 | 78000 |
| 促销数据键 | 值 |
| ActiveSpecialEvent | SummerParty2 |
| ActivePromoCode | BONUS123 |
| CanAccessPartyPlace | true |
要创建一个新条目,请调用 SetAsync(),并提供键名和一个值。
local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, errorMessage = pcall(function()
gameStore:SetAsync("User_1234", 50)
end)
if not success then
print(errorMessage)
end更新数据
要更改数据存储中的任何存储值,请调用 UpdateAsync(),并提供条目的键名和一个回调函数,该函数定义您希望如何更新条目。此回调接受当前值并根据您定义的逻辑返回新值。如果回调返回 nil,则写入操作将被取消,值不会更新。
local DataStoreService = game:GetService("DataStoreService")
local nicknameStore = DataStoreService:GetDataStore("Nicknames")
local function makeNameUpper(currentName)
local nameUpper = string.upper(currentName)
return nameUpper
end
local success, updatedName = pcall(function()
return nicknameStore:UpdateAsync("User_1234", makeNameUpper)
end)
if success then
print("大写名称:", updatedName)
end设置与更新
使用设置快速更新特定键。SetAsync() 函数:
- 如果两个服务器尝试同时设置相同的键,可能会导致数据不一致
- 仅计入写入限制
使用更新来处理多服务器尝试。UpdateAsync() 函数:
- 在进行任何更改之前,从最后更新它的服务器读取当前键值
- 由于在写入之前读取,因此速度较慢
- 计入读取和写入限制
读取数据
要读取数据存储条目的值,请调用 GetAsync(),并提供条目的键名。
local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, currentGame = pcall(function()
return gameStore:GetAsync("User_1234")
end)
if success then
print(currentGame)
end增量数据
要在数据存储中递增一个整数,请调用 IncrementAsync(),并提供条目的键名和一个数字,表示要更改的值。IncrementAsync() 是一个便利函数,让您避免调用 UpdateAsync() 并手动递增整数。
local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, newGame = pcall(function()
return gameStore:IncrementAsync("Player_1234", 1)
end)
if success then
print(newGame)
end移除数据
要移除一个条目并返回与键关联的值,请调用 RemoveAsync()。
local DataStoreService = game:GetService("DataStoreService")
local nicknameStore = DataStoreService:GetDataStore("Nicknames")
local success, removedValue = pcall(function()
return nicknameStore:RemoveAsync("User_1234")
end)
if success then
print(removedValue)
end元数据
与键关联的元数据有两种类型:
- 服务定义:默认只读元数据,例如最近的更新时间和创建时间。每个对象都有服务定义的元数据。
要管理元数据,请扩展 SetAsync()、UpdateAsync()、GetAsync()、IncrementAsync() 和 RemoveAsync() 函数。
SetAsync() 接受可选的第三和第四个参数:
一个 UserIds 的表。这可以帮助内容版权和知识产权的跟踪和移除。
一个 DataStoreSetOptions 对象,您可以使用 SetMetadata() 函数定义自定义元数据。
local DataStoreService = game:GetService("DataStoreService")local gameStore = DataStoreService:GetDataStore("PlayerGame")local setOptions = Instance.new("DataStoreSetOptions")setOptions:SetMetadata({["GameElement"] = "Fire"})local success, errorMessage = pcall(function()gameStore:SetAsync("User_1234", 50, {1234}, setOptions)end)if not success thenprint(errorMessage)end
GetAsync()、IncrementAsync() 和 RemoveAsync() 返回 DataStoreKeyInfo 对象中的第二个值。这个第二个值包含服务定义的属性和获取用户定义元数据的函数。
- Version 属性获取键的版本。
- CreatedTime 属性获取键创建的时间,格式为自纪元以来的毫秒数。
- UpdatedTime 属性获取键最后一次更新的时间,格式为自纪元以来的毫秒数。
local DataStoreService = game:GetService("DataStoreService")local gameStore = DataStoreService:GetDataStore("PlayerGame")local success, currentGame, keyInfo = pcall(function()return gameStore:GetAsync("User_1234")end)if success thenprint(currentGame)print(keyInfo.Version)print(keyInfo.CreatedTime)print(keyInfo.UpdatedTime)print(keyInfo:GetUserIds())print(keyInfo:GetMetadata())endUpdateAsync() 的回调函数在 DataStoreKeyInfo 对象中接受一个额外参数,该参数描述当前键状态。它返回修改后的值、与 UserIds 关联的键和键的元数据。
local DataStoreService = game:GetService("DataStoreService")local nicknameStore = DataStoreService:GetDataStore("Nicknames")local function makeNameUpper(currentName, keyInfo)local nameUpper = string.upper(currentName)local userIDs = keyInfo:GetUserIds()local metadata = keyInfo:GetMetadata()return nameUpper, userIDs, metadataendlocal success, updatedName, keyInfo = pcall(function()return nicknameStore:UpdateAsync("User_1234", makeNameUpper)end)if success thenprint(updatedName)print(keyInfo.Version)print(keyInfo.CreatedTime)print(keyInfo.UpdatedTime)print(keyInfo:GetUserIds())print(keyInfo:GetMetadata())end
有关定义元数据时的限制,请参见 元数据限制。
有序数据存储
默认情况下,数据存储不会对其内容进行排序。如果您需要以有序的方式获取数据,例如在持久排行榜统计中,请调用 GetOrderedDataStore(),而不是 GetDataStore()。
local DataStoreService = game:GetService("DataStoreService")
local characterAgeStore = DataStoreService:GetOrderedDataStore("CharacterAges")有序数据存储支持与默认数据存储相同的基本功能,以及独特的 GetSortedAsync() 函数。此函数根据特定的排序顺序、页面大小和最小/最大值检索 多个排序键。
以下示例将角色数据按降序排序为每页三个条目,然后循环遍历页面并输出每个角色的名称和年龄。
local DataStoreService = game:GetService("DataStoreService")
local characterAgeStore = DataStoreService:GetOrderedDataStore("CharacterAges")
-- 填充有序数据存储
local characters = {
Mars = 19,
Janus = 20,
Diana = 18,
Venus = 25,
Neptune = 62
}
for char, age in characters do
local success, errorMessage = pcall(function()
characterAgeStore:SetAsync(char, age)
end)
if not success then
print(errorMessage)
end
end
-- 按降序将数据排序为每页三个条目
local success, pages = pcall(function()
return characterAgeStore:GetSortedAsync(false, 3)
end)
if success then
while true do
-- 获取当前(第一页)
local entries = pages:GetCurrentPage()
-- 遍历页面上的所有键值对
for _, entry in entries do
print(entry.key .. " : " .. tostring(entry.value))
end
-- 检查是否已到达最后一页
if pages.IsFinished then
break
else
print("----------")
-- 前进到下一页
pages:AdvanceToNextPageAsync()
end
end
end读取多个条目
要在单个请求中读取多个 有序数据存储 条目,请调用 BatchGetAsync(),并提供一个键的数组。这是逐个读取条目的 GetAsync() 的批处理对应。
BatchGetAsync() 返回一个字典,将每个请求的键映射到一个具有 value 字段的表。不存在的键将从字典中省略,因此在读取其值之前,请确认键是否存在。
您请求的每个键都计为一个读取请求,因此对 N 个键的单个调用计为对有序数据存储 读取限制 的 N 个请求。
以下示例在单个请求中读取三个玩家分数,然后循环遍历键并输出每个存在的分数。
local DataStoreService = game:GetService("DataStoreService")
local playerScores = DataStoreService:GetOrderedDataStore("PlayerScores")
local keys = {"Player_123", "Player_456", "Player_789"}
local success, results = pcall(function()
return playerScores:BatchGetAsync(keys)
end)
if success then
for _, key in keys do
local entry = results[key]
if entry then
print(key .. " : " .. tostring(entry.value))
else
print(key .. " 没有保存的条目")
end
end
end