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