[v2.1.0] MatchmakingService - ON HOLD

THIS PROJECT IS ON INDEFINITE HOLD.

MatchmakingService

Preface

Current Version: V2.1.0

Github. Asset. Uncopylocked hub/receiver game.

Check out these games that use the service

Want to get your game added to that list? Send me a message and I’ll check your game out!

Introduction

MatchmakingService is a way to easily make games that involve matchmaking. It utilizes the new MemoryStoreService for high through-put potential. MatchmakingService is as easy to use as:

(On your hub server where players queue from)


-- Obtain the service

local MatchmakingService = require(7567983240).GetSingleton()

-- Set the game place

MatchmakingService:AddGamePlace("Map 1", 7584483307)

MatchmakingService:SetPlayerRange("Map 1", NumberRange.new(2, 2))

-- Queue players (you can call QueuePlayer from anywhere)

game.Players.PlayerAdded:Connect(function(p)

MatchmakingService:QueuePlayer(p, "queue", "Map 1")

end)

for i, p in ipairs(game.Players:GetPlayers()) do

MatchmakingService:QueuePlayer(p, "queue", "Map 1")

end

On the game where players are teleported to:


local MatchmakingService = require(7567983240).GetSingleton()

-- It's important game servers know how large they can get. You don't really need every map here,

-- but you do need whichever map this is.

MatchmakingService:SetPlayerRange("Map 1", NumberRange.new(2, 2))

-- Tell the service this is a game server

MatchmakingService:SetIsGameServer(true)

local gameData = nil

local t1 = {}

local t2 = {}

-- Basic start function

function Start()

print("Started")

MatchmakingService:StartGame(gameData.gameCode)

-- Simple teams for a 1v1.

local p = game.Players:GetPlayers()

table.insert(t1, p[1])

table.insert(t2, p[2])

end

-- YOU MUST CALL UpdateRatings BEFORE THE GAME IS CLOSED. YOU CANNOT PUT THIS IN BindToClose!

function EndGame(winner)

MatchmakingService:UpdateRatings(gameData.ratingType, {if winner == 1 then 1 else 2, if winner == 2 then 1, else 2}, {t1, t2})

for i, v in ipairs(game.Players:GetPlayers()) do

-- You can teleport them back to the hub here, I just kick them

v:Kick()

end

end

game.Players.PlayerAdded:Connect(function(player)

if not gameData then

gameData = MatchmakingService:GetGameData()

end

if #game.Players:GetPlayers() >= 2 then

Start()

end

end)

Small note before we start

Due to the lack of tools that MemoryQueue allows, current this version of MatchmakingService solely uses different SortedMaps which are slightly less tuned for this process. If/when MemoryQueue gets more tools that allow us to reliably manage it, then I will write this all utilizing MemoryQueues where possible.

How does it work?

MatchmakingService utilizes the new MemoryStoreService for cross-game ephemeral memory storage. This storage is kind of like the RAM in your computer or phone, except it’s not exactly the same. There’s a great article on it here which describes more of the technical details if you’re interested in it. MemoryStores have a much higher throughput potential than other services which makes them great for queuing items that will be quickly removed or changed. It has overwrite protections as well! Basically MemoryStores are the best way to make a system like this (it will be even better when they give us more tools to manage a MemoryQueue which will speed this up even more).

Basically, however, one server will manage making matches across the entire queue. Think of this server as the centralized handler (I was thinking of ways to have this be completely random access, but it gets a little messy, though has potential to happen in the future). When a player queues for a specific skill level they will only be matched up against a certain number of people in the same skill level. The number that are put into the game depends on what you set it to (read the docs below!).

Users are in a first-in-first-out queue. This means that the first players to queue are the first players to get into a game. When a game is created it can either be joinable or not. By default it is still joinable if the game hasn’t started and the server isn’t full, the MatchmakingService will prioritize these existing games before trying to make new ones. When a game starts, by default, the server will be locked and no new joiners are permitted.

Documentation

You can find up-to-date documentation here.

Future Plans

  • Switch to MemoryQueues if/when we get more ways to manage it

  • Fully random access management that doesn’t use a central server

  • Party parity

Latest changelog:

291 Likes

This is awesome… Thank you :smiley:

()

12 Likes

Amazing resource and an epix use of the new memory service! 10/10! ;D

8 Likes

Work pretty well. I would use this as my Game Ideas

4 Likes

You should check this out for the skill level things :slight_smile:

8 Likes

I was actually thinking about implementing that at a base level when I first saw it a few days ago. I’ll just have to read through how it works and think of a good way to implement it. Thank you for the suggestion though!

