数据储存

Time:15 分钟

Data Store(数据存储)是 Roblox 为游戏提供的存储功能,可以用来保存需要在玩家退出游戏后仍然留存的数据,包括玩家物品栏中的物品、当前经验值或几乎任何其他需要保留的数据。

数据存储在单个游戏中是共享的,因此游戏中的任何场景,包括不同服务器上的场景,都可以访问和更改相同的数据。

结构

数据存储本质上是一个字典,就像 Lua 表格一样。数据存储中的每个值都可以通过唯一的键进行索引,比如使用玩家的 Player/UserId|UserId

键 值

Player_1234 50

Player_2345 20

Player_7462 78000

Player_8934 1200

Player_10345 0

数据存储访问

数据存储由 DataStoreService 管理,因此开发者编写的脚本必须先获取该服务,然后才能执行其他操作。

    
    local DataStoreService = game:GetService("DataStoreService")

DataStoreService 写入脚本之后,就可以使用 DataStoreService/GetDataStore|GetDataStore() 函数并用数据储存的名称对其进行访问。例如:

    
    local DataStoreService = game:GetService("DataStoreService")
    local experienceStore = DataStoreService:GetDataStore("PlayerExperience")

数据储存只能由服务器通过 Script|Script 访问。尝试从客户端通过 LocalScript 访问会导致错误。

管理数据储存

设置数据

GlobalDataStore/SetAsync|SetAsync() 可以设置新的数据储存条目的值。此函数需要条目的键名和要设置的

    
    local DataStoreService = game:GetService("DataStoreService")
    local experienceStore = DataStoreService:GetDataStore("PlayerExperience")
    
    local success, err = pcall(function()
    	experienceStore:SetAsync("Player_1234", 50)
    end)
    
    if success then
    	print("Success!")
    end

诸如 GlobalDataStore/SetAsync|SetAsync() 等通过网络访问数据储存内容的调用有时会失败。正如我们前面说的,建议将这些调用打包在 pcall() 中,以捕获和处理所有错误。

使用 GlobalDataStore/SetAsync|SetAsync() 拥有一定的潜在的风险,因为其会覆盖任何条目中的当前值。如果开发者想要更新一个已有的条目,推荐使用 GlobalDataStore/UpdateAsync|UpdateAsync(),因为此函数在进行更改前会考虑旧值。

读取数据

GlobalDataStore/GetAsync|GetAsync() 函数可以通过数据储存条目的键名来获取该条目的值。

    
    local DataStoreService = game:GetService("DataStoreService")
    local experienceStore = DataStoreService:GetDataStore("PlayerExperience")
    
    local success, currentExperience = pcall(function()
    	return experienceStore:GetAsync("Player_1234")
    end)
    
    if success then
    	print("Current Experience:", currentExperience)
    end

数据增量

GlobalDataStore/IncrementAsync|IncrementAsync() 可以更改数据存储中的一个数字值。此函数需要条目的键名和数值增量。

    
    local DataStoreService = game:GetService("DataStoreService")
    local experienceStore = DataStoreService:GetDataStore("PlayerExperience")
    
    local success, newExperience = pcall(function()
    	return experienceStore:IncrementAsync("Player_1234", 1)
    end)
    
    if success then
    	print("New Experience:", newExperience)
    end

更新数据

GlobalDataStore/UpdateAsync|UpdateAsync() 可以更改数据存储中存储的任何值。此函数需要条目的键名以及一个定义条目更新方式的函数。此函数根据您定义的逻辑获取当前值并返回新值。

    
    local DataStoreService = game:GetService("DataStoreService")
    local nicknameStore = DataStoreService:GetDataStore("Nicknames")
     
    local function makeNameUpper(currentName)
    	local newName = string.upper(currentName)
    	return newName
    end
     
    local success, newName = pcall(function()
    	return nicknameStore:UpdateAsync("Player_1234", makeNameUpper)
    end)
    
    if success then
    	print("Uppercase Name:", newName)
    end

传递给 GlobalDataStore/UpdateAsync|UpdateAsync() 的函数允许暂停,也就是说其不能包含任何例如 wait() 的暂停函数。

删除数据

GlobalDataStore/RemoveAsync|RemoveAsync() 可以删除任何一条条目,且返回该键对应的值。

    
    local DataStoreService = game:GetService("DataStoreService")
    local nicknameStore = DataStoreService:GetDataStore("Nicknames")
    
    local success, nickname = pcall(function()
    	return nicknameStore:RemoveAsync("Player_1234")
    end)
    
    if success then
    	print("Removed Nickname:", nickname)
    end

