Matchmaking System Tutorial

Introduction

Before reading please keep in mind this is a decently long read. There’s a lot to go over. By the end you should:

  • Have an in-depth view of various matchmaking system approaches
  • Have knowledge of the pros & cons of different approaches
  • Have a basic idea of how to implement said approaches

Table of Contents

  1. Background Information
  2. Approaches
    2.1 Same Server Matchmaking
    2.2 Cross Server Matchmaking with MessagingService
    2.3 Cross Server Matchmaking with HttpService
  3. Conclusion

1.0 Background Information

What exactly is a matchmaking system? Rather than thinking in terms of Roblox let’s think in terms of some of the most popular games currently on the market. Fortnite, Valorant, CS:GO, Rainbow Six: Siege, etc. When a player loads up the game they are able to queue for a match where they will be placed with other players. There are different types of queues (casual, unrated, ranked, competitive, etc.). Some queues are entirely random where as others are based on tracked statistics (rank, kills, skill level, etc.).

This system is known as matchmaking. The game will find a match for you while queueing. This is an incredibly common concept and yet one that is rarely utilized or talked about on Roblox. I’m currently working on a game that will use a matchmaking system. Players are put into servers with a maximum of 20 players per server and will then have the main menu UI displayed where they can start/stop matchmaking. When enough players are in the queue (my game requires 4) the first 4 added to the queue are given priority and teleported to a reserved place.


2.0 Approaches

Roblox provides no easy way to implement this. The heavy lifting has to be coded from the ground up but there are a few ways to approach this. Each approach has various pros & cons so when making a matchmaking system it is important to decide what is most important for your game. I would like to note I did in fact create all these various approaches when deciding which was best for my game.

It’s worth keeping in mind that the following approaches share similar mechanics. This includes a queue system that manages players currently matchmaking, edge case handling for when players join/leave, opening a reserved place then teleporting the players there.

2.1 Same Server Matchmaking

The first and simplest approach is same server matchmaking. So how does this work? Well each server has its own matchmaking system per se. Basically when a player queues they are queueing with the other people in their server. So let’s say you have a lobby place with a max of 50 players. When players hit the matchmake button they get added to a queue. If enough players are in the queue remove them from the queue and teleport them. Pretty simple so let’s get into more complicated approaches.

Pros

  • Very easy to implement
  • Significantly more reliable compared to other approaches

Cons

  • No cross server matchmaking
    • If players are AFK they might never find a game
  • Custom lobbies with private invites are not very viable
    • Limited to same server players

2.2 Cross Server Matchmaking with MessagingService

So firstly what is MessagingService? It’s a service Roblox offers for cross server communication. On the threads I’ve read about matchmaking systems this seems to be considered the ideal way to handle matchmaking. The reason for this being it’s offered directly from Roblox and isn’t too much off a hassle to implement.

The way this approach works is by dedicating one server to be the “host” server. This server is randomly assigned and will always be the first server that starts in a place. The host server handles the actual matchmaking queue as well as an active server table that stores the JobIds of other servers that are online.

This data is stored & received by the host server specifically subscribing to certain topics using MessagingService. For example, it will listen for a topic called ServerUpdated. When something is sent to this topic it will then handle it. In this case the topic is called from other non-host servers that will pass in a request (ServerAdded, ServerRemoved, etc.) as well as some data. When a server that is a non-host server starts up it will check if it is the host (usually through a datastore). If it isn’t then publish to the ServerUpdated topic passing in ServerAdded as well as the JobId of that server. It will then get added to the active server table.

This same process has to be repeated with actual matchmaking. A topic has to be created & listened to on the host for matchmaking. When a player queues the topic is published to with a certain request (such as Matchmake) and when they dequeue it is published to with another request (such as EndMatchmaking). The host adds the player to the queue, checks if there are enough players in the queue, then does teleporting by publishing to all servers who are listening to a teleport topic.

It’s also worth noting that rehosting is an important part of this approach. If a host server goes offline (all players leave and the server is closing) then a request needs to randomly be sent to a non-host server to become the new host.

This approach appears solid. Except for the countless posts talking about unreliability using MessagingService. Sometimes requests aren’t sent or received and this can cause major issues. You can’t return values using MessagingService so determining if a player is successfully queueing or if a server got added to the active servers table requires extra leg work and can be tedious.

Pros

  • Cross server matchmaking
  • Custom lobbies with private invites are very viable

Cons

  • Potential unreliability
  • MessagingService is rate limited
  • Hard to implement

2.3 Cross Server Matchmaking with HttpService

Before reading any further I should mention that this approach can cost money depending on the size of your game. So if you decide to implement this approach be realistic with how well you expect your game to do! You should also have some prior JavaScript experience.

This approach relies on a web app as well as a REST API. To create a web app I’m using Glitch. Using Glitch you can create web apps extremely easily and they provide the tools necessary to create a REST API using Node.js.

For my web app I used the express framework. However, it may be worth looking into alternatives such as fastify.