Here’s what I’m thinking:
I’ll make some sort of MatchmakingService:GetRating(plr, ratingType) where ratingType is a string of a defined type of rating (e.g. “ranked” or “normal”) that will default if not existing. This will allow you to have many separate ratings for different queues, much like most games already work where they have a rating for ranked and a rating for unranked. While this would be for internal use when queueing a player instead of providing a skill level, you provide a ratingType and it will get the data for you out of the back end (i.e. MatchmakingService:QueuePlayer(plr, skillLevel) becomes MatchmakingService:QueuePlayer(plr, ratingType)), you could still get their rating yourself if you want to display it to them. Instead of single queue pools for each skill level, they will be put into a pool in a range of levels that gets increasingly bigger the longer they’re in queue. I will also add a default ratingType of none that basically queues all the players that were queued with it in one queue with no rating taken into account and no rating is updated at the end, a pure non-rated game (most games still use some sort of rating in unrated gameplay, but I will provide the option to skip it completely).

Feedback on this idea?

10 Likes

I’m about 70% done with my rewrite that involves adding a rating system into this service. Right now all necessary functions have been rewritten to accept these new rating values. There’s basically 2 new things, a rating type, think of this as ranked or normal (the gamemode essentailly), but it can be any string you want to call it, and a rating itself. For every rating type, a player is assigned a glicko-2 rating. So if you have 5 different rated queues you can have 5 different ratings for each queue if it’s a different gamemode. See figure below:

Glicko-2 is a pretty good rating system but it does have a flaw called volatility farming. I won’t go into detail about this flaw, but I will be looking into making some changes to glicko-2 to fix this, but it’s currently not something I’m worried about.

There will also be a queue that does not use any rating system. This will be done by using “none” as the rating. This queue will be entirely separate and have no ratings attached.

This update will not be backwards compatible with the current version.

8 Likes

I just pushed version 2.0.0-beta out! I’ve updated the post with additional information and how the system works now. This version is not fully backwards compatible with the v1 versions. I will soon add the party system and the none rating type for non-skill based match making.

8 Likes

Considering the tragedy of skill-based matchmaking, I will be using this wonderful resource. However, I have one question (idk if it’s too dumb or not): is this using SBMM ( or is it using something different)? I’m asking because I have serious concerns about SBMM regarding players and I am planning to add to my game a ranked version of a new game mode I just added.

3 Likes

As of version 2.0.0-beta, there is skill-based match making using the glicko-2 rating system (glicko-2 is used in games like TF2, CSGO, Splatoon and more). Players are queued into a pool based on their rating and the service prioritizes getting players of a similar rating but does expand its search every now and then if it can’t find people of the same level. I will soon be adding a none rating type that will not use any skill based match making or rating system to pool them into a queue, but I am currently working on the party system.

5 Likes

Wow, sorry I didn’t see your messages but nice work on this! I’m definitely going to be using it on a future project as this simplifies things so much! I’d love to help you in some way, if there’s anything I can do.

1 Like

Any testing you can do on a larger scale to ensure that it’s stable at more than 2 players would be amazing. I can only test with 2 players, so before I make an official release version I really want to make sure it’s stable.

4 Likes

Is there a way to get how many players are in a queue?

3 Likes

Not currently I will add that in with the next update though! Thanks for the suggestion!

3 Likes

2.1.0 is now out with MatchmakingService:GetQueueCounts()

3 Likes

Would it be best to constantly refresh it or is there a smarter way of updating it?

1 Like

Im a little confused with what you mean. If you want I could add an event you can subscribe to in code to listen to when someone gets added or removed from the queue which would be significantly more performant and wouldn’t add to the rate limits.

3 Likes

Version 2.2.0-beta has been released!
Changes (breaking):

  • None

Changes (non-breaking):

  • [Addition] MatchmakingService:SetMaxPartySkillGap(newMaxGap)
  • [Addition] MatchmakingService:GetPlayerInfo(player)
  • [Addition] MatchmakingService:QueueParty(players, ratingType)
  • [Addition] MatchmakingService:GetPlayerParty(player)
  • [Addition] MatchmakingService.PlayerAddedToQueue signal.
  • [Addition] MatchmakingService.PlayerRemovedFromQueue signal.
  • [Change] MatchmakingService:SetPlayerInfo now accepts a new argument, party, which is a table of player ids in their party including the player’s own id.

Fixes:

  • None

The party system did work with 2 players, but I would appreciate if someone could test it with more to make sure it works! Please remember this is a beta, bugs may exist!

Currently the signals are not global across servers, this is planned though!

2 Likes

Does this service work across servers or is it just within one server?

1 Like

As long as all of the games are in the same universe it will work between them all and queue is global.

Meaning they’re like this:
df907351cea63b77f62deac109f918ca674b38d6_2_690x453

My recommendation is a hub place where players can queue up (all hub server instances would be connected, so if you have say 5000 players across 100 servers, all 100 servers would share the same queue pool). At the moment, only one game place is allowed. The game place is where players are teleported when they find a game. In the teleport data you can get information like the game type, the game code, etc and generate a map based on that data. In the future I may look into allowing multiple game places for different maps, but for now you can clone a map into the workspace based on teleport data if you need multiple maps.