How would I go about matching players in the same region together, but also adding a fallback if there isn't any other regions?

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear! "I’m trying to match players together based on their region (as in the LocalizationService function) but also add a fallback so that if there aren’t any other regions, they get matched with other regions.

  2. What is the issue? Include screenshots / videos if possible! “I have looked all over the DevForum for some answers, and there is nothing related to regional matchmaking as far as I’ve looked.”

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub? “I have tried putting in a regional tag with matchmaking entries, but didn’t work as I needed it to.”

I’m using MemoryStoreService for my matchmaking. The type of memory store I’m using is a “SortedMap.” I’ve tried putting in a regional tag from LocalizationService, but players from the same region didn’t get matched together. Also, I don’t have a fallback for when there are no other regions that a player is in.

Here is some of my matchmaking module.

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

If you can help, respond if you can. Thank you. :+1:

1 Like