정렬된 맵 데이터 구조는 메모리 저장소에서 자주 사용되는 인메모리 데이터를 키-값 쌍으로 저장하고 선택적으로 정렬 키를 설정하며 정렬 키와 키를 기준으로 특정 순서를 유지할 수 있게 해줍니다. 큐와 달리, 맵에 들어가는 키의 순서는 처리 순서를 결정하지 않으며, 이는 정렬된 맵이 리더보드, 크로스 서버 경매와 같은 참여를 위한 게임 내 엔티티 구현을 위한 데이터 정리에서 유용하다는 것을 의미합니다.
제한 사항
데이터 구조 크기 제한 외에도, 정렬된 맵은 키의 크기 제한이 128자, 값의 크기 제한이 32KB 및 정렬 키의 크기 제한이 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일)입니다.
대부분의 게임에서 여러 서버가 동일한 키를 동시에 업데이트하고 값을 변경할 수 있습니다. 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
-- 현재 하한에서 최대 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, sizeError = pcall(function()
size = sortedMap:GetSizeAsync()
end)
if success then
print(size)
else
warn(sizeError)
end