Abstract Class: Matchmaker<Env>
Defined in: server/matchmaker.ts:61
Puts waiting players together into matches. One Durable Object per queue name.
A player waits by holding a WebSocket open. As soon as matchSize players are waiting, the matchmaker picks a new room id, reserves the room for them, tells each of them where to go and closes their sockets. The queue is the set of open sockets, so the object hibernates while people wait.
Who is matched with whom is first come, first served, unless you say otherwise: ratingOf and ratingGap keep players of different skill apart, and regionWaitMs keeps players of different regions apart, each for as long as you think a player should wait for a better match.
Friends who queue together are a party: their join tokens say so, or partyOf does. A party is matched as one, never split, and with teams set it plays on one side.
Extends
DurableObject<Env>
Type Parameters
| Type Parameter | Default type |
|---|---|
Env | Cloudflare.Env |
Constructors
Constructor
new Matchmaker<Env>(ctx, env): Matchmaker<Env>;Defined in: server/matchmaker.ts:129
Parameters
| Parameter | Type |
|---|---|
ctx | DurableObjectState |
env | Env |
Returns
Matchmaker<Env>
Overrides
DurableObject<Env>.constructor
Properties
| Property | Modifier | Type | Default value | Description | Defined in |
|---|---|---|---|---|---|
matchSize | protected | number | 2 | Players per match. | server/matchmaker.ts:63 |
minPlayers | protected | number | undefined | undefined | The fewest players a match may start with once the longest-waiting player has waited maxWaitMs. Defaults to matchSize: full matches only. | server/matchmaker.ts:69 |
maxWaitMs | protected | number | 0 | How long the longest-waiting player waits for a full match before one starts with whoever is there, provided that is at least minPlayers. 0, the default, waits for a full match however long it takes. | server/matchmaker.ts:76 |
ratingGap | protected | number | Infinity | How far apart two players' ratings may be for them to be matched. Infinity, the default, matches players whatever ratingOf says. A match is built around whoever has waited longest: the players nearest to them in rating, none further away than this. | server/matchmaker.ts:84 |
ratingGapPerSecond | protected | number | 0 | How much ratingGap grows for every second a player has waited, so that a player nobody is close to still gets a match. 0, the default, never widens it: such a player waits until someone close enough arrives. | server/matchmaker.ts:91 |
regionWaitMs | protected | number | 0 | For how long a player is matched only with players of their own region. After that they are matched with anyone, players of their region first. 0, the default, matches across regions from the start. | server/matchmaker.ts:98 |
teams | protected | number | 1 | How many sides a match is split into. 1, the default, says nothing about sides. With more, the matchmaker shares each match's players out among that many teams of as equal a size as it can, keeps every party on one team, and evens out the teams' ratings. The teams go in the match message and to the room, as this.teams. A party larger than a team is turned away. | server/matchmaker.ts:108 |
partyWaitMs | protected | number | 60_000 | How long the first member of a party to arrive waits for the others. After that the members who are there are matched without the rest. | server/matchmaker.ts:114 |
rooms | protected | RoomNamespace | undefined | undefined | Where the rooms for matches are: the Durable Object namespace of your Room class. protected override rooms = this.env.ROOMS; | server/matchmaker.ts:120 |
Methods
reserveRoom()
protected reserveRoom(
roomId,
players,
locationHint,
teams?
): Promise<void>;Defined in: server/matchmaker.ts:141
Set the room up for these players. The default creates it in rooms, near locationHint (where most of the players are), and closes it to everyone else. Override it to do more first, such as writing down the match, and call super.reserveRoom from yours. If it throws, the players keep waiting and the match is tried again shortly.
Parameters
| Parameter | Type |
|---|---|
roomId | string |
players | string[] |
locationHint | DurableObjectLocationHint | undefined |
teams? | string[][] |
Returns
Promise<void>
ratingOf()
protected ratingOf(player, request): number | Promise<number | undefined> | undefined;Defined in: server/matchmaker.ts:168
How good this player is, as a number in which players who are close are a fair match: an Elo rating, a rank, a level. It is asked once, when the player starts waiting, and only matters once ratingGap is set. A player without a rating, which is what the default gives everyone, can be matched with anyone.
protected override ratingGap = 150;
protected override async ratingOf(player: string) {
const stats = await new Accounts(this.env.DB, options).stats(player);
return stats.rating ?? 1000;
}
Parameters
| Parameter | Type |
|---|---|
player | string |
request | Request |
Returns
number | Promise<number | undefined> | undefined
regionOf()
protected regionOf(player, request): string | Promise<string | undefined> | undefined;Defined in: server/matchmaker.ts:181
Which region this player is in, for regionWaitMs. The default is the part of the world the gateway saw the request come from, one of Cloudflare's location hints such as "weur" or "enam", and undefined when that is not known, as in local development. A player without a region can be matched with anyone.
Parameters
| Parameter | Type |
|---|---|
player | string |
request | Request |
Returns
string | Promise<string | undefined> | undefined
partyOf()
protected partyOf(player, request):
| Party
| Promise<Party | undefined>
| undefined;Defined in: server/matchmaker.ts:194
The party this player queues with, if any: friends who are to be matched together. The default is what their join token says, which only your server can write (see JoinTokenClaims.party). Override it to look the party up yourself, in a table of your own for instance. Never take it from the request's query: a player who could name any party could join a stranger's.
Parameters
| Parameter | Type |
|---|---|
player | string |
request | Request |
Returns
| Party | Promise<Party | undefined> | undefined
fetch()
fetch(request): Promise<Response>;Defined in: server/matchmaker.ts:208
Durable Object entry point for players joining the queue. Tickflare's: don't override it.
Parameters
| Parameter | Type |
|---|---|
request | Request |
Returns
Promise<Response>
Overrides
DurableObject.fetch
webSocketClose()
webSocketClose(
ws,
code,
reason
): void;Defined in: server/matchmaker.ts:268
Durable Object entry point for players leaving the queue. Tickflare's: don't override it.
Parameters
| Parameter | Type |
|---|---|
ws | WebSocket |
code | number |
reason | string |
Returns
void
Overrides
DurableObject.webSocketClose
alarm()
alarm(): Promise<void>;Defined in: server/matchmaker.ts:277
The wait is over for whoever is in the queue.
Returns
Promise<void>
Overrides
DurableObject.alarm