有序映射数据结构在内存存储中允许您将频繁的内存数据存储为键值对,带有可选的排序键,并基于排序键和键维持特定的顺序。与队列不同,进入映射的键的顺序并不决定处理顺序,这使得有序映射对于实现游戏内的参与实体(例如排行榜和跨服务器拍卖)的数据组织非常有用。
限制
除了数据结构大小限制外,有序映射的键大小限制为128个字符,值大小限制为32 KB,排序键大小限制为128个字符。
如果您需要存储超出此限制的数据,您可以采用分片技术通过键前缀将其拆分并分布到多个数据结构中。对内存存储进行分片还可以帮助提高您的系统的可扩展性。
获取有序映射
要获取有序映射,请调用 MemoryStoreService:GetSortedMap() 并传入要为映射定义的名称。该名称在游戏中是全局的,因此您可以在任何脚本中使用该名称访问相同的有序映射。
local MemoryStoreService = game:GetService("MemoryStoreService")
local sortedMap = MemoryStoreService:GetSortedMap("SortedMap1")获取有序映射后,可以调用以下任一函数:
| 函数 | 操作 |
|---|---|
| MemoryStoreSortedMap:SetAsync() | 添加一个新键或覆盖已存在的键的值和/或排序键。 |
| MemoryStoreSortedMap:GetAsync() | 读取特定键。 |
| MemoryStoreSortedMap:GetRangeAsync() | 读取所有现有键或它们的特定范围。 |
| MemoryStoreSortedMap:UpdateAsync() | 更新键的值和/或排序键,在从有序映射中检索后。 |
| MemoryStoreSortedMap:RemoveAsync() | 移除有序映射中的某个键。 |
| MemoryStoreSortedMap:GetSizeAsync() | 获取有序映射中的项目数量。 |
添加或覆盖数据
要添加新键或覆盖有序映射中某个键的值或排序键,请调用 MemoryStoreSortedMap:SetAsync(),传入键名称、其值、过期时间(以秒为单位)和可选排序键。一旦键过期,内存会自动清理。最大过期时间为3,888,000秒(45天)。如果提供,则排序键必须是有效数字(整数或浮点数)或字符串。
在键的排序顺序中,排序键优先于键。例如,在升序排序中,数字排序键首先排序,然后是字符串排序键,最后是没有排序键的项目。所有具有数字排序键的项目按排序键排序,如果两个项目的排序键相等,则按键排序。类似地,所有具有字符串排序键的项目按排序键排序,如果两个项目的排序键相等,则按键排序。所有没有排序键的项目仅按键排序。
以下是一些按升序排序的数据示例 -
{key: "player1", value: someValue1, sortKey: -1}
{key: "player2", value: someValue2, sortKey: 0}
{key: "player4", value: someValue3, sortKey: 1}
{key: "player5", value: someValue4, sortKey: 1}
{key: "player3", value: someValue5, sortKey: 3.14}
{key: "player6", value: someValue6, sortKey: "someString"}
{key: "player0", value: someValue7}
{key: "player7", value: someValue8}注意 player0 在所有带有排序键的键之后排序。player6 在所有具有数字排序键的键之后排序。player4 和 player5 具有相同的排序键,因此它们按键的升序排序。
local MemoryStoreService = game:GetService("MemoryStoreService")
local sortedMap = MemoryStoreService:GetSortedMap("SortedMap1")
local setSuccess, _ = pcall(function()
return sortedMap:SetAsync("User_1234", 1000, 30, 3.14152)
end)
if setSuccess then
print("设置成功。")
end获取数据
您可以获取与特定键关联的数据值和排序键,或者获取范围内多个键的多个值和排序键。
使用单个键获取数据
要获取与有序映射中某个键关联的值和排序键,请调用 MemoryStoreSortedMap:GetAsync() 并传入键名称。
local MemoryStoreService = game:GetService("MemoryStoreService")
local sortedMap = MemoryStoreService:GetSortedMap("SortedMap1")
local setSuccess, _ = pcall(function()
return sortedMap:SetAsync("User_1234", 1000, 30, 3.14152)
end)
if setSuccess then
print("设置成功。")
end
local item
local getSuccess, getError = pcall(function()
item = sortedMap:GetAsync("User_1234")
end)
if getSuccess then
print(item)
else
warn(getError)
end使用多个键获取数据
要作为单个操作从有序映射获取多个键的数据,请调用 MemoryStoreSortedMap:GetRangeAsync()。此函数默认列出所有现有键,但您可以设置键范围的上限和下限。例如,以下代码示例从有序映射开始检索多达20个项目,范围内的键大于或等于 10,排序键大于或等于 100,以及小于或等于 50 和排序键小于或等于 500。
local MemoryStoreService = game:GetService("MemoryStoreService")
local sortedMap = MemoryStoreService:GetSortedMap("SortedMap1")
local lowerBound = {}
lowerBound["key"] = "10"
lowerBound["sortKey"] = 100
local upperBound = {}
upperBound["key"] = "50"
upperBound["sortKey"] = 500
-- 从头开始获取多达20个项目
local getSuccess, items = pcall(function()
return sortedMap:GetRangeAsync(
Enum.SortDirection.Ascending, 20, lowerBound, upperBound)
end)
if getSuccess then
for _, item in items do
print(item.key)
print(item.sortKey)
end
end更新数据
要从有序映射中检索键的值和排序键并更新它,调用 MemoryStoreSortedMap:UpdateAsync(),传入键名称、一个回调函数以更新此键的值和排序键,以及过期时间(以秒为单位)。最大过期时间为3,888,000秒(45天)。
对于大多数游戏,多个服务器可以并发更新相同的键并更改值。由于 MemoryStoreSortedMap:UpdateAsync()始终在更新之前修改最新值,因此您应该使用它来读取最新值作为回调函数的输入。
例如,以下代码示例更新某个玩家在排行榜上的分数。分数计算为击杀数/死亡数。UpdateAsync()确保即使多个游戏服务器同时更新相同的项目,也会更新最新的击杀数和死亡数。玩家的击杀数和死亡数是单调递增的值,因此在会话中只能增加。
local MemoryStoreService = game:GetService("MemoryStoreService")
local sortedMap = MemoryStoreService:GetSortedMap("Leaderboard")
local function updateLeaderboard(itemKey, killsToAdd, deathsToAdd)
local success, newStats, newScore = pcall(function()
return sortedMap:UpdateAsync(itemKey, function(playerStats, playerScore)
playerStats = playerStats or { kills = 0, deaths = 0 }
playerStats.kills += killsToAdd
playerStats.deaths += deathsToAdd
if playerStats then
-- `playerScore` 是用于对映射中的项目进行排序的 sortKey
playerScore = playerStats.kills / math.max(playerStats.deaths, 1)
return playerStats, playerScore
end
return nil
end, 30)
end)
if success then
print(newStats)
print(newScore)
end
endUpdateAsync() 的延迟与 GetAsync() 和 SetAsync() 相似,除非发生冲突。
当发生冲突时,系统会自动重试操作,直到下列三种情况之一发生:操作成功、回调函数返回 nil,或达到最大重试次数。如果系统达到最大重试次数,则会返回冲突。
移除数据
您可以使用 MemoryStoreSortedMap:RemoveAsync() 来移除有序映射中的一个键,也可以用于删除内存存储有序映射中的所有数据。
移除一个键
要从有序映射中移除一个键,调用 MemoryStoreSortedMap:RemoveAsync() 并传入键名称。
local MemoryStoreService = game:GetService("MemoryStoreService")
local sortedMap = MemoryStoreService:GetSortedMap("SortedMap1")
local setSuccess, _ = pcall(function()
return sortedMap:SetAsync("User_1234", 1000, 30, "someStringSortKey")
end)
if setSuccess then
print("设置成功。")
end
local removeSuccess, removeError = pcall(function()
sortedMap:RemoveAsync("User_1234")
end)
if not removeSuccess then
warn(removeError)
end删除所有数据
要删除有序映射中的内存,首先使用 MemoryStoreSortedMap:GetRangeAsync() 列出所有键,然后使用 MemoryStoreSortedMap:RemoveAsync() 将其移除。
local MemoryStoreService = game:GetService("MemoryStoreService")
local sortedMap = MemoryStoreService:GetSortedMap("SortedMap1")
-- 初始下界为 nil 从第一个项目开始清空
local exclusiveLowerBound = nil
while true do
-- 从当前下界开始获取多达一百个项目
local getRangeSuccess, items = pcall(function()
return sortedMap:GetRangeAsync(Enum.SortDirection.Ascending, 100, exclusiveLowerBound)
end)
if getRangeSuccess then
local removeSuccess = true
local removeError = nil
for _, item in items do
removeSuccess, removeError = pcall(function()
sortedMap:RemoveAsync(item.key)
end)
end
-- 如果删除项目时发生错误,尝试使用相同的独占下界再次执行
if not removeSuccess then
warn(removeError)
-- 如果范围少于一百个项目,则已达到映射末尾
elseif #items < 100 then
break
else
-- 最后检索到的键是下一次迭代的独占下界
exclusiveLowerBound = {}
exclusiveLowerBound["key"] = items[#items].key
exclusiveLowerBound["sortKey"] = items[#items].sortKey
end
end
end获取大小
要获取有序映射中的项目数量,请调用 MemoryStoreSortedMap:GetSizeAsync()。
local MemoryStoreService = game:GetService("MemoryStoreService")
local sortedMap = MemoryStoreService:GetSortedMap("SortedMap1")
local setSuccess, _ = pcall(function()
return sortedMap:SetAsync("User_1234", 1000, 30, 3.14152)
end)
if setSuccess then
print("设置成功。")
end
local size
local success, sizError = pcall(function()
size = sortedMap:GetSizeAsync()
end)
if success then
print(size)
else
warn(sizeError)
end