I’m currently developing a game that requires a party cross-server matchmaking system (Having a group of players join a queue with other random players. Eg. A group of 2 enter a queue and join a game with 2 random players, or another group of 2).
I’ve looked up some approaches to this system, and concluded that MemoryStoreService is what I’m looking for. Problem is I am having trouble implementing the “Party” feature, and I am unsure whether I should be using the Queue or Sorted Map primitive data structures. I am also unsure on how reliable MemoryStoreService actually is, and of any possible issues (Eg. Limits, latency issues, request outages, etc.) that I should be aware of.
In short, I am looking to build a scalable, robust and custom match making system that allows players to globally queue up as a party, or by themselves.
I am not looking for any exemplar code (Though any code is appreciated), but instead an explanation or nudge to point me in the right direction!
Hopefully I can be helpful, but I am going to start out by saying I have never used MemoryStoreService, And My experience is coming from My DataStore knowledge, as well as this MemoryStoreService Community Tutorial which I highly recommend you check out.
Memory store Service is the right choice. Lets first establish why, just in case other people Mention other methods, and as well fill in any gaps in your knowledge and understanding. You had 3 choices that are common for a system like this, that you could have used. MemoryStoreSerivce, DatastoreService, and MessagingService . You could “makes these work” for a system like this, but Its highly not recommended and heres why:
MessagingService Is NOT meant to be used as a reliable method, It isn’t a guarantee.
As stated in the Roblox docs on MessagingService: “Delivery is best effort and not guaranteed. Make sure to architect your game so delivery failures are not critical.”
Datastores are slow, Yield, and meant for Session based data (Data that is saved and that no data is lost, and there is no expiration time). You need something that is still reliable but server wide. You don’t need to save data if there is no servers. So because of this, we can roll out datastores.
Ok, so we have decided the other 2 options are unfit, and memory stores are the way to go. Lets talk about it itself.
" MemoryStoreService is a high throughput and low latency data service that provides fast in-memory data storage accessible from all servers in a live session. Memory Stores are suitable for frequent and ephemeral data that change rapidly and don’t need to be durable, because they are faster to access and vanish when reaching the maximum lifetime"
MemoryStores are meant for changes rapidly, for fast memory and accessibility. This is the best server so scaling up and allow all server access and meant for this.
These limited are quite lose and you shouldn’t need to worry, unless your game becomes really big on the platform and hundreds of thousands are using this system at once.
The memory quota limits the total amount of memory that an experience can consume. It’s not a fixed value. Instead, it changes over time depending on the number of users in the experience according to the following formula: 64KB + 1KB ⨉ [number of users].
“For API request limits, there’s a Request Unit quota applies for all MemoryStoreService API calls, which is 1000 + 100 * [number of concurrent users] request units per minute. Additionally, the rate of requests to any single queue or sorted map is limited to 100,000 request units per minute” …
These limits are Huge! Although if your worried, roblox has a Best Practices docs on Memory Stores to help with this!
It looks like you can use Both Queues and Sorted Map. Personally, I would use Sorted Maps, as it will allow you to get more organized and for me, Its easier to read and understand. I recommend checking out MemoryStoreService Community Tutorial if your totally lost after this explanation.
I would Make the Key the PrivateServerId that you would make with TeleportService:ReserveServer(), and then the Value with the players that have already Joined. That way, you can know when a server a full. When you find a server that is full, you remove it from the sorted map.
Here is a rough Example, And we will Assume the Max Server Amount is 4:
local players = game:GetService("Players")
local PlaceID = nil --PlaceId your teleporting too
local TeleportService = game:GetService("TeleportService")
local memoryStoreService = game:GetService("MemoryStoreService")
local TeleportServersMap = memoryStoreService:GetSortedMap("TeleportServers")
local function FindAServer(PartySize, PlayerInstanceList)
local success, data = pcall(function()
return TeleportServersMap:GetRangeAsync(Enum.SortDirection.Descending, 200) -- return the data
end)
local FoundServer = false
if success and typeof(data) == "table" then
for _, info in ipairs(data) do
local key = info.key
local value = info.value
if #value >= 4 then --If its full, we will remove it from the list reguardless
TeleportServersMap:RemoveAsync(key)
end
if FoundServer == false and #value + PartySize <= 4 then
FoundServer = true
if #value + PartySize == 4 then
TeleportServersMap:RemoveAsync(key)
else
--Update the Value here with the new party members
end
TeleportService:TeleportToPrivateServer(PlaceID, key, PlayerInstanceList) --Teleport the players here
end
end
elseif typeof(data) == "string" then
warn(string.format('failed to fetch TeleportServersMaps data for reason of: %s', data))
end
if FoundServer == false then
local Code = TeleportService:ReserveServer(PlaceID)
local success, err = pcall(function()
local UserIDs = {}
for i, player in PlayerInstanceList do
table.insert(UserIDs, player.UserId)
end
TeleportServersMap:SetAsync(Code, UserIDs, 30) -- add Server. If no one joins in 30 seconds, the server is removed from map.
end)
if not success then warn(string.format("failed to set %.f's data for reason of: %s", plr.UserId, err)) end -- log error
TeleportService:TeleportToPrivateServer(PlaceID, Code, PlayerInstanceList) --Teleport the players here if no servers where found
end
end
Basically:
→ Its gets the current servers
→ if a server has room, the members join that server
→ If a server does not have enough room, it moves on in the list
→ if no server is fit for the amount of people, It will make a server
→ It will add this server to the list so others can join and fill it up.
→ Once it reaches the max, server is removed from list
This is a basic idea and more code is needed for this to be improved on. Let me know if you have any questions. If your confused about this code, I recommend you check the community tutorial and I’m happy to answer any questions you may have!