ソート済みマップデータ構造は、メモリストアにおいて、オプションのソートキーを持つキーと値のペアとして頻繁に使われるメモリデータを保存し、ソートキーおよびキーに基づいて特定の順序を維持することを可能にします。キューとは異なり、マップに入るキーの順序は処理の順序を決定するものではないため、ソート済みマップは、リーダーボードやクロスサーバーオークションなど、ゲーム内のエンティティの実装におけるデータの整理に役立ちます。
制限
データ構造のサイズ制限に加えて、ソート済みマップには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日)です。提供されたソートキーは有効な数(整数または浮動小数点)または文字列でなければなりません。
キーのソート順では、ソートキーがキーよりも優先されます。たとえば、昇順でソートする場合、数値のソートキーが最初にソートされ、その後に文字列のソートキー、最終的にソートキーがないアイテムが続きます。数値のソートキーを持つすべてのアイテムは、ソートキーでソートされます。もし2つのアイテムのソートキーが同じ場合、キーでソートされます。同様に、すべての文字列のソートキーを持つアイテムもソートキーでソートされ、ソートキーが等しい場合はキーでソートされます。ソートキーがないすべてのアイテムは、キーだけでソートされます。
昇順でソートされたデータの例 -
{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()は、更新する前に最新の値を必ず変更するため、それをコールバック関数の入力とするべきです。
たとえば、以下のコードサンプルは、プレイヤーのリーダーボードスコアを更新します。このスコアは、キル数/死亡数として計算されます。MemoryStoreSortedMap: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`はマップ内のアイテムをソートするために使用されるソートキーです
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
end
MemoryStoreSortedMap:UpdateAsync()のレイテンシは、MemoryStoreSortedMap:GetAsync()やMemoryStoreSortedMap:SetAsync()と同様です。ただし、競合が発生した場合は異なります。
競合が発生した場合、システムは、次のいずれかが発生するまで、操作を自動的に再試行します:操作が成功する、コールバック関数がnilを返す、または最大再試行回数に達する。システムが最大再試行回数に達した場合、競合が返されます。
データの削除
ソート済みマップから1つのキーを削除したり、すべてのデータを削除するために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")
-- 下限を指定しないと先頭から削除が始まります
local exclusiveLowerBound = nil
while true do
-- 現在の下限から最大100アイテムを取得
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)
-- アイテム数が100未満の場合、マップの終わりに達したことを示します
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