Skip to content
A game matchmaking example using TypeScript (node).
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
certs
css
data
docs
src
test
.gitignore
README.md
gulpfile.js
index.html
package.json
tsconfig.json
tslint.json

README.md

matchmaker-ts

https://github.com/wwlib/matchmaker-ts

matchmaker-ts

matchmaker-ts is a tool for designing and analyzing multiplayer matchmaking.

Build & Run

yarn
yarn start

Documentation

https://wwlib.github.io/matchmaker-ts/typedoc/index.html

Getting Started

matchmaker-ts provides a GUI for controlling and testing the server. The GUI also allows matchmaker-ts to act as a client app that can connect to the server.

For example:

  • mock clients/players can be generated by clicking the addMockClient button
  • these will be added to lobbies and matched
  • clicking the step button below the stats graph will add the current number-of-lobbies and number-of-clients as graph data points
  • clicking the startSim button will cause new clients to be created continuously (rapidly)
  • periodically clicking step will add real time data points to the graph
  • clicking the on button below the stats graph will cause the graph to update continuously
  • Note: this is not yet well-optimized and may not perform well over time

Using the client app:

  • launch another instance of matchmaker-ts (on the same machine, for now)
  • in both clients, click the connect button
  • then type messages in the clients' <input> fields
  • the messages should be relayed between clients and displayed in the <messages> fields
  • Note: when these special clients connect to the server they are added to a ChatLobby which does not attempt any matchmaking. This allows the clients to chat indefinitely. Up to 8 clients will be added to the special ChatLobby. Subsequent connections are treated normally.

Overview and Architecture

matchmaker-ts is a real time multiplayer server written in TypeScript with an Electron/React front-end for analysis and testing.

matchmaker-ts-architecture

Director

The Director coordinates the servers subsystems.

  • Instantiates the ConnectionManager
  • Manages communication with the Database
  • Manages the lifecycle of Lobbies
  • whenever a new player connects, the Director either:
    • adds the player to an existing Lobby or
    • creates a new Lobby appropriate for that player
  • Manages the lifecycle of authenticated TCPClientSessions
  • Creates and destroys ClientProxy instances used to relay messages between TCPClientSessions and GameWorlds (Lobbies)
  • Manages the creation of clients used for testing the server
  • mock clients = a mock TCPClientSession + ClientProxy
  • mock clients are added to Lobbies just like actual clientSession
  • Manages the creation/clean-up of (mock) PlayerAccounts

Pub/Sub

  • The Director currently uses a local/in-memory pub/sub module (PubSubJS) to relay messages between TCP connections and Lobby/GameWorlds
  • Greater scalability could be achieved by using Redis which would allow messages to be shared between multiple server instances

Primary/Replica

  • The Director is designed to have two modes: Primary and Replica (unimplemented)
  • In Primary mode, the Director acts as the authoritative Database and owner/director of Lobby/GameWorld instances
  • The Replica Director would rely on the Primary Director to distribute Lobby/GameWorld creation/management responsibility across all instances.
  • In Replica mode, the Director would instantiate a ConnectionManager and accept TCP connections routed to it by a load balancer. Messaging between Primary and Replica instances would be via pub/sub
  • A more scalable approach would allow Replica instances to also create/manage Lobby/GameWorld instances

Matchmaking

The Director coordinates matchmaking by:

  • finding the most appropriate Lobby instance for each new player/client
  • each existing Lobby is queried to see if it will accept the player: Lobby: willAcceptPlayer(player: PlayerAccount): boolean
  • if no Lobby will accept the player, a new lobby is created for that player: Director: addLobbyWithPlayerAccount(player: PlayerAccount): Lobby

Lobby instances accept players based on configurable criteria:

  • PlayerLocation (i.e. NorthAmericaEast)
  • Player MMR score: using an mmrRange, i.e {min: 1001, max: 1800}
  • Unimplemented: latency, business priority, behavior profile (history of quitting), etc.

Matching

  • The Lobby is responsible for matching players
  • The current matching algorithm is simplistic and assumes 1v1 matching (teams are not supported, yet)
  • Periodically (every deltaTime, i.e. 1 second) every player in the lobby is compared to every other player to determine if a match is acceptable: willMatchClients(client1: ClientProxy, client2: ClientProxy): boolean
  • A greedy approach is used so that matchable players are immediately matched
  • Players will be matched if the difference between their MMR scores is less than the Lobby's maxClientMMRDifference (i.e. 100 points)
  • If a pair's combined wait time in the lobby exceeds the Lobby's maxCombinedClientWaitTime (i.e. 30 seconds) the pair will be matched

GamePlay

  • The current implementation does not involve actual or simulated gameplay
  • As soon as a match is made, the players are disposed by the Director: handleGameOver(client1: ClientProxy, client2: ClientProxy): void

ClientProxy

The ClientProxy class acts as a bridge between the TCPClientSessions (sockets) and Lobby/GameWorld instances. This abstraction anticipates the need to distribute socket connections across server instances/machines for scalability. The ClientProxy publishes and subscribes to channels identified by the player's UUID. The ClientProxy receives messages when the TCPClientSession publishes to the player's inbound channel ([UUID].in) and relays these to the Lobby/GameWorld to which the player has been added. The TCPClientSession sends messages via the socket which it receives via the player's [UUID].out channel. As noted, this would allow for TCPClientSessions to be hosted by multiple servers/machines.

Messages

matchmaker-ts anticipates the need to optimize message sizes and uses schemapack to pack JavaScript Objects (JSON) into compact binary messages.

Note: The currently implemented message types use string payloads. Packing is most effective with simpler payload types.

Scalability Considerations

The standard way to scale multiplayer matching to millions of players/connections it to run multiple server instances fed by a load balancer. In this architecture, each server manages thousands of connections, lobbies and game worlds. Messages are routed between server instances using a pub/sub service like Redis. Redis also serves as the shared, in-memory database for all server instances.

matchmaker-ts anticipates this architecture by using a local pub/sub module (PubSubJS) that could be swapped out for node-redis. As noted above, the Director is designed to have Primary and Replica modes where the Replica Director would rely on the Primary Director to distribute Lobby/GameWorld creation/management responsibility across all instances.

For example: Amazon's GameLift service can provide a highly scalable multi-server architecture using redis. GameLift's matchmaking service also provides a configurable, scalable mechanism for matchmaking.

Performance

There is room for a lot of performance tuning in the current implementation. As noted above, the matching algorithm is simplistic. The Electron wrapper is useful for design and development. A headless node instances would be used in production.

TODO: Use workers to improve matching performance.

Matching Considerations

Matching is an interesting (hard) problem and the subject of previous and ongoing research. These relevant links address both intuitive and counter-intuitive strategies for maximizing player engagement:

AWS

Research

MMR/ELO

Experience

Approach

Data/ML

Using ML (Deep Learning) could be a valubale approach to creating an 'intelligent' adaptive matching strategy - especially given that non-obvious, counter-intuitive factors can contribute to player engagement, retention and overall profitability.

Teams vs 1v1

Teams are conceptually like a Lobby, made up of players who have often explicitly chosen to play as a team. An approach to team matching would give players a mechanism for joining a specific TeamLobby and then matching TeamLobby instances in a TeamMatchingLobby.

AWS: GameLift

You can’t perform that action at this time.