You can write your topic however you want, but you need to answer these questions:
-
What do you want to achieve? Keep it simple and clear! "I want to achieve ranked matchmaking.
-
What is the issue? Include screenshots / videos if possible! “I don’t know how to go about it.”
-
What solutions have you tried so far? Did you look for solutions on the Developer Hub? “I have looked around the DevForum for solutions to ranked matchmaking, but I couldn’t find anything. I have thought about using global leaderboards for the ranks, but it didn’t work.”
I am making a retro-themed FPS game. One of the ways I connect players together is through matchmaking. In this case, I want to figure out ranked matchmaking. Ranked matchmaking is connecting players together based on their rank which I don’t know how to do.
local Matchmaking = {}
local MemoryStoreService = game:GetService("MemoryStoreService")
local LocalizationService = game:GetService("LocalizationService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local HttpService = game:GetService("HttpService")
local ServerStorage = game:GetService("ServerStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local MessagingService = game:GetService("MessagingService")
local TeleportService = game:GetService("TeleportService")
local Debris = game:GetService("Debris")
local Players = game:GetService("Players")
local MainModule = require(script.Parent)
local MatchmakingInterval = 5
local QueuesTable = {
["RandomizedQueue1"] = {
Name = "RandomizedQueue1",
MinimumPlayers = 2,
MaxPlayers = 15,
MatchmakingType = "Locational",
Active = true
},
["ZombieQueue1"] = {
Name = "ZombieQueue1",
MinimumPlayers = 1,
MaxPlayers = 15,
MatchmakingType = "Locational",
Active = true
},
["SkilledQueue1"] = {
Name = "SkilledQueue1",
MinimumPlayers = 2,
MaxPlayers = 15,
MatchmakingType = "SkilledLocational",
MinimumKillsForSkilled = 500,
Active = true,
},
}
local BRQ1List = {}
local BZQ1List = {}
Matchmaking.QueuesTable = QueuesTable
Matchmaking.MatchmakingInterval = MatchmakingInterval
function Matchmaking:GetPlayerData(player)
if ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name) then
local ClonedData = ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name):Clone()
ClonedData.Parent = ServerStorage:WaitForChild("PlayerDataDump")
return ClonedData
else
return false
end
end
function Matchmaking:GetPlayerLocation(player)
local PlayerLocation = LocalizationService:GetCountryRegionForPlayerAsync(player)
return PlayerLocation
end
function Matchmaking:AddPlayerToQueue(player, queue, specializedLocation)
if Players:FindFirstChild(player.Name) then
if QueuesTable[queue] then
local QueueInfo = QueuesTable[queue]
local MemoryStoreQueue = MemoryStoreService:GetSortedMap(QueueInfo.Name)
if QueueInfo.Active == true then
if QueueInfo.MatchmakingType == "Locational" then
local PlayerLocation
-- local Priority = -1
if specializedLocation == nil then
PlayerLocation = Matchmaking:GetPlayerLocation(player)
else
PlayerLocation = specializedLocation
end
--[[
task.spawn(function()
local IsLocationAvailable, queuedPlayers = Matchmaking:IsSameLocationAvailable(MemoryStoreQueue, 10, PlayerLocation)
for index, player in ipairs(queuedPlayers) do
if queuedPlayers.Location == PlayerLocation then
-- Priority = 1
end
end
end)
--]]
if QueueInfo.Name:find("RandomizedQueue") then
if not table.find(BRQ1List, player.Name) then
local success, err = pcall(function()
MemoryStoreQueue:SetAsync(player.UserId, {PlayerName = player.Name, PlayerId = player.UserId}, 3600)
end)
if not success then
print(err)
else
print("Added player.")
if ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name) then
local PlayerData = ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name)
if PlayerData:FindFirstChild("CurrentQueue") then
PlayerData:FindFirstChild("CurrentQueue").Value = QueueInfo.Name
end
end
if not ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name):FindFirstChild(player.Name) then
local PlayerEntry = Instance.new("BoolValue")
PlayerEntry.Name = player.Name
PlayerEntry.Parent = ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name)
end
end
else
print("player is already in queue.")
end
elseif QueueInfo.Name:find("ZombieQueue") then
if not table.find(BZQ1List, player.Name) then
local success, err = pcall(function()
MemoryStoreQueue:SetAsync(player.UserId, {PlayerName = player.Name, PlayerId = player.UserId, Timestamp = os.time()}, 3600)
end)
if not success then
print(err)
else
print("Added player.")
if ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name) then
local PlayerData = ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name)
if PlayerData:FindFirstChild("CurrentQueue") then
PlayerData:FindFirstChild("CurrentQueue").Value = QueueInfo.Name
end
end
if not ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name):FindFirstChild(player.Name) then
local PlayerEntry = Instance.new("BoolValue")
PlayerEntry.Name = player.Name
PlayerEntry.Parent = ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name)
end
end
else
print("player is already in queue.")
end
end
elseif QueueInfo.MatchmakingType == "SkilledLocational" then
local PlayerLocation
local PlayerData = Matchmaking:GetPlayerData(player)
if PlayerData == nil or PlayerData == false then
warn("could not place player into skilled queue because data could not be provided. (error type: data could not be retrieved [matchmaking module])")
return
end
local Priority = -1
if specializedLocation == nil then
PlayerLocation = Matchmaking:GetPlayerLocation(player)
else
PlayerLocation = specializedLocation
end
--[[
task.spawn(function()
local IsLocationAvailable, queuedPlayers = Matchmaking:IsSameLocationAvailable(MemoryStoreQueue, 10, PlayerLocation)
for index, player in ipairs(queuedPlayers) do
if queuedPlayers.Location == PlayerLocation then
Priority = 1
end
end
end)
--]]
if not table.find(BRQ1List, player.Name) then
if PlayerData.Kills.Value >= 500 then
local success, err = pcall(function()
MemoryStoreQueue:SetAsync(player.UserId, {PlayerName = player.Name, PlayerId = player.UserId}, 3600)
end)
if not success then
warn(err .. " (error type: queue entry denial [matchmaking module])")
else
print("Added player.")
if ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name) then
local PlayerData = ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name)
if PlayerData:FindFirstChild("CurrentQueue") then
PlayerData:FindFirstChild("CurrentQueue").Value = QueueInfo.Name
end
end
if not ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name):FindFirstChild(player.Name) then
local PlayerEntry = Instance.new("BoolValue")
PlayerEntry.Name = player.Name
PlayerEntry.Parent = ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name)
end
end
else
warn("player's kills were not greater than or equal to 500. (error type: non-sufficent kills value [matchmaking module])")
end
else
warn("player is already in queue. (error type: trying to add player to queue they are already in [matchmaking module])")
end
end
else
warn("queue is offline. (error type: attempting to access offline queue [matchmaking module])")
end
else
warn("queue does not exist. (error type: attempting to access non-existent queue [matchmaking module])")
end
end
end
function Matchmaking:RemovePlayerFromQueue(player, queue)
if Players:FindFirstChild(player.Name) then
if QueuesTable[queue] then
local QueueInfo = QueuesTable[queue]
local MemoryStoreQueue = MemoryStoreService:GetSortedMap(QueueInfo.Name)
local success, err = pcall(function()
MemoryStoreQueue:RemoveAsync(player.UserId)
end)
if ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name) then
local PlayerData = ServerStorage.GameStorage.PlayerData:FindFirstChild(player.Name)
if PlayerData:FindFirstChild("CurrentQueue") then
PlayerData:FindFirstChild("CurrentQueue").Value = ""
end
end
if table.find(BRQ1List, player.Name) then
local index = table.find(BRQ1List, player.Name)
table.remove(BRQ1List, index)
end
if table.find(BZQ1List, player.Name) then
local index = table.find(BZQ1List, player.Name)
table.remove(BZQ1List, index)
end
if ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name):FindFirstChild(player.Name) then
ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name):FindFirstChild(player.Name):Destroy()
end
end
end
end
function Matchmaking:RunMatchmaking()
task.spawn(function()
local QueueName = "RandomizedQueue1"
local QueueInfo = QueuesTable[QueueName]
while true do
local success, playersInQueue = pcall(function()
return MemoryStoreService:GetSortedMap(QueueName):GetRangeAsync(Enum.SortDirection.Descending, 15)
end)
if success then
for _, playerData in ipairs(playersInQueue) do
local DataValue = playerData.value
if not table.find(BZQ1List, DataValue.PlayerName) then
table.insert(BZQ1List, DataValue.PlayerName)
print(#playersInQueue)
print(#BZQ1List)
end
end
if #BZQ1List >= 2 then
for _, playerData in ipairs(BZQ1List) do
local player = Players:FindFirstChild(tostring(playerData.PlayerName))
if player then
--player:SetAttribute("MatchFound", true)
end
end
for _, data in ipairs(BZQ1List) do
if Players:FindFirstChild(tostring(data)) then
local success, result = pcall(function()
return Players:GetUserIdFromNameAsync(tostring(data))
end)
if Players:FindFirstChild(tostring(data)) then
if ServerStorage.GameStorage.PlayerData:FindFirstChild(tostring(data)) then
local PlayerData = ServerStorage.GameStorage.PlayerData:FindFirstChild(tostring(data))
if PlayerData:FindFirstChild("CurrentQueue").Value == QueueName then
ReplicatedStorage.Remotes.MatchFoundVisual:FireClient(Players:FindFirstChild(tostring(data)))
local TeleportOptions = Instance.new("TeleportOptions")
local TeleportData = {
Gamemode = MainModule:ToBase64("Randomized")
}
TeleportOptions:SetTeleportData(TeleportData)
wait(2)
local success2, err = pcall(function()
TeleportService:TeleportAsync(0, {Players:FindFirstChild(tostring(data))}, TeleportOptions)
end)
end
end
end
if success then
print(result)
MemoryStoreService:GetSortedMap(QueueName):RemoveAsync(Players:FindFirstChild(tostring(data)).UserId)
end
end
end
for index, entry in ipairs(ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name):GetChildren()) do
entry:Destroy()
end
table.clear(BRQ1List)
end
end
wait(Matchmaking.MatchmakingInterval)
end
end)
task.spawn(function()
local QueueName = "ZombieQueue1"
local QueueInfo = QueuesTable[QueueName]
while true do
local success, playersInQueue = pcall(function()
return MemoryStoreService:GetSortedMap(QueueName):GetRangeAsync(Enum.SortDirection.Descending, 15)
end)
if success then
for _, playerData in ipairs(playersInQueue) do
local DataValue = playerData.value
if not table.find(BZQ1List, DataValue.PlayerName) then
table.insert(BZQ1List, DataValue.PlayerName)
print(#playersInQueue)
print(#BZQ1List)
end
end
if #BZQ1List >= 2 then
for _, playerData in ipairs(BZQ1List) do
local player = Players:FindFirstChild(tostring(playerData.PlayerName))
if player then
--player:SetAttribute("MatchFound", true)
end
end
for _, data in ipairs(BZQ1List) do
if Players:FindFirstChild(tostring(data)) then
local success, result = pcall(function()
return Players:GetUserIdFromNameAsync(tostring(data))
end)
if Players:FindFirstChild(tostring(data)) then
if ServerStorage.GameStorage.PlayerData:FindFirstChild(tostring(data)) then
local PlayerData = ServerStorage.GameStorage.PlayerData:FindFirstChild(tostring(data))
if PlayerData:FindFirstChild("CurrentQueue").Value == QueueName then
ReplicatedStorage.Remotes.MatchFoundVisual:FireClient(Players:FindFirstChild(tostring(data)))
local TeleportOptions = Instance.new("TeleportOptions")
local TeleportData = {
Gamemode = MainModule:ToBase64("Zombie Outbreak")
}
TeleportOptions:SetTeleportData(TeleportData)
wait(2)
local success2, err = pcall(function()
TeleportService:TeleportAsync(0, {Players:FindFirstChild(tostring(data))}, TeleportOptions)
end)
end
end
end
if success then
print(result)
MemoryStoreService:GetSortedMap(QueueName):RemoveAsync(Players:FindFirstChild(tostring(data)).UserId)
end
end
end
for index, entry in ipairs(ServerStorage.MatchmakingQueues:FindFirstChild(QueueInfo.Name):GetChildren()) do
entry:Destroy()
end
table.clear(BRQ1List)
end
end
wait(Matchmaking.MatchmakingInterval)
end
end)
end
return Matchmaking
The code block above is my current matchmaking code. (I know that the place ids are 0, I don’t want to leak anything.)
If you can provide anything, I’ll try to make use of it.