有序数据存储

常规数据存储不会对其内容进行排序。大多数游戏并不需要这种功能,但有时以有序的方式获取数据也是有用的,比如排行榜的统计数据。

OrderedDataStore(有序数据存储)是一种特殊类型的数据存储,它可以:

  • 轻松按排序返回内容。

  • 一次请求返回多条记录(常规数据存储一次只能请求一个条目)。

有序数据存储使用与常规数据存储相同的函数,包括 GlobalDataStore/GetAsync|GetAsync()GlobalDataStore/SetAsync|SetAsync()GlobalDataStore/UpdateAsync|UpdateAsync() 等。此外,它还提供了 OrderedDataStore/GetSortedAsync|GetSortedAsync() 函数,该函数接受几个参数:返回的 DataStorePages 对象的“分页大小”、排序顺序和最小/最大值。

假设有一个由五个角色及其年龄填充的有序数据存储,此示例将数据按降序排序到每页 3 个条目的页面中,然后循环遍历这些页面并输出每个角色的姓名/年龄。

    
    local DataStoreService = game:GetService("DataStoreService")
    local characterAgeStore = DataStoreService:GetOrderedDataStore("CharacterAges")
    
    -- 填充有序数据存储
    characterAgeStore:SetAsync("Mars", 19)
    characterAgeStore:SetAsync("Janus", 20)
    characterAgeStore:SetAsync("Diana", 18)
    characterAgeStore:SetAsync("Venus", 25)
    characterAgeStore:SetAsync("Neptune", 62)
    
    -- 将数据排列到每页三个条目的页面中(降序)
    local pages = characterAgeStore:GetSortedAsync(false, 3)
    
    while true do
    	-- 获取当前(第一个)页面
    	local data = pages:GetCurrentPage()
    	-- 遍历页面上的所有键值对
    	for _, entry in pairs(data) do
    		print(entry.key .. ":" .. tostring(entry.value))
    	end
    	-- 检查是否已经到达最后一页
    	if pages.IsFinished then
    		break
    	else
    		print("----------------")
    		-- 进行下一页
    		pages:AdvanceToNextPageAsync()
    	end
    end
    
    
    Neptune: 62
    Venus: 25
    Janus: 20
    ----------------
    Mars: 19
    Diana: 18

限制、排队和错误处理

像所有网络调用一样,对数据存储的请求有时可能由于连接不良或其他问题而失败。正如在整篇文章中所看到的那样,将数据储存命令打包到 pcall() 中以处理任何错误是很有必要的。开发者可以将返回的带有错误代码的数据储存消息和Articles/Datastore Errors|数据存储错误和限制中的表格进行交叉比对。

此外,数据存储模型也有应用的限制。如果游戏超出这些限制,Roblox 引擎将自动限制游戏的数据存储使用,导致数据请求花费更长时间。这些请求会被放入队列中,这将在 Articles/Datastore Errors 文章中进一步描述。

在 Studio 中使用数据储存

默认情况下,Studio 中模拟的场景没有数据储存的访问权限,所以在 Studio 中调用 GlobalDataStore/SetAsync|SetAsync()GlobalDataStore/GetAsync|GetAsync() 这样的请求函数都会导致错误。

如果需要,开发者可以在 Studio 中启用数据存储,如下所示:

1.在 Home(主页)选项卡中,打开 Game Settings(游戏设置)窗口。

https://developer.roblox.com/assets/bltd6af44e38b951d0a/Game-Settings.png

2.在 Options(选项)部分,启用 Enable Studio Access to API Services(允许 Studio 访问 API 服务)。
3.单击 Save(保存)应用更改。

访问 Studio 中的数据存储对于实时游戏来说可能很危险,因为 Studio 访问的数据存储与客户端应用程序相同。为避免覆盖制作数据,开发者不应为实时游戏启用此设置,而应为游戏的单独测试版本启用此设置。

如果开发者并非通过 Roblox 网站编辑场景(例如使用本地的 .rbxl 文件等),则需要在命令栏中调用DataModel/SetPlaceId|SetPlaceId(),然后 Studio 中的游戏才能访问数据存储。

***Roblox官方链接:数据储存