Something important to remember is you’ll be using an API Key to access the backend of this web app. It will be passed as a header when making HTTP requests from Roblox. Save your API Key in a .env file that can be accessed using process.env.API_KEY. On Roblox you need to keep this API Key secure. I recommend writing part of the key to a datastore, and storing another part in a model that can be fetched using InsertService. This is fairly secure. It’s also possible to implement hashing algorithms for further security.

In your web app you’ll have various routes that will handle various functions. For example, my web app adds a new player to the queue like so:

/*
  Add a player to the queue
*/
app.post('/queue/add/:playerid::serverid', (req, res) => {
  validateKey(req, res); // Validate the API key
  
  const playerId = req.params.playerid;
  const serverId = req.params.serverid;
  
  const alreadyExists = matchmakingQueue.some(queueElement => queueElement.playerId === playerId);
  
  // Add to queue if not already in queue
  if (alreadyExists)
    res.end();
  else {
    matchmakingQueue.push({
      playerId: playerId,
      serverId: serverId
    });
  }

  // Handle teleporting players if the queue matches the correct number of players
  const playersToTeleport = resolveQueue();
  if (playersToTeleport != undefined)
      res.json([...playersToTeleport])
});

Then in Roblox you just send these HTTP requests and handle the responses. No host server needed since the web app basically acts as the host.

Pros

  • Easy to implement
  • Cross server matchmaking
  • Custom lobbies with private invites are very viable
  • Rate limits are barely noticeable (500 requests/min is more than sufficient)
    • Can be further reduced by storing a local queue in Roblox

Cons

  • Security can be a problem
    • Unfortunately Roblox doesn’t have a very good way of securing private information like API keys
  • Potential cost
    • While Glitch provides a free web app solution the app automatically goes offline after 5 minutes
    • This can be prevented by upgrading your account for $8/month
      • Alternatively you can look at other ways to send requests to your web app to keep it online

3. Conclusion

I hope this tutorial furthered your knowledge on matchmaking systems. There are very few resources on this topic and I do hope to eventually see Roblox tackle it head on with something like a MatchmakingService. If you have any questions feel free to ask.

87 Likes

Great tutorial, usually I implement cross server simply because of how much the pros outweigh the cons. Entire game instance matchmaking except its rate limited, no brainer. But i appreciate how you explained multiple ways to implement it.

2 Likes

Nice tutorial! I’d like to mention that you should encourage using middleware functions in web applications with Express, rather than manually checking the credentials provided for every method you create.

psst, move your post to Community Tutorials

3 Likes

Very good tutorial! I will release a module soon which handles matchmaking with MessagingService automatically and this is almost the exact way I did it.

4 Likes

You can also use node.js and databases (I recommend mongodb) incase you plan on using your JS code from multiple scripts.

2 Likes

I was doing cross server matchmaking with messaging service, but I did it a little different than you did. I had every server subscribe to 2 topics: EditQueue and Teleport. Basically whenever a player tries to join a game mode, I check though a local table on the server to see if they can find a player two, and if so, send a message to edit queue telling every server to remove player2 from the list, and then reserve a server and send a message to teleport with the code and the players user ids. If I can’t find a player two, then we send a message telling all Servers to add them to the list. Ofc whenever a player leaves we also remove them from the list. Would this work too?

3 Likes

So yeah that method works as well however it can end up being more costly since you’re storing the queue on every single server. That said there’s no host server or rehosting needed so it might actually be cheaper. There’s pros and cons to the different ways of doing matchmaking :man_shrugging:

2 Likes

I wasn’t aware that MongoDB actually offered a free version (the last time I used it was like 4 years ago). After more research I fully agree with you and this is now my preferred way of storing the data. I did look into SQL-based databases before making my matchmaking system but truthfully I decided against them because it wasn’t worth the effort. MongoDB is a lot more lightweight though and I’m now in the process of updating my current system. I’ll more than likely update the tutorial with a section about MongoDB too.

Thanks for bringing this to my attention!

2 Likes

Something I have been looking for a while now! Thanks for the good explaining with the pros and cons, I will definitely use this post to create a matchmaking system for my game, thanks!

1 Like

This should help me with my new game! Thank you very much!

1 Like

Is this across all servers? Like, let’s say you have 30 servers, in one of them a player starts a queue, then across all servers, players when they want to join a queue they join in that queue until it’s full, and then a new one begins.

This is a very good and detailed tutorial, I’ll for sure use this for my game! Just a question, does this affect performance?

You should now use the MemoryStoreService now

1 Like

did u finished the module or is it public? i need to implement a matchmaking system

The module is finished and publicly available but hasn’t been updated since 2021. You shouldn’t use MessagingService anymore for matchmaking, that method is outdated. Instead use MemoryStoreService.

1 Like

thanks for the reply but where do i find themodule?
and can I simply replace the MessaginService with MemoryStoreService without chaning anything else?

I just saw that my module actually uses MemoryStoreService combined with MessagingService. So you can use it if you want:

But don’t be surprised if it doesn’t work. I won’t help you with any bugs.

Of course not