Skip to content

Modules: Matchmaking

Server-authoritative matchmaking — queue management, match formation, ready-up, and reserved server teleportation (@broblox/matchmaking). Status: Implemented (125 tests).

Purpose

  • FIFO queue with optional MMR-based matching and configurable queue sizes.
  • Match lifecycle state machine: forming → starting → active → ended/cancelled.
  • Ready-up system with per-player tracking and AllPlayersReady events.
  • Reserved server allocation and teleportation with retry logic.

Core rules

  • Players can only be in one queue at a time (single-queue enforcement).
  • Match transitions follow a strict state machine — invalid transitions return errors.
  • Queue entries auto-expire after timeoutSeconds to prevent starvation.
  • Teams are assigned via round-robin when teamSize and teamCount are configured.

Data model

  • QueueEntryplayerId, joinedAt, mmr?, gameMode, metadata?.
  • QueueConfiggameMode, minPlayers, maxPlayers, timeoutSeconds, useMMR?, maxMMRDelta?.
  • MatchmatchId, gameMode, players, teams?, status, serverAccessCode?.
  • MatchStatus"forming" | "starting" | "active" | "ended" | "cancelled".
  • ReservedServeraccessCode, placeId, matchId, expectedPlayers, joinedPlayers.
  • TeleportRequestrequestId, matchId, players, status, retryCount.

Public API

Queue management

Method Description
registerQueue(config) Register a game mode queue
joinQueue(playerId, gameMode, mmr?) Add player to queue
leaveQueue(playerId, reason?) Remove player from queue
getQueueStatus(playerId) Position, wait time, estimated wait
tryFormMatch(gameMode, config?) FIFO match formation with optional teams
processTimeouts() Evict players exceeding timeout

Match lifecycle

Method Description
playerReady(playerId) Ready-up; emits AllPlayersReadyEvent when all ready
transitionToStarting(matchId) forming → starting
startMatch(matchId) starting → active
endMatch(matchId) active → ended
cancelMatch(matchId, reason?) Any → cancelled
removePlayerFromMatch(playerId, min?) Auto-cancels if below threshold

Server allocation

Method Description
allocateServer(placeId, matchId, players) Reserve a private server
teleportToMatch(matchId, players, data?) Teleport players to reserved server
recordPlayerJoined(matchId, playerId) Track player arrivals
cleanupExpiredServers() Evict stale reservations

Factory

const mm = createMatchmakingService({
  queues: [{ gameMode: "ffa", minPlayers: 2, maxPlayers: 8, timeoutSeconds: 120 }],
  teleportService: myTeleportService,
});

Security

  • Server-authoritative — all queue and match state is server-side only.
  • Single-queue enforcement — joining a second queue fails.
  • TeleportService DI — injectable interface; stub returns errors in tests.
  • Player verificationrecordPlayerJoined validates against expected player list.

Config

Key Default Description
timeoutSeconds per-queue Queue entry TTL
maxMMRDelta per-queue Max MMR gap for matching
maxRetries 3 Server allocation retry attempts
retryDelaySeconds 2 Delay between retries
reservationTimeoutSeconds 300 Stale server cleanup window

Observability

  • QueueJoinEvent / QueueLeaveEvent — queue activity
  • MatchFormedEvent — match created (player count, avg wait time)
  • MatchStatusChangedEvent — state transitions
  • AllPlayersReadyEvent — all players ready
  • ServerAllocatedEvent — server reserved
  • TeleportInitiatedEvent / TeleportFailureEvent — teleport lifecycle