@colyseus/core 0.17.42 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/MatchMaker.cjs +19 -6
- package/build/MatchMaker.cjs.map +2 -2
- package/build/MatchMaker.d.ts +10 -0
- package/build/MatchMaker.mjs +18 -6
- package/build/MatchMaker.mjs.map +2 -2
- package/build/Protocol.cjs +102 -37
- package/build/Protocol.cjs.map +2 -2
- package/build/Protocol.d.ts +33 -2
- package/build/Protocol.mjs +102 -37
- package/build/Protocol.mjs.map +2 -2
- package/build/Room.cjs +296 -19
- package/build/Room.cjs.map +3 -3
- package/build/Room.d.ts +186 -3
- package/build/Room.mjs +303 -21
- package/build/Room.mjs.map +3 -3
- package/build/RoomPlugin.cjs +252 -0
- package/build/RoomPlugin.cjs.map +7 -0
- package/build/RoomPlugin.d.ts +271 -0
- package/build/RoomPlugin.mjs +220 -0
- package/build/RoomPlugin.mjs.map +7 -0
- package/build/Server.cjs +40 -7
- package/build/Server.cjs.map +2 -2
- package/build/Server.d.ts +25 -0
- package/build/Server.mjs +41 -8
- package/build/Server.mjs.map +2 -2
- package/build/Transport.cjs +38 -2
- package/build/Transport.cjs.map +2 -2
- package/build/Transport.d.ts +40 -4
- package/build/Transport.mjs +38 -2
- package/build/Transport.mjs.map +2 -2
- package/build/index.cjs +11 -2
- package/build/index.cjs.map +2 -2
- package/build/index.d.ts +2 -1
- package/build/index.mjs +12 -2
- package/build/index.mjs.map +2 -2
- package/build/input/InputBuffer.cjs +113 -0
- package/build/input/InputBuffer.cjs.map +7 -0
- package/build/input/InputBuffer.d.ts +136 -0
- package/build/input/InputBuffer.mjs +86 -0
- package/build/input/InputBuffer.mjs.map +7 -0
- package/build/internal.cjs +61 -0
- package/build/internal.cjs.map +7 -0
- package/build/internal.d.ts +9 -0
- package/build/internal.mjs +29 -0
- package/build/internal.mjs.map +7 -0
- package/build/matchmaker/LocalDriver/LocalDriver.cjs +13 -0
- package/build/matchmaker/LocalDriver/LocalDriver.cjs.map +2 -2
- package/build/matchmaker/LocalDriver/LocalDriver.d.ts +1 -0
- package/build/matchmaker/LocalDriver/LocalDriver.mjs +13 -0
- package/build/matchmaker/LocalDriver/LocalDriver.mjs.map +2 -2
- package/build/matchmaker/driver.cjs.map +1 -1
- package/build/matchmaker/driver.d.ts +12 -0
- package/build/matchmaker/driver.mjs.map +1 -1
- package/build/presence/LocalPresence.d.ts +1 -1
- package/build/rooms/LobbyRoom.cjs +8 -10
- package/build/rooms/LobbyRoom.cjs.map +2 -2
- package/build/rooms/LobbyRoom.d.ts +4 -3
- package/build/rooms/LobbyRoom.mjs +8 -10
- package/build/rooms/LobbyRoom.mjs.map +2 -2
- package/build/rooms/RelayRoom.cjs +12 -16
- package/build/rooms/RelayRoom.cjs.map +2 -2
- package/build/rooms/RelayRoom.d.ts +32 -11
- package/build/rooms/RelayRoom.mjs +10 -16
- package/build/rooms/RelayRoom.mjs.map +2 -2
- package/build/router/index.cjs +65 -4
- package/build/router/index.cjs.map +2 -2
- package/build/router/index.d.ts +30 -6
- package/build/router/index.mjs +66 -6
- package/build/router/index.mjs.map +3 -3
- package/build/utils/UserSessionIndex.cjs +162 -0
- package/build/utils/UserSessionIndex.cjs.map +7 -0
- package/build/utils/UserSessionIndex.d.ts +166 -0
- package/build/utils/UserSessionIndex.mjs +130 -0
- package/build/utils/UserSessionIndex.mjs.map +7 -0
- package/package.json +19 -14
- package/src/MatchMaker.ts +40 -6
- package/src/Protocol.ts +130 -59
- package/src/Room.ts +475 -22
- package/src/RoomPlugin.ts +563 -0
- package/src/Server.ts +72 -11
- package/src/Transport.ts +76 -8
- package/src/index.ts +10 -1
- package/src/input/InputBuffer.ts +192 -0
- package/src/internal.ts +46 -0
- package/src/matchmaker/LocalDriver/LocalDriver.ts +10 -0
- package/src/matchmaker/driver.ts +13 -0
- package/src/rooms/LobbyRoom.ts +12 -8
- package/src/rooms/RelayRoom.ts +9 -15
- package/src/router/index.ts +112 -11
- package/src/utils/UserSessionIndex.ts +311 -0
package/build/Room.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/Room.ts"],
|
|
4
|
-
"sourcesContent": ["import { unpack } from '@colyseus/msgpackr';\nimport { decode, type Iterator, $changes } from '@colyseus/schema';\nimport { ClockTimer as Clock } from '@colyseus/timer';\n\nimport { EventEmitter } from 'events';\nimport { logger } from './Logger.ts';\n\nimport type { Presence } from './presence/Presence.ts';\nimport type { Serializer } from './serializer/Serializer.ts';\nimport type { IRoomCache } from './matchmaker/driver.ts';\n\nimport { NoneSerializer } from './serializer/NoneSerializer.ts';\nimport { SchemaSerializer } from './serializer/SchemaSerializer.ts';\n\nimport { getMessageBytes } from './Protocol.ts';\nimport { type Type, Deferred, generateId, wrapTryCatch } from './utils/Utils.ts';\nimport { createNanoEvents } from './utils/nanoevents.ts';\nimport { isDevMode } from './utils/DevMode.ts';\n\nimport { debugAndPrintError, debugMatchMaking, debugMessage } from './Debug.ts';\nimport { ServerError } from './errors/ServerError.ts';\nimport { ClientState, type AuthContext, type Client, type ClientPrivate, ClientArray, type ISendOptions, type MessageArgs } from './Transport.ts';\nimport { type RoomMethodName, OnAuthException, OnCreateException, OnDisposeException, OnDropException, OnJoinException, OnLeaveException, OnMessageException, OnReconnectException, type RoomException, SimulationIntervalException, TimedEventException } from './errors/RoomExceptions.ts';\n\nimport { standardValidate, type StandardSchemaV1 } from './utils/StandardSchema.ts';\nimport * as matchMaker from './MatchMaker.ts';\n\nimport {\n CloseCode,\n ErrorCode,\n Protocol,\n type MessageHandlerWithFormat as SharedMessageHandlerWithFormat,\n type MessageHandler as SharedMessageHandler,\n type Messages as SharedMessages,\n} from '@colyseus/shared-types';\n\nconst DEFAULT_PATCH_RATE = 1000 / 20; // 20fps (50ms)\nconst DEFAULT_SIMULATION_INTERVAL = 1000 / 60; // 60fps (16.66ms)\nconst noneSerializer = new NoneSerializer();\n\nexport const DEFAULT_SEAT_RESERVATION_TIME = Number(process.env.COLYSEUS_SEAT_RESERVATION_TIME || 15);\n\nexport type SimulationCallback = (deltaTime: number) => void;\n\nexport interface RoomOptions {\n state?: object;\n metadata?: any;\n client?: Client;\n}\n\n// Helper types to extract individual properties from RoomOptions\nexport type ExtractRoomState<T> = T extends { state?: infer S extends object } ? S : any;\nexport type ExtractRoomMetadata<T> = T extends { metadata?: infer M } ? M : any;\nexport type ExtractRoomClient<T> = T extends { client?: infer C extends Client } ? C : Client;\n\nexport interface IBroadcastOptions extends ISendOptions {\n except?: Client | Client[];\n}\n\n/**\n * Message handler with automatic type inference from format schema.\n * When a format is provided, the message type is automatically inferred from the schema.\n */\nexport type MessageHandlerWithFormat<T extends StandardSchemaV1 = any, This = any> =\n SharedMessageHandlerWithFormat<T, Client, This>;\n\nexport type MessageHandler<This = any> = SharedMessageHandler<Client, This>;\n\n/**\n * A map of message types to message handlers.\n */\nexport type Messages<This extends Room> = SharedMessages<This, Client>;\n\n/**\n * Helper function to create a validated message handler with automatic type inference.\n *\n * @example\n * ```typescript\n * messages = {\n * move: validate(z.object({ x: z.number(), y: z.number() }), (client, message) => {\n * // message.x and message.y are automatically typed as numbers\n * console.log(message.x, message.y);\n * })\n * }\n * ```\n */\nexport function validate<T extends StandardSchemaV1, This = any>(\n format: T,\n handler: (this: This, client: Client, message: StandardSchemaV1.InferOutput<T>) => void\n): MessageHandlerWithFormat<T, This> {\n return { format, handler };\n}\n\nexport const RoomInternalState = {\n CREATING: 0,\n CREATED: 1,\n DISPOSING: 2,\n} as const;\nexport type RoomInternalState = (typeof RoomInternalState)[keyof typeof RoomInternalState];\n\nexport type OnCreateOptions<T extends Type<Room>> = Parameters<NonNullable<InstanceType<T>['onCreate']>>[0];\n\n/**\n * A Room class is meant to implement a game session, and/or serve as the communication channel\n * between a group of clients.\n *\n * - Rooms are created on demand during matchmaking by default\n * - Room classes must be exposed using `.define()`\n *\n * @example\n * ```typescript\n * class MyRoom extends Room<{\n * state: MyState,\n * metadata: { difficulty: string },\n * client: MyClient\n * }> {\n * // ...\n * }\n * ```\n */\nexport class Room<T extends RoomOptions = RoomOptions> {\n '~client': ExtractRoomClient<T>;\n '~state': ExtractRoomState<T>;\n '~metadata': ExtractRoomMetadata<T>;\n\n /**\n * This property will change on these situations:\n * - The maximum number of allowed clients has been reached (`maxClients`)\n * - You manually locked, or unlocked the room using lock() or `unlock()`.\n *\n * @readonly\n */\n public get locked() {\n return this.#_locked;\n }\n\n /**\n * Get the room's matchmaking metadata.\n */\n public get metadata(): ExtractRoomMetadata<T> {\n return this._listing.metadata;\n }\n\n /**\n * Set the room's matchmaking metadata.\n *\n * **Note**: This setter does NOT automatically persist. Use `setMatchmaking()` for automatic persistence.\n *\n * @example\n * ```typescript\n * class MyRoom extends Room<{ metadata: { difficulty: string; rating: number } }> {\n * async onCreate() {\n * this.metadata = { difficulty: \"hard\", rating: 1500 };\n * }\n * }\n * ```\n */\n public set metadata(meta: ExtractRoomMetadata<T>) {\n if (this._internalState !== RoomInternalState.CREATING) {\n // prevent user from setting metadata after room has been created.\n throw new ServerError(ErrorCode.APPLICATION_ERROR, \"'metadata' can only be manually set during onCreate(). Use setMatchmaking() instead.\");\n }\n\n this._listing.metadata = meta;\n }\n\n /**\n * The room listing cache for matchmaking.\n * @internal\n */\n private _listing: IRoomCache<ExtractRoomMetadata<T>>;\n\n /**\n * Timing events tied to the room instance.\n * Intervals and timeouts are cleared when the room is disposed.\n */\n public clock: Clock = new Clock();\n\n #_roomId: string;\n #_roomName: string;\n #_onLeaveConcurrent: number = 0; // number of onLeave calls in progress\n\n /**\n * Maximum number of clients allowed to connect into the room. When room reaches this limit,\n * it is locked automatically. Unless the room was explicitly locked by you via `lock()` method,\n * the room will be unlocked as soon as a client disconnects from it.\n */\n public maxClients: number = Infinity;\n #_maxClientsReached: boolean = false;\n #_maxClients: number;\n\n /**\n * Automatically dispose the room when last client disconnects.\n *\n * @default true\n */\n public autoDispose: boolean = true;\n #_autoDispose: boolean;\n\n /**\n * Frequency to send the room state to connected clients, in milliseconds.\n *\n * @default 50ms (20fps)\n */\n public patchRate: number | null = DEFAULT_PATCH_RATE;\n #_patchRate: number;\n #_patchInterval: NodeJS.Timeout;\n\n /**\n * Maximum number of messages a client can send to the server per second.\n * If a client sends more messages than this, it will be disconnected.\n *\n * @default Infinity\n */\n public maxMessagesPerSecond: number = Infinity;\n\n /**\n * The state instance you provided to `setState()`.\n */\n public state: ExtractRoomState<T>;\n #_state: ExtractRoomState<T>;\n\n /**\n * The presence instance. Check Presence API for more details.\n *\n * @see [Presence API](https://docs.colyseus.io/server/presence)\n */\n public presence: Presence;\n\n /**\n * The array of connected clients.\n *\n * @see [Client instance](https://docs.colyseus.io/room#client)\n */\n public clients: ClientArray<ExtractRoomClient<T>> = new ClientArray();\n\n /**\n * Set the number of seconds a room can wait for a client to effectively join the room.\n * You should consider how long your `onAuth()` will have to wait for setting a different seat reservation time.\n * The default value is 15 seconds. You may set the `COLYSEUS_SEAT_RESERVATION_TIME`\n * environment variable if you'd like to change the seat reservation time globally.\n *\n * @default 15 seconds\n */\n public seatReservationTimeout: number = DEFAULT_SEAT_RESERVATION_TIME;\n\n private _events = new EventEmitter();\n\n private _reservedSeats: { [sessionId: string]: [any, any, boolean?, boolean?] } = {};\n private _reservedSeatTimeouts: { [sessionId: string]: NodeJS.Timeout } = {};\n\n private _reconnections: { [reconnectionToken: string]: [string, Deferred] } = {};\n private _reconnectionAttempts: { [reconnectionToken: string]: Deferred } = {};\n\n public messages?: Messages<any>;\n\n private onMessageEvents = createNanoEvents();\n private onMessageValidators: {[message: string]: StandardSchemaV1} = {};\n\n private onMessageFallbacks = {\n '__no_message_handler': (client: ExtractRoomClient<T>, messageType: string | number, _: unknown) => {\n const errorMessage = `room onMessage for \"${messageType}\" not registered.`;\n debugMessage(`${errorMessage} (roomId: ${this.roomId})`);\n\n if (isDevMode) {\n // send error code to client in development mode\n client.error(ErrorCode.INVALID_PAYLOAD, errorMessage);\n\n } else {\n // immediately close the connection in production\n client.leave(CloseCode.WITH_ERROR, errorMessage);\n }\n }\n };\n\n private _serializer: Serializer<ExtractRoomState<T>> = noneSerializer;\n private _afterNextPatchQueue: Array<[string | number | ExtractRoomClient<T>, ArrayLike<any>]> = [];\n\n private _simulationInterval: NodeJS.Timeout;\n\n private _internalState: RoomInternalState = RoomInternalState.CREATING;\n\n private _lockedExplicitly: boolean = false;\n #_locked: boolean = false;\n\n // this timeout prevents rooms that are created by one process, but no client\n // ever had success joining into it on the specified interval.\n private _autoDisposeTimeout: NodeJS.Timeout;\n\n constructor() {\n this._events.once('dispose', () => {\n this.#_dispose()\n .catch((e) => debugAndPrintError(`onDispose error: ${(e && e.stack || e.message || e || 'promise rejected')} (roomId: ${this.roomId})`))\n .finally(() => this._events.emit('disconnect'));\n });\n\n /**\n * If `onUncaughtException` is defined, it will automatically catch exceptions\n */\n if (this.onUncaughtException !== undefined) {\n this.#registerUncaughtExceptionHandlers();\n }\n }\n\n /**\n * This method is called by the MatchMaker before onCreate()\n * @internal\n */\n private __init() {\n this.#_state = this.state;\n this.#_autoDispose = this.autoDispose;\n this.#_patchRate = this.patchRate;\n this.#_maxClients = this.maxClients;\n\n Object.defineProperties(this, {\n state: {\n enumerable: true,\n get: () => this.#_state,\n set: (newState: ExtractRoomState<T>) => {\n if (newState?.constructor[Symbol.metadata] !== undefined || newState[$changes] !== undefined) {\n this.setSerializer(new SchemaSerializer());\n } else if ('_definition' in newState) {\n throw new Error(\"@colyseus/schema v2 compatibility currently missing (reach out if you need it)\");\n } else if ($changes === undefined) {\n throw new Error(\"Multiple @colyseus/schema versions detected. Please make sure you don't have multiple versions of @colyseus/schema installed.\");\n }\n this._serializer.reset(newState);\n this.#_state = newState;\n },\n },\n\n maxClients: {\n enumerable: true,\n get: () => this.#_maxClients,\n set: (value: number) => {\n this.setMatchmaking({ maxClients: value });\n },\n },\n\n autoDispose: {\n enumerable: true,\n get: () => this.#_autoDispose,\n set: (value: boolean) => {\n if (\n value !== this.#_autoDispose &&\n this._internalState !== RoomInternalState.DISPOSING\n ) {\n this.#_autoDispose = value;\n this.resetAutoDisposeTimeout();\n }\n },\n },\n\n patchRate: {\n enumerable: true,\n get: () => this.#_patchRate,\n set: (milliseconds: number) => {\n this.#_patchRate = milliseconds;\n // clear previous interval in case called setPatchRate more than once\n if (this.#_patchInterval) {\n clearInterval(this.#_patchInterval);\n this.#_patchInterval = undefined;\n }\n if (milliseconds !== null && milliseconds !== 0) {\n this.#_patchInterval = setInterval(() => this.broadcastPatch(), milliseconds);\n } else if (!this._simulationInterval) {\n // When patchRate and no simulation interval are both set to 0, tick the clock to keep timers working\n this.#_patchInterval = setInterval(() => this.clock.tick(), DEFAULT_SIMULATION_INTERVAL);\n }\n },\n },\n });\n\n // set patch interval, now with the setter\n this.patchRate = this.#_patchRate;\n\n // set state, now with the setter\n if (this.#_state) {\n this.state = this.#_state;\n }\n\n // Bind messages to the room\n if (this.messages !== undefined) {\n\n // Handle \"_\" as a fallback handler\n if (this.messages['_']) {\n this.onMessage('*', (this.messages['_'] as Function).bind(this));\n delete this.messages['_'];\n }\n\n Object.entries(this.messages).forEach(([messageType, callback]) => {\n if (typeof callback === 'function') {\n // Direct handler function - bind to room instance\n this.onMessage(messageType, callback.bind(this) as any);\n } else {\n // Object with format and handler - bind handler to room instance\n this.onMessage(messageType, callback.format, callback.handler.bind(this));\n }\n });\n }\n\n // set default _autoDisposeTimeout\n this.resetAutoDisposeTimeout(this.seatReservationTimeout);\n\n this.clock.start();\n }\n\n /**\n * The name of the room you provided as first argument for `gameServer.define()`.\n *\n * @returns roomName string\n */\n public get roomName() { return this.#_roomName; }\n /**\n * Setting the name of the room. Overwriting this property is restricted.\n *\n * @param roomName\n */\n public set roomName(roomName: string) {\n if (this.#_roomName) {\n // prevent user from setting roomName after it has been defined.\n throw new ServerError(ErrorCode.APPLICATION_ERROR, \"'roomName' cannot be overwritten.\");\n }\n this.#_roomName = roomName;\n }\n\n /**\n * A unique, auto-generated, 9-character-long id of the room.\n * You may replace `this.roomId` during `onCreate()`.\n *\n * @returns roomId string\n */\n public get roomId() { return this.#_roomId; }\n\n /**\n * Setting the roomId, is restricted in room lifetime except upon room creation.\n *\n * @param roomId\n * @returns roomId string\n */\n public set roomId(roomId: string) {\n if (this._internalState !== RoomInternalState.CREATING && !isDevMode) {\n // prevent user from setting roomId after room has been created.\n throw new ServerError(ErrorCode.APPLICATION_ERROR, \"'roomId' can only be overridden upon room creation.\");\n }\n this.#_roomId = roomId;\n }\n\n // Optional abstract methods\n\n /**\n * This method is called before the latest version of the room's state is broadcasted to all clients.\n */\n public onBeforePatch?(state: ExtractRoomState<T>): void | Promise<any>;\n\n /**\n * This method is called when the room is created.\n * @param options - The options passed to the room when it is created.\n */\n public onCreate?(options: any): void | Promise<any>;\n\n /**\n * This method is called when a client joins the room.\n * @param client - The client that joined the room.\n * @param options - The options passed to the client when it joined the room.\n * @param auth - The data returned by the `onAuth` method - (Deprecated: use `client.auth` instead)\n */\n public onJoin?(client: ExtractRoomClient<T>, options?: any, auth?: any): void | Promise<any>;\n\n /**\n * This method is called when a client leaves the room without consent.\n * You may allow the client to reconnect by calling `allowReconnection` within this method.\n *\n * @param client - The client that was dropped from the room.\n * @param code - The close code of the leave event.\n */\n public onDrop?(client: ExtractRoomClient<T>, code?: number): void | Promise<any>;\n\n /**\n * This method is called when a client reconnects to the room.\n * @param client - The client that reconnected to the room.\n */\n public onReconnect?(client: ExtractRoomClient<T>): void | Promise<any>;\n\n /**\n * This method is called when a client effectively leaves the room.\n * @param client - The client that left the room.\n * @param code - The close code of the leave event.\n */\n public onLeave?(client: ExtractRoomClient<T>, code?: number): void | Promise<any>;\n\n /**\n * This method is called when the room is disposed.\n */\n public onDispose?(): void | Promise<any>;\n\n /**\n * Define a custom exception handler.\n * If defined, all lifecycle hooks will be wrapped by try/catch, and the exception will be forwarded to this method.\n *\n * These methods will be wrapped by try/catch:\n * - `onMessage`\n * - `onAuth` / `onJoin` / `onLeave` / `onCreate` / `onDispose`\n * - `clock.setTimeout` / `clock.setInterval`\n * - `setSimulationInterval`\n *\n * (Experimental: this feature is subject to change in the future - we're currently getting feedback to improve it)\n */\n public onUncaughtException?(error: RoomException, methodName: RoomMethodName): void;\n\n /**\n * This method is called before onJoin() - this is where you should authenticate the client\n * @param client - The client that is authenticating.\n * @param options - The options passed to the client when it is authenticating.\n * @param context - The authentication context, including the token and the client's IP address.\n * @returns The authentication result.\n *\n * @example\n * ```typescript\n * return {\n * userId: 123,\n * username: \"John Doe\",\n * email: \"john.doe@example.com\",\n * };\n * ```\n */\n public onAuth(\n client: Client,\n options: any,\n context: AuthContext\n ): any | Promise<any> {\n return true;\n }\n\n static async onAuth(\n token: string,\n options: any,\n context: AuthContext\n ): Promise<unknown> {\n return true;\n }\n\n /**\n * This method is called during graceful shutdown of the server process\n * You may override this method to dispose the room in your own way.\n *\n * Once process reaches room count of 0, the room process will be terminated.\n */\n public onBeforeShutdown() {\n this.disconnect(\n (isDevMode)\n ? CloseCode.MAY_TRY_RECONNECT\n : CloseCode.SERVER_SHUTDOWN\n ).catch(() => {});\n }\n\n /**\n * devMode: When `devMode` is enabled, `onCacheRoom` method is called during\n * graceful shutdown.\n *\n * Implement this method to return custom data to be cached. `onRestoreRoom`\n * will be called with the data returned by `onCacheRoom`\n */\n public onCacheRoom?(): any;\n\n /**\n * devMode: When `devMode` is enabled, `onRestoreRoom` method is called during\n * process startup, with the data returned by the `onCacheRoom` method.\n */\n public onRestoreRoom?(cached?: any): void;\n\n /**\n * Returns whether the sum of connected clients and reserved seats exceeds maximum number of clients.\n *\n * @returns boolean\n */\n public hasReachedMaxClients(): boolean {\n return (\n (this.clients.length + Object.keys(this._reservedSeats).length) >= this.#_maxClients ||\n this._internalState === RoomInternalState.DISPOSING\n );\n }\n\n /**\n * @deprecated Use `seatReservationTimeout=` instead.\n */\n public setSeatReservationTime(seconds: number) {\n console.warn(`DEPRECATED: .setSeatReservationTime(${seconds}) is deprecated. Assign a .seatReservationTimeout property value instead.`);\n this.seatReservationTimeout = seconds;\n return this;\n }\n\n public hasReservedSeat(sessionId: string, reconnectionToken?: string): boolean {\n const reservedSeat = this._reservedSeats[sessionId];\n\n if (reservedSeat) {\n // seat reservation is present\n return (\n // not consumed\n (reservedSeat[2] === false) ||\n // reconnection is allowed and the reconnection token is valid.\n (reservedSeat[3] && this._reconnections[reconnectionToken]?.[0] === sessionId)\n )\n\n } else if (typeof(reconnectionToken) === \"string\") {\n // potentially a stale client reference, so a reconnection attempt is possible.\n return this.clients.getById(sessionId)?.reconnectionToken === reconnectionToken;\n }\n\n return false;\n }\n\n public checkReconnectionToken(reconnectionToken: string) {\n const sessionId = this._reconnections[reconnectionToken]?.[0];\n const reservedSeat = this._reservedSeats[sessionId];\n\n if (reservedSeat && reservedSeat[3]) {\n return sessionId;\n }\n\n const client = this.clients.find((client) => client.reconnectionToken === reconnectionToken);\n if (client) {\n this.#_forciblyCloseClient(client as ExtractRoomClient<T> & ClientPrivate, CloseCode.WITH_ERROR);\n return client.sessionId;\n }\n\n return undefined;\n }\n\n /**\n * (Optional) Set a simulation interval that can change the state of the game.\n * The simulation interval is your game loop.\n *\n * @default 16.6ms (60fps)\n *\n * @param onTickCallback - You can implement your physics or world updates here!\n * This is a good place to update the room state.\n * @param delay - Interval delay on executing `onTickCallback` in milliseconds.\n */\n public setSimulationInterval(onTickCallback?: SimulationCallback, delay: number = DEFAULT_SIMULATION_INTERVAL): void {\n // clear previous interval in case called setSimulationInterval more than once\n if (this._simulationInterval) { clearInterval(this._simulationInterval); }\n\n if (onTickCallback) {\n if (this.onUncaughtException !== undefined) {\n onTickCallback = wrapTryCatch(onTickCallback, this.onUncaughtException.bind(this), SimulationIntervalException, 'setSimulationInterval');\n }\n\n this._simulationInterval = setInterval(() => {\n this.clock.tick();\n onTickCallback(this.clock.deltaTime);\n }, delay);\n }\n }\n\n /**\n * @deprecated Use `.patchRate=` instead.\n */\n public setPatchRate(milliseconds: number | null): void {\n this.patchRate = milliseconds;\n }\n\n /**\n * @deprecated Use `.state =` instead.\n */\n public setState(newState: ExtractRoomState<T>) {\n this.state = newState;\n }\n\n public setSerializer(serializer: Serializer<ExtractRoomState<T>>) {\n this._serializer = serializer;\n }\n\n public async setMetadata(meta: Partial<ExtractRoomMetadata<T>>, persist: boolean = true) {\n if (!this._listing.metadata) {\n this._listing.metadata = meta as ExtractRoomMetadata<T>;\n\n } else {\n for (const field in meta) {\n if (!meta.hasOwnProperty(field)) { continue; }\n this._listing.metadata[field] = meta[field];\n }\n\n // `MongooseDriver` workaround: persit metadata mutations\n if ('markModified' in this._listing) {\n (this._listing as any).markModified('metadata');\n }\n }\n\n if (persist && this._internalState === RoomInternalState.CREATED) {\n await matchMaker.driver.persist(this._listing);\n\n // emit metadata-change event to update lobby listing\n this._events.emit('metadata-change');\n }\n }\n\n public async setPrivate(bool: boolean = true, persist: boolean = true) {\n if (this._listing.private === bool) return;\n\n this._listing.private = bool;\n\n if (persist && this._internalState === RoomInternalState.CREATED) {\n await matchMaker.driver.persist(this._listing);\n }\n\n // emit visibility-change event to update lobby listing\n this._events.emit('visibility-change', bool);\n }\n\n /**\n * Update multiple matchmaking/listing properties at once with a single persist operation.\n * This is the recommended way to update room listing properties.\n *\n * @param updates - Object containing the properties to update\n *\n * @example\n * ```typescript\n * // Update multiple properties at once\n * await this.setMatchmaking({\n * metadata: { difficulty: \"hard\", rating: 1500 },\n * private: true,\n * locked: true,\n * maxClients: 10\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Update only metadata\n * await this.setMatchmaking({\n * metadata: { status: \"in_progress\" }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Partial metadata update (merges with existing)\n * await this.setMatchmaking({\n * metadata: { ...this.metadata, round: this.metadata.round + 1 }\n * });\n * ```\n */\n public async setMatchmaking(updates: {\n metadata?: ExtractRoomMetadata<T>;\n private?: boolean;\n locked?: boolean;\n maxClients?: number;\n unlisted?: boolean;\n [key: string]: any;\n }) {\n for (const key in updates) {\n if (!updates.hasOwnProperty(key)) { continue; }\n\n switch (key) {\n case 'metadata': {\n this.setMetadata(updates.metadata, false);\n break;\n }\n\n case 'private': {\n this.setPrivate(updates.private, false);\n break;\n }\n\n case 'locked': {\n if (updates[key]) {\n // @ts-ignore\n this.lock.call(this, true);\n this._lockedExplicitly = true;\n } else {\n // @ts-ignore\n this.unlock.call(this, true);\n this._lockedExplicitly = false;\n }\n break;\n }\n\n case 'maxClients': {\n this.#_maxClients = updates.maxClients;\n this._listing.maxClients = updates.maxClients;\n\n const hasReachedMaxClients = this.hasReachedMaxClients();\n\n // unlock room if maxClients has been increased\n if (!this._lockedExplicitly && this.#_maxClientsReached && !hasReachedMaxClients) {\n this.#_maxClientsReached = false;\n this.#_locked = false;\n this._listing.locked = false;\n updates.locked = false;\n }\n\n // lock room if maxClients has been decreased\n if (hasReachedMaxClients) {\n this.#_maxClientsReached = true;\n this.#_locked = true;\n this._listing.locked = true;\n updates.locked = true;\n }\n\n break;\n }\n\n case 'clients': {\n console.warn(\"setMatchmaking() does not allow updating 'clients' property.\");\n break;\n }\n\n default: {\n // Allow any other listing properties to be updated\n this._listing[key] = updates[key];\n break;\n }\n }\n }\n\n // Only persist if room is not CREATING\n if (this._internalState === RoomInternalState.CREATED) {\n await matchMaker.driver.update(this._listing, { $set: updates });\n\n // emit metadata-change event to update lobby listing\n this._events.emit('metadata-change');\n }\n }\n\n /**\n * Lock the room. This prevents new clients from joining this room.\n */\n public async lock() {\n // rooms locked internally aren't explicit locks.\n this._lockedExplicitly = (arguments[0] === undefined);\n\n // skip if already locked.\n if (this.#_locked) { return; }\n\n this.#_locked = true;\n\n // Only persist if this is an explicit lock/unlock\n if (this._lockedExplicitly) {\n await matchMaker.driver.update(this._listing, {\n $set: { locked: this.#_locked },\n });\n }\n\n this._events.emit('lock');\n }\n\n /**\n * Unlock the room. This allows new clients to join this room, if maxClients is not reached.\n */\n public async unlock() {\n // only internal usage passes arguments to this function.\n if (arguments[0] === undefined) {\n this._lockedExplicitly = false;\n }\n\n // skip if already locked\n if (!this.#_locked) { return; }\n\n this.#_locked = false;\n\n // Only persist if this is an explicit lock/unlock\n if (arguments[0] === undefined) {\n await matchMaker.driver.update(this._listing, {\n $set: { locked: this.#_locked },\n });\n }\n\n this._events.emit('unlock');\n }\n\n /**\n * @deprecated Use `client.send(...)` instead.\n */\n public send(client: Client, type: string | number, message: any, options?: ISendOptions): void;\n public send(client: Client, messageOrType: any, messageOrOptions?: any | ISendOptions, options?: ISendOptions): void {\n logger.warn('DEPRECATION WARNING: use client.send(...) instead of this.send(client, ...)');\n client.send(messageOrType, messageOrOptions, options);\n }\n\n /**\n * Broadcast a message to all connected clients.\n * @param type - The type of the message.\n * @param message - The message to broadcast.\n * @param options - The options for the broadcast.\n *\n * @example\n * ```typescript\n * this.broadcast('message', { message: 'Hello, world!' });\n * ```\n */\n public broadcast<K extends keyof ExtractRoomClient<T>['~messages'] & string | number>(\n type: K,\n ...args: MessageArgs<ExtractRoomClient<T>['~messages'][K], IBroadcastOptions>\n ) {\n const [message, options] = args;\n if (options && options.afterNextPatch) {\n delete options.afterNextPatch;\n this._afterNextPatchQueue.push(['broadcast', [type, ...args]]);\n return;\n }\n\n this.broadcastMessageType(type, message, options);\n }\n\n /**\n * Broadcast bytes (UInt8Arrays) to a particular room\n */\n public broadcastBytes(type: string | number, message: Uint8Array, options: IBroadcastOptions) {\n if (options && options.afterNextPatch) {\n delete options.afterNextPatch;\n this._afterNextPatchQueue.push(['broadcastBytes', arguments]);\n return;\n }\n\n this.broadcastMessageType(type as string, message, options);\n }\n\n /**\n * Checks whether mutations have occurred in the state, and broadcast them to all connected clients.\n */\n public broadcastPatch() {\n if (this.onBeforePatch) {\n this.onBeforePatch(this.state);\n }\n\n if (!this._simulationInterval) {\n this.clock.tick();\n }\n\n if (!this.state) {\n return false;\n }\n\n const hasChanges = this._serializer.applyPatches(this.clients, this.state);\n\n // broadcast messages enqueued for \"after patch\"\n this._dequeueAfterPatchMessages();\n\n return hasChanges;\n }\n\n /**\n * Register a message handler for a specific message type.\n * This method is used to handle messages sent by clients to the room.\n * @param messageType - The type of the message.\n * @param callback - The callback to call when the message is received.\n * @returns A function to unbind the callback.\n *\n * @example\n * ```typescript\n * this.onMessage('message', (client, message) => {\n * console.log(message);\n * });\n * ```\n *\n * @example\n * ```typescript\n * const unbind = this.onMessage('message', (client, message) => {\n * console.log(message);\n * });\n *\n * // Unbind the callback when no longer needed\n * unbind();\n * ```\n */\n public onMessage<T = any, C extends Client = ExtractRoomClient<T>>(\n messageType: '*',\n callback: (client: C, type: string | number, message: T) => void\n );\n public onMessage<T = any, C extends Client = ExtractRoomClient<T>>(\n messageType: string | number,\n callback: (client: C, message: T) => void,\n );\n public onMessage<T = any, C extends Client = ExtractRoomClient<T>>(\n messageType: string | number,\n validationSchema: StandardSchemaV1<T>,\n callback: (client: C, message: T) => void,\n );\n public onMessage<T = any>(\n _messageType: '*' | string | number,\n _validationSchema: StandardSchemaV1<T> | ((...args: any[]) => void),\n _callback?: (...args: any[]) => void,\n ) {\n const messageType = _messageType.toString();\n\n const validationSchema = (typeof _callback === 'function')\n ? _validationSchema as StandardSchemaV1<T>\n : undefined;\n\n const callback = (validationSchema === undefined)\n ? _validationSchema as (...args: any[]) => void\n : _callback;\n\n const removeListener = this.onMessageEvents.on(messageType, (this.onUncaughtException !== undefined)\n ? wrapTryCatch(callback, this.onUncaughtException.bind(this), OnMessageException, 'onMessage', false, _messageType)\n : callback);\n\n if (validationSchema !== undefined) {\n this.onMessageValidators[messageType] = validationSchema;\n }\n\n // returns a method to unbind the callback\n return () => {\n removeListener();\n if (this.onMessageEvents.events[messageType].length === 0) {\n delete this.onMessageValidators[messageType];\n }\n };\n }\n\n public onMessageBytes<T = any, C extends Client = ExtractRoomClient<T>>(\n // public onMessageBytes<T = any, C extends Client = TClient>(\n messageType: string | number,\n callback: (client: C, message: T) => void,\n );\n public onMessageBytes<T = any, C extends Client = ExtractRoomClient<T>>(\n // public onMessageBytes<T = any, C extends Client = TClient>(\n messageType: string | number,\n validationSchema: StandardSchemaV1<T>,\n callback: (client: C, message: T) => void,\n );\n public onMessageBytes<T = any>(\n _messageType: string | number,\n _validationSchema: StandardSchemaV1<T> | ((...args: any[]) => void),\n _callback?: (...args: any[]) => void,\n ) {\n const messageType = `_$b${_messageType}`;\n\n const validationSchema = (typeof _callback === 'function')\n ? _validationSchema as StandardSchemaV1<T>\n : undefined;\n\n const callback = (validationSchema === undefined)\n ? _validationSchema as (...args: any[]) => void\n : _callback;\n\n if (validationSchema !== undefined) {\n return this.onMessage(messageType, validationSchema as any, callback as any);\n } else {\n return this.onMessage(messageType, callback as any);\n }\n }\n\n /**\n * Disconnect all connected clients, and then dispose the room.\n *\n * @param closeCode WebSocket close code (default = 4000, which is a \"consented leave\")\n * @returns Promise<void>\n */\n public disconnect(closeCode: number = CloseCode.CONSENTED): Promise<any> {\n // skip if already disposing\n if (this._internalState === RoomInternalState.DISPOSING) {\n return Promise.resolve(`disconnect() ignored: room (${this.roomId}) is already disposing.`);\n\n } else if (this._internalState === RoomInternalState.CREATING) {\n throw new Error(\"cannot disconnect during onCreate()\");\n }\n\n this._internalState = RoomInternalState.DISPOSING;\n matchMaker.driver.remove(this._listing.roomId);\n\n this.#_autoDispose = true;\n\n const delayedDisconnection = new Promise<void>((resolve) =>\n this._events.once('disconnect', () => resolve()));\n\n // reject pending reconnections\n this._rejectPendingReconnections(\"disconnecting\");\n\n let numClients = this.clients.length;\n if (numClients > 0) {\n // clients may have `async onLeave`, room will be disposed after they're fulfilled\n while (numClients--) {\n this.#_forciblyCloseClient(this.clients[numClients] as ExtractRoomClient<T> & ClientPrivate, closeCode);\n }\n\n } else {\n // no clients connected, dispose immediately.\n this._events.emit('dispose');\n }\n\n return delayedDisconnection;\n }\n\n private _rejectPendingReconnections(message: string) {\n for (const [_, reconnection] of Object.values(this._reconnections)) {\n reconnection.reject(new ServerError(CloseCode.NORMAL_CLOSURE, message));\n // Suppress unhandled rejection \u2014 expected during shutdown/devMode\n // restart, handled downstream by _onLeave's .catch() handler.\n reconnection.catch(() => {});\n }\n }\n\n private async _onJoin(\n client: ExtractRoomClient<T> & ClientPrivate,\n authContext: AuthContext,\n connectionOptions?: { reconnectionToken?: string, skipHandshake?: boolean }\n ) {\n const sessionId = client.sessionId;\n\n // generate unique private reconnection token\n // (each new reconnection receives a new reconnection token)\n client.reconnectionToken = generateId();\n\n if (this._reservedSeatTimeouts[sessionId]) {\n clearTimeout(this._reservedSeatTimeouts[sessionId]);\n delete this._reservedSeatTimeouts[sessionId];\n }\n\n // clear auto-dispose timeout.\n if (this._autoDisposeTimeout) {\n clearTimeout(this._autoDisposeTimeout);\n this._autoDisposeTimeout = undefined;\n }\n\n //\n // user may be trying to reconnect while the old connection is still open (stale)\n // (e.g. during network switches, where the old connection is still open while a new reconnection attempt is being made)\n //\n if (\n this._reservedSeats[sessionId] === undefined &&\n connectionOptions?.reconnectionToken &&\n this.clients.getById(sessionId)?.reconnectionToken === connectionOptions.reconnectionToken\n ) {\n debugMatchMaking('attempting to reconnect client with a stale previous connection - sessionId: \\'%s\\', roomId: \\'%s\\'', client.sessionId, this.roomId);\n this._reconnectionAttempts[connectionOptions.reconnectionToken] = new Deferred();\n\n const reconnectionAttemptTimeout = setTimeout(() => {\n this._reconnectionAttempts[connectionOptions.reconnectionToken]?.reject(new ServerError(CloseCode.MAY_TRY_RECONNECT, 'Reconnection attempt timed out'));\n }, this.seatReservationTimeout * 1000);\n\n const cleanup = () => {\n clearTimeout(reconnectionAttemptTimeout);\n delete this._reconnectionAttempts[connectionOptions.reconnectionToken];\n }\n\n await this._reconnectionAttempts[connectionOptions.reconnectionToken]\n .then(() => cleanup())\n .catch(() => cleanup());\n\n if (!this._reservedSeats[sessionId]) {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, \"failed to reconnect\");\n }\n }\n\n // get seat reservation options and clear it\n const [joinOptions, authData, isConsumed, isWaitingReconnection] = this._reservedSeats[sessionId];\n\n //\n // TODO: remove this check on 1.0.0\n // - the seat reservation is used to keep track of number of clients and their pending seats (see `hasReachedMaxClients`)\n // - when we fully migrate to static onAuth(), the seat reservation can be removed immediately here\n // - if async onAuth() is in use, the seat reservation is removed after onAuth() is fulfilled.\n // - mark reservation as \"consumed\"\n //\n if (isConsumed) {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, \"already consumed\");\n }\n this._reservedSeats[sessionId][2] = true; // flag seat reservation as \"consumed\"\n debugMatchMaking('consuming seat reservation, sessionId: \\'%s\\' (roomId: %s)', client.sessionId, this.roomId);\n\n // share \"after next patch queue\" reference with every client.\n client._afterNextPatchQueue = this._afterNextPatchQueue;\n\n // add temporary callback to keep track of disconnections during `onJoin`.\n client.ref['onleave'] = (_) => client.state = ClientState.LEAVING;\n client.ref.once('close', client.ref['onleave']);\n\n if (isWaitingReconnection) {\n const reconnectionToken = connectionOptions?.reconnectionToken;\n if (reconnectionToken && this._reconnections[reconnectionToken]?.[0] === sessionId) {\n this.clients.push(client);\n\n //\n // await for reconnection:\n // (end user may customize the reconnection token at this step)\n //\n await this._reconnections[reconnectionToken]?.[1].resolve(client);\n\n try {\n if (this.onReconnect) {\n await this.onReconnect(client);\n }\n\n // FIXME: we shouldn't rely on WebSocket specific API here (make it transport agnostic)\n if (client.readyState !== WebSocket.OPEN) {\n throw new Error(\"reconnection denied\");\n }\n\n // client.leave() may have been called during onReconnect()\n if (client.state === ClientState.RECONNECTING) {\n // switch client state from RECONNECTING to JOINING\n // (to allow to attach messages to the client again)\n client.state = ClientState.JOINING;\n }\n\n } catch (e) {\n await this._onLeave(client, CloseCode.FAILED_TO_RECONNECT);\n throw e;\n }\n\n } else {\n const errorMessage = (process.env.NODE_ENV === 'production')\n ? \"already consumed\" // trick possible fraudsters...\n : \"bad reconnection token\" // ...or developers\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, errorMessage);\n }\n\n } else {\n try {\n if (authData) {\n client.auth = authData;\n\n } else if (this.onAuth !== Room.prototype.onAuth) {\n try {\n client.auth = await this.onAuth(client, joinOptions, authContext);\n\n if (!client.auth) {\n throw new ServerError(ErrorCode.AUTH_FAILED, 'onAuth failed');\n }\n\n } catch (e) {\n // remove seat reservation\n delete this._reservedSeats[sessionId];\n await this.#_decrementClientCount();\n throw e;\n }\n }\n\n //\n // On async onAuth, client may have been disconnected.\n //\n if (client.state === ClientState.LEAVING) {\n throw new ServerError(CloseCode.WITH_ERROR, 'already disconnected');\n }\n\n this.clients.push(client);\n\n //\n // Flag sessionId as non-enumarable so hasReachedMaxClients() doesn't count it\n // (https://github.com/colyseus/colyseus/issues/726)\n //\n Object.defineProperty(this._reservedSeats, sessionId, {\n value: this._reservedSeats[sessionId],\n enumerable: false,\n });\n\n if (this.onJoin) {\n // TODO: deprecate auth as 3rd argument on Colyseus 1.0\n await this.onJoin(client, joinOptions, client.auth);\n }\n\n // @ts-ignore: client left during `onJoin`, call _onLeave immediately.\n if (client.state === ClientState.LEAVING) {\n throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, \"early_leave\");\n\n } else {\n // remove seat reservation\n delete this._reservedSeats[sessionId];\n\n // emit 'join' to room handler\n this._events.emit('join', client);\n }\n\n } catch (e: any) {\n await this._onLeave(client, CloseCode.WITH_ERROR);\n\n // remove seat reservation\n delete this._reservedSeats[sessionId];\n\n // make sure an error code is provided.\n if (!e.code) {\n e.code = ErrorCode.APPLICATION_ERROR;\n }\n\n throw e;\n }\n }\n\n // state might already be ClientState.LEAVING here\n if (client.state === ClientState.JOINING) {\n client.ref.removeListener('close', client.ref['onleave']);\n\n // only bind _onLeave after onJoin has been successful\n client.ref['onleave'] = this._onLeave.bind(this, client);\n client.ref.once('close', client.ref['onleave']);\n\n // allow client to send messages after onJoin has succeeded.\n client.ref.on('message', this._onMessage.bind(this, client));\n\n // confirm room id that matches the room name requested to join\n client.raw(getMessageBytes[Protocol.JOIN_ROOM](\n client.reconnectionToken,\n this._serializer.id,\n /**\n * if skipHandshake is true, we don't need to send the handshake\n * (in case client already has handshake data)\n */\n (connectionOptions?.skipHandshake)\n ? undefined\n : this._serializer.handshake && this._serializer.handshake(),\n ));\n }\n }\n\n /**\n * Allow the specified client to reconnect into the room. Must be used inside `onLeave()` method.\n * If seconds is provided, the reconnection is going to be cancelled after the provided amount of seconds.\n *\n * @param client - The client that is allowed to reconnect into the room.\n * @param seconds - The time in seconds that the client is allowed to reconnect into the room.\n *\n * @returns Deferred<Client> - The differed is a promise like type.\n * This type can forcibly reject the promise by calling `.reject()`.\n *\n * @example\n * ```typescript\n * onDrop(client: Client, code: CloseCode) {\n * // Allow the client to reconnect into the room with a 15 seconds timeout.\n * this.allowReconnection(client, 15);\n * }\n * ```\n */\n public allowReconnection(previousClient: Client, seconds: number | \"manual\"): Deferred<Client> {\n //\n // Return rejected promise if client has never fully JOINED.\n //\n // (having `_enqueuedMessages !== undefined` means that the client has never been at \"ClientState.JOINED\" state)\n //\n if ((previousClient as unknown as ClientPrivate)._enqueuedMessages !== undefined) {\n // @ts-ignore\n return Promise.reject(new ServerError(\"not joined\"));\n }\n\n if (seconds === undefined) { // TODO: remove this check\n console.warn(\"DEPRECATED: allowReconnection() requires a second argument. Using \\\"manual\\\" mode.\");\n seconds = \"manual\";\n }\n\n if (seconds === \"manual\") {\n seconds = Infinity;\n }\n\n if (this._internalState === RoomInternalState.DISPOSING) {\n // @ts-ignore\n return Promise.reject(new Error(\"disposing\"));\n }\n\n const sessionId = previousClient.sessionId;\n const reconnectionToken = previousClient.reconnectionToken;\n\n //\n // prevent duplicate .allowReconnection() calls\n // (may occur during network switches, where the old connection is still\n // open while a new reconnection attempt is being made)\n //\n if (this._reconnections[reconnectionToken]) {\n debugMatchMaking('skipping duplicate .allowReconnection() call for client - sessionId: \\'%s\\', roomId: \\'%s\\'', sessionId, this.roomId);\n return this._reconnections[reconnectionToken][1];\n }\n\n this._reserveSeat(sessionId, true, previousClient.auth, seconds, true);\n\n // keep reconnection reference in case the user reconnects into this room.\n const reconnection = new Deferred<Client & ClientPrivate>();\n this._reconnections[reconnectionToken] = [sessionId, reconnection];\n\n if (seconds !== Infinity) {\n // expire seat reservation after timeout\n this._reservedSeatTimeouts[sessionId] = setTimeout(() =>\n reconnection.reject(false), seconds * 1000);\n }\n\n const cleanup = () => {\n delete this._reconnections[reconnectionToken];\n delete this._reservedSeats[sessionId];\n delete this._reservedSeatTimeouts[sessionId];\n };\n\n reconnection.then((newClient) => {\n newClient.auth = previousClient.auth;\n newClient.userData = previousClient.userData;\n newClient.view = previousClient.view;\n newClient.state = ClientState.RECONNECTING;\n\n // for convenience: populate previous client reference with new client\n previousClient.state = ClientState.RECONNECTED;\n previousClient.ref = newClient.ref;\n previousClient.reconnectionToken = newClient.reconnectionToken;\n clearTimeout(this._reservedSeatTimeouts[sessionId]);\n\n }, () => {\n this.resetAutoDisposeTimeout();\n\n }).finally(() => {\n cleanup();\n });\n\n //\n // If a reconnection attempt is already in progress, resolve it\n //\n // This step ensures reconnection works when network changes (e.g.,\n // switching Wi-Fi), as the original connection may still be open while a\n // new reconnection attempt is being made.\n //\n if (this._reconnectionAttempts[reconnectionToken]) {\n debugMatchMaking('resolving reconnection attempt for client - sessionId: \\'%s\\', roomId: \\'%s\\'', sessionId, this.roomId);\n this._reconnectionAttempts[reconnectionToken].resolve(true);\n }\n\n return reconnection;\n }\n\n private resetAutoDisposeTimeout(timeoutInSeconds: number = 1) {\n clearTimeout(this._autoDisposeTimeout);\n\n if (!this.#_autoDispose) {\n return;\n }\n\n this._autoDisposeTimeout = setTimeout(() => {\n this._autoDisposeTimeout = undefined;\n this.#_disposeIfEmpty();\n }, timeoutInSeconds * 1000);\n }\n\n private broadcastMessageType(type: number | string, message?: any | Uint8Array, options: IBroadcastOptions = {}) {\n debugMessage(\"broadcast: %O (roomId: %s)\", message, this.roomId);\n\n const encodedMessage = (message instanceof Uint8Array)\n ? getMessageBytes.raw(Protocol.ROOM_DATA_BYTES, type, undefined, message)\n : getMessageBytes.raw(Protocol.ROOM_DATA, type, message)\n\n const except = (typeof (options.except) !== \"undefined\")\n ? Array.isArray(options.except)\n ? options.except\n : [options.except]\n : undefined;\n\n let numClients = this.clients.length;\n while (numClients--) {\n const client = this.clients[numClients];\n\n if (!except || !except.includes(client)) {\n client.enqueueRaw(encodedMessage);\n }\n }\n }\n\n private sendFullState(client: Client): void {\n client.raw(this._serializer.getFullState(client));\n }\n\n private _dequeueAfterPatchMessages() {\n const length = this._afterNextPatchQueue.length;\n\n if (length > 0) {\n for (let i = 0; i < length; i++) {\n const [target, args] = this._afterNextPatchQueue[i];\n\n if (target === \"broadcast\") {\n this.broadcast.apply(this, args as any);\n\n } else {\n (target as Client).raw.apply(target, args as any);\n }\n }\n\n // new messages may have been added in the meantime,\n // let's splice the ones that have been processed\n this._afterNextPatchQueue.splice(0, length);\n }\n }\n\n private async _reserveSeat(\n sessionId: string,\n joinOptions: any = true,\n authData: any = undefined,\n seconds: number = this.seatReservationTimeout,\n allowReconnection: boolean = false,\n devModeReconnectionToken?: string,\n ) {\n if (!allowReconnection && this.hasReachedMaxClients()) {\n return false;\n }\n\n debugMatchMaking(\n 'reserving seat on \\'%s\\' - sessionId: \\'%s\\', roomId: \\'%s\\', processId: \\'%s\\'',\n this.roomName, sessionId, this.roomId, matchMaker.processId,\n );\n\n this._reservedSeats[sessionId] = [joinOptions, authData, false, allowReconnection];\n\n if (!allowReconnection) {\n await this.#_incrementClientCount();\n\n this._reservedSeatTimeouts[sessionId] = setTimeout(async () => {\n delete this._reservedSeats[sessionId];\n delete this._reservedSeatTimeouts[sessionId];\n await this.#_decrementClientCount();\n }, seconds * 1000);\n\n this.resetAutoDisposeTimeout(seconds);\n }\n\n if (devModeReconnectionToken) {\n const reconnection = new Deferred<Client & ClientPrivate>();\n this._reconnections[devModeReconnectionToken] = [sessionId, reconnection];\n\n // If the client doesn't reconnect within the timeout, call onLeave\n // so the room can clean up stale state (e.g. delete player data).\n clearTimeout(this._reservedSeatTimeouts[sessionId]);\n this._reservedSeatTimeouts[sessionId] = setTimeout(async () => {\n if (!this._reconnections[devModeReconnectionToken]) { return; }\n\n delete this._reconnections[devModeReconnectionToken];\n delete this._reservedSeats[sessionId];\n delete this._reservedSeatTimeouts[sessionId];\n\n if (!allowReconnection) {\n await this.#_decrementClientCount();\n }\n\n this.onLeave?.({ sessionId } as any, CloseCode.MAY_TRY_RECONNECT);\n }, seconds * 1000);\n }\n\n return true;\n }\n\n private async _reserveMultipleSeats(\n multipleSessionIds: string[],\n multipleJoinOptions: any = true,\n multipleAuthData: any = undefined,\n seconds: number = this.seatReservationTimeout,\n ) {\n let promises: Promise<boolean>[] = [];\n\n for (let i = 0; i < multipleSessionIds.length; i++) {\n promises.push(this._reserveSeat(multipleSessionIds[i], multipleJoinOptions[i], multipleAuthData[i], seconds));\n }\n\n return await Promise.all(promises);\n }\n\n #_disposeIfEmpty() {\n const willDispose = (\n this.#_onLeaveConcurrent === 0 && // no \"onLeave\" calls in progress\n this.#_autoDispose &&\n this._autoDisposeTimeout === undefined &&\n this.clients.length === 0 &&\n Object.keys(this._reservedSeats).length === 0\n );\n\n if (willDispose) {\n this._events.emit('dispose');\n }\n\n return willDispose;\n }\n\n async #_dispose(): Promise<any> {\n this._internalState = RoomInternalState.DISPOSING;\n\n // If the room is still CREATING, the roomId is not yet set.\n if (this._listing?.roomId !== undefined) {\n await matchMaker.driver.remove(this._listing.roomId);\n }\n\n let userReturnData;\n if (this.onDispose) {\n userReturnData = this.onDispose();\n }\n\n if (this.#_patchInterval) {\n clearInterval(this.#_patchInterval);\n this.#_patchInterval = undefined;\n }\n\n if (this._simulationInterval) {\n clearInterval(this._simulationInterval);\n this._simulationInterval = undefined;\n }\n\n if (this._autoDisposeTimeout) {\n clearInterval(this._autoDisposeTimeout);\n this._autoDisposeTimeout = undefined;\n }\n\n // clear all timeouts/intervals + force to stop ticking\n this.clock.clear();\n this.clock.stop();\n\n return await (userReturnData || Promise.resolve());\n }\n\n private _onMessage(client: ExtractRoomClient<T> & ClientPrivate, buffer: Buffer) {\n // skip if client is on LEAVING state.\n if (client.state === ClientState.LEAVING) { return; }\n\n if (!buffer) {\n debugAndPrintError(`${this.roomName} (roomId: ${this.roomId}), couldn't decode message: ${buffer}`);\n return;\n }\n\n // reset message count every second\n if (this.clock.currentTime - client._lastMessageTime >= 1000) {\n client._numMessagesLastSecond = 0;\n client._lastMessageTime = this.clock.currentTime;\n } else if (++client._numMessagesLastSecond > this.maxMessagesPerSecond) {\n // drop client if it sends more messages than the maximum allowed per second\n debugMatchMaking('dropping client - sessionId: \\'%s\\' (roomId: %s), too many messages per second', client.sessionId, this.roomId);\n return this.#_forciblyCloseClient(client, CloseCode.WITH_ERROR);\n }\n\n const it: Iterator = { offset: 1 };\n const code = buffer[0];\n\n if (code === Protocol.ROOM_DATA) {\n const messageType = (decode.stringCheck(buffer, it))\n ? decode.string(buffer, it)\n : decode.number(buffer, it);\n\n let message;\n try {\n message = (buffer.byteLength > it.offset)\n ? unpack(buffer.subarray(it.offset, buffer.byteLength))\n : undefined;\n debugMessage(\"received: '%s' -> %j (roomId: %s)\", messageType, message, this.roomId);\n\n // custom message validation\n if (this.onMessageValidators[messageType] !== undefined) {\n message = standardValidate(this.onMessageValidators[messageType], message);\n }\n\n } catch (e: any) {\n debugAndPrintError(e);\n client.leave(CloseCode.WITH_ERROR);\n return;\n }\n\n if (this.onMessageEvents.events[messageType]) {\n this.onMessageEvents.emit(messageType as string, client, message);\n\n } else if (this.onMessageEvents.events['*']) {\n this.onMessageEvents.emit('*', client, messageType, message);\n\n } else {\n this.onMessageFallbacks['__no_message_handler'](client, messageType, message);\n }\n\n } else if (code === Protocol.ROOM_DATA_BYTES) {\n const messageType = (decode.stringCheck(buffer, it))\n ? decode.string(buffer, it)\n : decode.number(buffer, it);\n\n let message: any = buffer.subarray(it.offset, buffer.byteLength);\n debugMessage(\"received: '%s' -> %j (roomId: %s)\", messageType, message, this.roomId);\n\n const bytesMessageType = `_$b${messageType}`;\n\n // custom message validation\n try {\n if (this.onMessageValidators[bytesMessageType] !== undefined) {\n message = standardValidate(this.onMessageValidators[bytesMessageType], message);\n }\n } catch (e: any) {\n debugAndPrintError(e);\n client.leave(CloseCode.WITH_ERROR);\n return;\n }\n\n if (this.onMessageEvents.events[bytesMessageType]) {\n this.onMessageEvents.emit(bytesMessageType, client, message);\n\n } else if (this.onMessageEvents.events['*']) {\n this.onMessageEvents.emit('*', client, messageType, message);\n\n } else {\n this.onMessageFallbacks['__no_message_handler'](client, messageType, message);\n }\n\n } else if (code === Protocol.JOIN_ROOM && client.state === ClientState.JOINING) {\n // join room has been acknowledged by the client\n client.state = ClientState.JOINED;\n client._joinedAt = this.clock.elapsedTime;\n\n // send current state when new client joins the room\n if (this.state) {\n this.sendFullState(client);\n }\n\n // dequeue messages sent before client has joined effectively (on user-defined `onJoin`)\n if (client._enqueuedMessages.length > 0) {\n client._enqueuedMessages.forEach((enqueued) => client.raw(enqueued));\n }\n delete client._enqueuedMessages;\n\n } else if (code === Protocol.PING) {\n client.raw(getMessageBytes[Protocol.PING]());\n\n } else if (code === Protocol.LEAVE_ROOM) {\n this.#_forciblyCloseClient(client, CloseCode.CONSENTED);\n }\n }\n\n #_forciblyCloseClient(client: ExtractRoomClient<T> & ClientPrivate, closeCode: number) {\n // stop receiving messages from this client\n client.ref.removeAllListeners('message');\n\n // prevent \"onLeave\" from being called twice if player asks to leave\n client.ref.removeListener('close', client.ref['onleave']);\n\n // only effectively close connection when \"onLeave\" is fulfilled\n this._onLeave(client, closeCode).then(() => client.leave(closeCode));\n }\n\n private async _onLeave(client: ExtractRoomClient<T>, code?: number): Promise<any> {\n // reconnecting check is required here to allow user to deny reconnection via onReconnect()\n const method = (code === CloseCode.CONSENTED || client.state === ClientState.RECONNECTING)\n ? this.onLeave\n : (this.onDrop || this.onLeave);\n\n client.state = ClientState.LEAVING;\n\n if (!this.clients.delete(client)) {\n // skip if client already left the room\n return;\n }\n\n if (method) {\n debugMatchMaking(`${method.name}, sessionId: \\'%s\\' (close code: %d, roomId: %s)`, client.sessionId, code, this.roomId);\n\n try {\n this.#_onLeaveConcurrent++;\n await method.call(this, client, code);\n\n } catch (e: any) {\n const serverError = (!(e instanceof ServerError))\n ? new ServerError(CloseCode.WITH_ERROR, `${method.name} error`, { cause: e })\n : e;\n debugAndPrintError(serverError);\n\n } finally {\n this.#_onLeaveConcurrent--;\n }\n }\n\n // check for manual \"reconnection\" flow\n if (this._reconnections[client.reconnectionToken]) {\n this._reconnections[client.reconnectionToken][1].catch(async () => {\n await this.#_onAfterLeave(client, code, method === this.onDrop);\n });\n\n // @ts-ignore (client.state may be modified at onLeave())\n } else if (client.state !== ClientState.RECONNECTED) {\n await this.#_onAfterLeave(client, code, method === this.onDrop);\n }\n }\n\n async #_onAfterLeave(client: ExtractRoomClient<T>, code?: number, isDrop: boolean = false) {\n if (isDrop && this.onLeave) {\n await this.onLeave(client, code);\n }\n\n // try to dispose immediately if client reconnection isn't set up.\n const willDispose = await this.#_decrementClientCount();\n\n // trigger 'leave' only if seat reservation has been fully consumed\n if (this._reservedSeats[client.sessionId] === undefined) {\n this._events.emit('leave', client, willDispose);\n }\n\n }\n\n async #_incrementClientCount() {\n // lock automatically when maxClients is reached\n if (!this.#_locked && this.hasReachedMaxClients()) {\n this.#_maxClientsReached = true;\n\n // @ts-ignore\n this.lock.call(this, true);\n }\n\n await matchMaker.driver.update(this._listing, {\n $inc: { clients: 1 },\n $set: { locked: this.#_locked },\n });\n }\n\n async #_decrementClientCount() {\n const willDispose = this.#_disposeIfEmpty();\n\n if (this._internalState === RoomInternalState.DISPOSING) {\n return true;\n }\n\n // unlock if room is available for new connections\n if (!willDispose) {\n if (this.#_maxClientsReached && !this._lockedExplicitly) {\n this.#_maxClientsReached = false;\n\n // @ts-ignore\n this.unlock.call(this, true);\n }\n\n // update room listing cache\n await matchMaker.driver.update(this._listing, {\n $inc: { clients: -1 },\n $set: { locked: this.#_locked },\n });\n }\n\n return willDispose;\n }\n\n #registerUncaughtExceptionHandlers() {\n const onUncaughtException = this.onUncaughtException.bind(this);\n const originalSetTimeout = this.clock.setTimeout;\n this.clock.setTimeout = (cb, timeout, ...args) => {\n return originalSetTimeout.call(this.clock, wrapTryCatch(cb, onUncaughtException, TimedEventException, 'setTimeout'), timeout, ...args);\n };\n\n const originalSetInterval = this.clock.setInterval;\n this.clock.setInterval = (cb, timeout, ...args) => {\n return originalSetInterval.call(this.clock, wrapTryCatch(cb, onUncaughtException, TimedEventException, 'setInterval'), timeout, ...args);\n };\n\n if (this.onCreate !== undefined) {\n this.onCreate = wrapTryCatch(this.onCreate.bind(this), onUncaughtException, OnCreateException, 'onCreate', true);\n }\n\n if (this.onAuth !== undefined) {\n this.onAuth = wrapTryCatch(this.onAuth.bind(this), onUncaughtException, OnAuthException, 'onAuth', true);\n }\n\n if (this.onJoin !== undefined) {\n this.onJoin = wrapTryCatch(this.onJoin.bind(this), onUncaughtException, OnJoinException, 'onJoin', true);\n }\n\n if (this.onLeave !== undefined) {\n this.onLeave = wrapTryCatch(this.onLeave.bind(this), onUncaughtException, OnLeaveException, 'onLeave', true);\n }\n\n if (this.onDrop !== undefined) {\n this.onDrop = wrapTryCatch(this.onDrop.bind(this), onUncaughtException, OnDropException, 'onDrop', true);\n }\n\n if (this.onReconnect !== undefined) {\n this.onReconnect = wrapTryCatch(this.onReconnect.bind(this), onUncaughtException, OnReconnectException, 'onReconnect', true);\n }\n\n if (this.onDispose !== undefined) {\n this.onDispose = wrapTryCatch(this.onDispose.bind(this), onUncaughtException, OnDisposeException, 'onDispose');\n }\n }\n\n}\n\n/**\n * (WIP) Alternative, method-based room definition.\n * We should be able to define\n */\n\ntype RoomLifecycleMethods =\n | 'messages'\n | 'onCreate'\n | 'onJoin'\n | 'onLeave'\n | 'onDispose'\n | 'onCacheRoom'\n | 'onRestoreRoom'\n | 'onDrop'\n | 'onReconnect'\n | 'onUncaughtException'\n | 'onAuth'\n | 'onBeforeShutdown'\n | 'onBeforePatch';\n\ntype DefineRoomOptions<T extends RoomOptions = RoomOptions> =\n Partial<Pick<Room<T>, RoomLifecycleMethods>> &\n { state?: ExtractRoomState<T> | (() => ExtractRoomState<T>); } &\n ThisType<Exclude<Room<T>, RoomLifecycleMethods>> &\n ThisType<Room<T>>\n;\n\nexport function room<T>(options: DefineRoomOptions<T>) {\n class _ extends Room<T> {\n messages = options.messages;\n\n constructor() {\n super();\n if (options.state && typeof options.state === 'function') {\n this.state = options.state();\n }\n }\n }\n\n // Copy all methods to the prototype\n for (const key in options) {\n if (typeof options[key] === 'function') {\n _.prototype[key] = options[key];\n }\n }\n\n return _ as typeof Room<T>;\n}"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Clock", "client"]
|
|
4
|
+
"sourcesContent": ["import { unpack } from 'msgpackr';\nimport { decode, Encoder, Reflection, type Iterator, $changes } from '@colyseus/schema';\nimport { InputDecoder } from '@colyseus/schema/input';\nimport { type InputAccessor, type InputAPI, type InputOptions, type NumericFieldsOf, InputAccessorImpl, InputBufferImpl, NO_OP_INPUT_ACCESSOR } from './input/InputBuffer.ts';\nexport { type InputAccessor, type InputAPI, type InputOptions, type NumericFieldsOf } from './input/InputBuffer.ts';\n\n/**\n * Module-level cache of `Reflection.encode` output keyed by input\n * constructor \u2014 pays the encoding cost once per Room class regardless of\n * room instance count. WeakMap so unused classes can be GC'd.\n */\nconst _inputReflectionCache = new WeakMap<Function, Uint8Array>();\nimport { ClockTimer as Clock } from '@colyseus/timer';\n\nimport { EventEmitter } from 'events';\nimport { logger } from './Logger.ts';\n\nimport type { Presence } from './presence/Presence.ts';\nimport type { Serializer } from './serializer/Serializer.ts';\nimport type { IRoomCache } from './matchmaker/driver.ts';\n\nimport { NoneSerializer } from './serializer/NoneSerializer.ts';\nimport { SchemaSerializer } from './serializer/SchemaSerializer.ts';\n\nimport { getMessageBytes } from './Protocol.ts';\nimport { type Type, Deferred, generateId, wrapTryCatch } from './utils/Utils.ts';\nimport { createNanoEvents } from './utils/nanoevents.ts';\nimport { isDevMode } from './utils/DevMode.ts';\n\nimport { debugAndPrintError, debugMatchMaking, debugMessage } from './Debug.ts';\nimport { ServerError } from './errors/ServerError.ts';\nimport { ClientState, type AuthContext, type Client, type ClientPrivate, ClientArray, type ISendOptions, type MessageArgs } from './Transport.ts';\nimport { type RoomMethodName, OnAuthException, OnCreateException, OnDisposeException, OnDropException, OnJoinException, OnLeaveException, OnMessageException, OnReconnectException, type RoomException, SimulationIntervalException, TimedEventException } from './errors/RoomExceptions.ts';\n\nimport { standardValidate, type StandardSchemaV1 } from './utils/StandardSchema.ts';\nimport * as matchMaker from './MatchMaker.ts';\n\nimport {\n CloseCode,\n ErrorCode,\n HandshakeSection,\n Protocol,\n ResponseStatus,\n type MessageHandlerWithFormat as SharedMessageHandlerWithFormat,\n type MessageHandler as SharedMessageHandler,\n type Messages as SharedMessages,\n} from '@colyseus/shared-types';\n\nimport {\n RoomPlugin,\n setupRoomPlugins,\n type PluginLayout,\n} from './RoomPlugin.ts';\nexport {\n RoomPlugin,\n definePlugins,\n attachToTestRoom,\n type RoomPluginOrder,\n} from './RoomPlugin.ts';\n\nconst DEFAULT_PATCH_RATE = 1000 / 20; // 20fps (50ms)\nconst DEFAULT_SIMULATION_INTERVAL = 1000 / 60; // 60fps (16.66ms)\nconst noneSerializer = new NoneSerializer();\n\n// Shape an Error (or thrown value) into a plain, msgpack-friendly object for a\n// ROOM_RESPONSE error payload. Only `name`/`message`/`code` cross the wire \u2014\n// stacks stay on the server.\nfunction toResponseError(e: any): { name: string; message: string; code?: any } {\n if (e instanceof Error) {\n const code = (e as any).code;\n return (code !== undefined)\n ? { name: e.name, message: e.message, code }\n : { name: e.name, message: e.message };\n }\n return { name: \"Error\", message: String(e) };\n}\n\nexport const DEFAULT_SEAT_RESERVATION_TIME = Number(process.env.COLYSEUS_SEAT_RESERVATION_TIME || 15);\n\nexport type SimulationCallback = (deltaTime: number) => void;\n\nexport interface RoomOptions {\n state?: object;\n metadata?: any;\n client?: Client;\n /**\n * Schema class for client\u2192server input packets. When set, the Room\n * allocates one instance per joining client and binds an InputDecoder.\n * Must be a flat Schema (primitive fields only \u2014 see InputEncoder docs).\n *\n * Typed loosely (no `Schema` constraint) to avoid type-identity clashes\n * when the user's app loads a different copy of `@colyseus/schema` than\n * `@colyseus/core` does. Runtime validation happens via the encoder.\n */\n input?: any;\n}\n\n// Helper types to extract individual properties from RoomOptions\nexport type ExtractRoomState<T> = T extends { state?: infer S extends object } ? S : any;\nexport type ExtractRoomMetadata<T> = T extends { metadata?: infer M } ? M : any;\nexport type ExtractRoomClient<T> = T extends { client?: infer C extends Client } ? C : Client;\nexport type ExtractRoomInput<T> = T extends { input?: infer I } ? I : never;\n\nexport interface IBroadcastOptions extends ISendOptions {\n except?: Client | Client[];\n}\n\n/**\n * Message handler with automatic type inference from format schema.\n * When a format is provided, the message type is automatically inferred from the schema.\n */\nexport type MessageHandlerWithFormat<T extends StandardSchemaV1 = any, This = any> =\n SharedMessageHandlerWithFormat<T, Client, This>;\n\nexport type MessageHandler<This = any> = SharedMessageHandler<Client, This>;\n\n/**\n * A map of message types to message handlers.\n */\nexport type Messages<This extends Room> = SharedMessages<This, Client>;\n\n/**\n * Helper function to create a validated message handler with automatic type inference.\n *\n * @example\n * ```typescript\n * messages = {\n * move: validate(z.object({ x: z.number(), y: z.number() }), (client, message) => {\n * // message.x and message.y are automatically typed as numbers\n * console.log(message.x, message.y);\n * })\n * }\n * ```\n */\nexport function validate<T extends StandardSchemaV1, This = any>(\n format: T,\n handler: (this: This, client: Client, message: StandardSchemaV1.InferOutput<T>) => void\n): MessageHandlerWithFormat<T, This> {\n return { format, handler };\n}\n\nexport const RoomInternalState = {\n CREATING: 0,\n CREATED: 1,\n DISPOSING: 2,\n} as const;\nexport type RoomInternalState = (typeof RoomInternalState)[keyof typeof RoomInternalState];\n\nexport type OnCreateOptions<T extends Type<Room>> = Parameters<NonNullable<InstanceType<T>['onCreate']>>[0];\n\n/**\n * A Room class is meant to implement a game session, and/or serve as the communication channel\n * between a group of clients.\n *\n * - Rooms are created on demand during matchmaking by default\n * - Room classes must be exposed using `.define()`\n *\n * @example\n * ```typescript\n * class MyRoom extends Room<{\n * state: MyState,\n * metadata: { difficulty: string },\n * client: MyClient\n * }> {\n * // ...\n * }\n * ```\n */\nexport class Room<T extends RoomOptions = RoomOptions> {\n '~client': ExtractRoomClient<T>;\n '~state': ExtractRoomState<T>;\n '~metadata': ExtractRoomMetadata<T>;\n\n /**\n * This property will change on these situations:\n * - The maximum number of allowed clients has been reached (`maxClients`)\n * - You manually locked, or unlocked the room using lock() or `unlock()`.\n *\n * @readonly\n */\n public get locked() {\n return this.#_locked;\n }\n\n /**\n * Get the room's matchmaking metadata.\n */\n public get metadata(): ExtractRoomMetadata<T> {\n return this._listing.metadata;\n }\n\n /**\n * Set the room's matchmaking metadata.\n *\n * **Note**: This setter does NOT automatically persist. Use `setMatchmaking()` for automatic persistence.\n *\n * @example\n * ```typescript\n * class MyRoom extends Room<{ metadata: { difficulty: string; rating: number } }> {\n * async onCreate() {\n * this.metadata = { difficulty: \"hard\", rating: 1500 };\n * }\n * }\n * ```\n */\n public set metadata(meta: ExtractRoomMetadata<T>) {\n if (this._internalState !== RoomInternalState.CREATING) {\n // prevent user from setting metadata after room has been created.\n throw new ServerError(ErrorCode.APPLICATION_ERROR, \"'metadata' can only be manually set during onCreate(). Use setMatchmaking() instead.\");\n }\n\n this._listing.metadata = meta;\n }\n\n /**\n * The room listing cache for matchmaking.\n * @internal\n */\n private _listing: IRoomCache<ExtractRoomMetadata<T>>;\n\n /**\n * Timing events tied to the room instance.\n * Intervals and timeouts are cleared when the room is disposed.\n */\n public clock: Clock = new Clock();\n\n #_roomId: string;\n #_roomName: string;\n #_onLeaveConcurrent: number = 0; // number of onLeave calls in progress\n\n /**\n * Maximum number of clients allowed to connect into the room. When room reaches this limit,\n * it is locked automatically. Unless the room was explicitly locked by you via `lock()` method,\n * the room will be unlocked as soon as a client disconnects from it.\n */\n public maxClients: number = Infinity;\n #_maxClientsReached: boolean = false;\n #_maxClients: number;\n\n /**\n * Automatically dispose the room when last client disconnects.\n *\n * @default true\n */\n public autoDispose: boolean = true;\n #_autoDispose: boolean;\n\n /**\n * Frequency to send the room state to connected clients, in milliseconds.\n *\n * @default 50ms (20fps)\n */\n public patchRate: number | null = DEFAULT_PATCH_RATE;\n #_patchRate: number;\n #_patchInterval: NodeJS.Timeout;\n\n /**\n * Maximum number of messages a client can send to the server per second.\n * If a client sends more messages than this, it will be disconnected.\n *\n * @default Infinity\n */\n public maxMessagesPerSecond: number = Infinity;\n\n /**\n * The state instance you provided to `setState()`.\n */\n public state: ExtractRoomState<T>;\n #_state: ExtractRoomState<T>;\n\n /**\n * The presence instance. Check Presence API for more details.\n *\n * @see [Presence API](https://docs.colyseus.io/server/presence)\n */\n public presence: Presence;\n\n /**\n * The array of connected clients.\n *\n * @see [Client instance](https://docs.colyseus.io/room#client)\n */\n public clients: ClientArray<ExtractRoomClient<T>> = new ClientArray();\n\n /**\n * Set the number of seconds a room can wait for a client to effectively join the room.\n * You should consider how long your `onAuth()` will have to wait for setting a different seat reservation time.\n * The default value is 15 seconds. You may set the `COLYSEUS_SEAT_RESERVATION_TIME`\n * environment variable if you'd like to change the seat reservation time globally.\n *\n * @default 15 seconds\n */\n public seatReservationTimeout: number = DEFAULT_SEAT_RESERVATION_TIME;\n\n private _events = new EventEmitter();\n\n private _reservedSeats: { [sessionId: string]: [any, any, boolean?, boolean?] } = {};\n private _reservedSeatTimeouts: { [sessionId: string]: NodeJS.Timeout } = {};\n\n private _reconnections: { [reconnectionToken: string]: [string, Deferred] } = {};\n private _reconnectionAttempts: { [reconnectionToken: string]: Deferred } = {};\n\n public messages?: Messages<any>;\n\n /**\n * Room plugins, keyed by an operator-chosen handle. Each plugin\n * contributes any subset of: declarative message handlers (merged\n * into `this.messages`), lifecycle hooks (composed with the room's\n * own), and public methods callable via `this.plugins.<key>.X()`.\n *\n * The framework walks this record once per Room subclass to compute\n * the lifecycle/message layout and install hook wrappers on the\n * class prototype; subsequent constructs reuse the cached layout\n * and just inject `.room` + merge messages.\n *\n * Use `definePlugins({...})` so TypeScript preserves each plugin's\n * literal instance type. Frozen after `__init`.\n */\n public plugins?: any;\n\n /**\n * Auto-included plugin instances pulled in via `static\n * dependencies` declarations on user-registered plugins. Kept\n * separate from `this.plugins` so the user's typed view doesn't\n * gain framework-managed keys. Sentinel-keyed (`__dep:<ClassName>`)\n * so the hook wrappers can route lookups to the right map.\n *\n * @internal\n */\n public _autoPlugins?: Record<string, RoomPlugin<any>>;\n\n /**\n * Layout cache populated on the FIRST construction of each Room\n * subclass. Holds the precomputed hook participation order + message\n * key \u2192 plugin key mapping. Stored on the constructor (a static field)\n * so all instances of the same class share it.\n *\n * `null` is a sentinel meaning \"no plugins on this class\" \u2014 distinct\n * from `undefined` (\"not yet computed\") so we don't re-walk an empty\n * plugin record on every construct.\n *\n * @internal\n */\n static __pluginLayout?: PluginLayout | null;\n\n private onMessageEvents = createNanoEvents();\n private onMessageValidators: {[message: string]: StandardSchemaV1} = {};\n\n private onMessageFallbacks = {\n '__no_message_handler': (client: ExtractRoomClient<T>, messageType: string | number, _: unknown) => {\n const errorMessage = `room onMessage for \"${messageType}\" not registered.`;\n debugMessage(`${errorMessage} (roomId: ${this.roomId})`);\n\n if (isDevMode) {\n // send error code to client in development mode\n client.error(ErrorCode.INVALID_PAYLOAD, errorMessage);\n\n } else {\n // immediately close the connection in production\n client.leave(CloseCode.WITH_ERROR, errorMessage);\n }\n }\n };\n\n private _serializer: Serializer<ExtractRoomState<T>> = noneSerializer;\n private _afterNextPatchQueue: Array<[string | number | ExtractRoomClient<T>, ArrayLike<any>]> = [];\n\n private _simulationInterval: NodeJS.Timeout;\n\n private _internalState: RoomInternalState = RoomInternalState.CREATING;\n\n private _lockedExplicitly: boolean = false;\n #_locked: boolean = false;\n\n // this timeout prevents rooms that are created by one process, but no client\n // ever had success joining into it on the specified interval.\n private _autoDisposeTimeout: NodeJS.Timeout;\n\n constructor() {\n this._events.once('dispose', () => {\n this.#_dispose()\n .catch((e) => debugAndPrintError(`onDispose error: ${(e && e.stack || e.message || e || 'promise rejected')} (roomId: ${this.roomId})`))\n .finally(() => this._events.emit('disconnect'));\n });\n\n /**\n * If `onUncaughtException` is defined, it will automatically catch exceptions\n */\n if (this.onUncaughtException !== undefined) {\n this.#registerUncaughtExceptionHandlers();\n }\n }\n\n /**\n * This method is called by the MatchMaker before onCreate()\n * @internal\n */\n private __init() {\n this.#_state = this.state;\n this.#_autoDispose = this.autoDispose;\n this.#_patchRate = this.patchRate;\n this.#_maxClients = this.maxClients;\n\n Object.defineProperties(this, {\n state: {\n enumerable: true,\n get: () => this.#_state,\n set: (newState: ExtractRoomState<T>) => {\n if (newState?.constructor[Symbol.metadata] !== undefined || newState[$changes] !== undefined) {\n this.setSerializer(new SchemaSerializer());\n } else if ('_definition' in newState) {\n throw new Error(\"@colyseus/schema v2 compatibility currently missing (reach out if you need it)\");\n } else if ($changes === undefined) {\n throw new Error(\"Multiple @colyseus/schema versions detected. Please make sure you don't have multiple versions of @colyseus/schema installed.\");\n }\n this._serializer.reset(newState);\n this.#_state = newState;\n },\n },\n\n maxClients: {\n enumerable: true,\n get: () => this.#_maxClients,\n set: (value: number) => {\n this.setMatchmaking({ maxClients: value });\n },\n },\n\n autoDispose: {\n enumerable: true,\n get: () => this.#_autoDispose,\n set: (value: boolean) => {\n if (\n value !== this.#_autoDispose &&\n this._internalState !== RoomInternalState.DISPOSING\n ) {\n this.#_autoDispose = value;\n this.resetAutoDisposeTimeout();\n }\n },\n },\n\n patchRate: {\n enumerable: true,\n get: () => this.#_patchRate,\n set: (milliseconds: number) => {\n this.#_patchRate = milliseconds;\n // clear previous interval in case called setPatchRate more than once\n if (this.#_patchInterval) {\n clearInterval(this.#_patchInterval);\n this.#_patchInterval = undefined;\n }\n if (milliseconds !== null && milliseconds !== 0) {\n this.#_patchInterval = setInterval(() => this.broadcastPatch(), milliseconds);\n } else if (!this._simulationInterval) {\n // When patchRate and no simulation interval are both set to 0, tick the clock to keep timers working\n this.#_patchInterval = setInterval(() => this.clock.tick(), DEFAULT_SIMULATION_INTERVAL);\n }\n },\n },\n });\n\n // set patch interval, now with the setter\n this.patchRate = this.#_patchRate;\n\n // set state, now with the setter\n if (this.#_state) {\n this.state = this.#_state;\n }\n\n // Wire room plugins from the instance-level `this.plugins` record.\n // The heavy lifting (conflict detection, hook participation, hook\n // wrapping on the prototype) runs once per class \u2014 see\n // `setupRoomPlugins` in `./RoomPlugin.ts`. Per-instance: set\n // `plugin.room = this`, instantiate auto-deps, merge messages.\n if (this.plugins !== undefined) {\n setupRoomPlugins(this);\n }\n\n // Bind messages to the room\n if (this.messages !== undefined) {\n\n // Handle \"_\" as a fallback handler\n if (this.messages['_']) {\n this.onMessage('*', (this.messages['_'] as Function).bind(this));\n delete this.messages['_'];\n }\n\n Object.entries(this.messages).forEach(([messageType, callback]) => {\n if (typeof callback === 'function') {\n // Direct handler function - bind to room instance\n this.onMessage(messageType, callback.bind(this) as any);\n } else {\n // Object with format and handler - bind handler to room instance\n this.onMessage(messageType, callback.format, callback.handler.bind(this));\n }\n });\n }\n\n // set default _autoDisposeTimeout\n this.resetAutoDisposeTimeout(this.seatReservationTimeout);\n\n this.clock.start();\n }\n\n\n /**\n * The name of the room you provided as first argument for `gameServer.define()`.\n *\n * @returns roomName string\n */\n public get roomName() { return this.#_roomName; }\n /**\n * Setting the name of the room. Overwriting this property is restricted.\n *\n * @param roomName\n */\n public set roomName(roomName: string) {\n if (this.#_roomName) {\n // prevent user from setting roomName after it has been defined.\n throw new ServerError(ErrorCode.APPLICATION_ERROR, \"'roomName' cannot be overwritten.\");\n }\n this.#_roomName = roomName;\n }\n\n /**\n * A unique, auto-generated, 9-character-long id of the room.\n * You may replace `this.roomId` during `onCreate()`.\n *\n * @returns roomId string\n */\n public get roomId() { return this.#_roomId; }\n\n /**\n * Setting the roomId, is restricted in room lifetime except upon room creation.\n *\n * @param roomId\n * @returns roomId string\n */\n public set roomId(roomId: string) {\n if (this._internalState !== RoomInternalState.CREATING && !isDevMode) {\n // prevent user from setting roomId after room has been created.\n throw new ServerError(ErrorCode.APPLICATION_ERROR, \"'roomId' can only be overridden upon room creation.\");\n }\n this.#_roomId = roomId;\n }\n\n // Optional abstract methods\n\n /**\n * This method is called before the latest version of the room's state is broadcasted to all clients.\n */\n public onBeforePatch?(state: ExtractRoomState<T>): void | Promise<any>;\n\n /**\n * This method is called when the room is created.\n * @param options - The options passed to the room when it is created.\n */\n public onCreate?(options: any): void | Promise<any>;\n\n /**\n * This method is called when a client joins the room.\n * @param client - The client that joined the room.\n * @param options - The options passed to the client when it joined the room.\n * @param auth - The data returned by the `onAuth` method - (Deprecated: use `client.auth` instead)\n */\n public onJoin?(client: ExtractRoomClient<T>, options?: any, auth?: any): void | Promise<any>;\n\n /**\n * This method is called when a client leaves the room without consent.\n * You may allow the client to reconnect by calling `allowReconnection` within this method.\n *\n * @param client - The client that was dropped from the room.\n * @param code - The close code of the leave event.\n */\n public onDrop?(client: ExtractRoomClient<T>, code?: number): void | Promise<any>;\n\n /**\n * This method is called when a client reconnects to the room.\n * @param client - The client that reconnected to the room.\n */\n public onReconnect?(client: ExtractRoomClient<T>): void | Promise<any>;\n\n /**\n * This method is called when a client effectively leaves the room.\n * @param client - The client that left the room.\n * @param code - The close code of the leave event.\n */\n public onLeave?(client: ExtractRoomClient<T>, code?: number): void | Promise<any>;\n\n /**\n * Per-client input accessor. Set by `defineInput()`. Call `room.input(sessionId)`\n * each tick to read the latest decoded input and/or the buffered snapshot ring\n * for that client.\n *\n * @example\n * ```typescript\n * class FpsRoom extends Room<{ input: MoveInput }> {\n * input = this.defineInput(MoveInput);\n *\n * onCreate() {\n * this.setSimulationInterval(() => {\n * for (const c of this.clients) {\n * const input = this.input(c.sessionId);\n * if (input.latest) this.apply(c, input.latest);\n * // for rollback / lockstep:\n * // const snapshot = input.at(this.clock.ticks);\n * // for (const snapshot of input.drain()) ...\n * }\n * }, 1000 / 30);\n * }\n * }\n * ```\n */\n public input?: InputAPI<ExtractRoomInput<T>>;\n\n /**\n * Input configuration. Set via {@link defineInput} only.\n * @internal\n */\n private inputOptions?: InputOptions;\n\n /**\n * Declare the input schema and configuration in a single line. Returns the\n * callable accessor that gets assigned to `this.input` \u2014 call\n * `this.input(sessionId)` per tick to consume.\n *\n * ```typescript\n * class FpsRoom extends Room<{ input: MoveInput }> {\n * input = this.defineInput(MoveInput, {\n * seqField: \"tick\", // typed: only numeric fields of MoveInput\n * bufferMaxSize: 64,\n * });\n *\n * // \u2026or without options \u2014 defaults to seqField: \"seq\", bufferMaxSize: 32:\n * // input = this.defineInput(MoveInput);\n * }\n * ```\n *\n * **Defaults** when `opts` (or individual fields) are omitted:\n * - `seqField`: `\"seq\"` \u2014 framework dedupes by `input.seq` if the schema has\n * such a field. Schemas without it gracefully skip dedupe.\n * - `bufferMaxSize`: `32` \u2014 enables per-client snapshot buffering for\n * `room.input(sessionId).drain() / .peek() / .at()`. Set to `0` to disable\n * buffering (the `.latest` read still works).\n */\n protected defineInput<C extends new () => any>(\n type: C,\n opts?: {\n seqField?: NumericFieldsOf<InstanceType<C>>;\n bufferMaxSize?: number;\n },\n ): InputAPI<InstanceType<C>> {\n this.inputOptions = {\n ctor: type,\n seqField: opts?.seqField ?? \"seq\",\n bufferMaxSize: opts?.bufferMaxSize ?? 32,\n };\n if (!_inputReflectionCache.has(type)) {\n // Reflection.encode walks the schema's TypeContext via a one-shot\n // Encoder around a throwaway instance; the bytes are SDK-deserializable\n // back into a constructor through Reflection.decode.\n _inputReflectionCache.set(type, Reflection.encode(new Encoder(new type())));\n }\n return ((sessionId: string): InputAccessor<InstanceType<C>> => {\n const c = this.clients.getById(sessionId) as unknown as ClientPrivate | undefined;\n return (c?._inputAccessor as InputAccessor<InstanceType<C>>) ?? NO_OP_INPUT_ACCESSOR;\n });\n }\n\n /**\n * This method is called when the room is disposed.\n */\n public onDispose?(): void | Promise<any>;\n\n /**\n * Define a custom exception handler.\n * If defined, all lifecycle hooks will be wrapped by try/catch, and the exception will be forwarded to this method.\n *\n * These methods will be wrapped by try/catch:\n * - `onMessage`\n * - `onAuth` / `onJoin` / `onLeave` / `onCreate` / `onDispose`\n * - `clock.setTimeout` / `clock.setInterval`\n * - `setSimulationInterval`\n *\n * (Experimental: this feature is subject to change in the future - we're currently getting feedback to improve it)\n */\n public onUncaughtException?(error: RoomException, methodName: RoomMethodName): void;\n\n /**\n * This method is called before onJoin() - this is where you should authenticate the client\n * @param client - The client that is authenticating.\n * @param options - The options passed to the client when it is authenticating.\n * @param context - The authentication context, including the token and the client's IP address.\n * @returns The authentication result.\n *\n * @example\n * ```typescript\n * return {\n * userId: 123,\n * username: \"John Doe\",\n * email: \"john.doe@example.com\",\n * };\n * ```\n */\n public onAuth(\n client: Client,\n options: any,\n context: AuthContext\n ): any | Promise<any> {\n return true;\n }\n\n static async onAuth(\n token: string,\n options: any,\n context: AuthContext\n ): Promise<unknown> {\n return true;\n }\n\n /**\n * This method is called during graceful shutdown of the server process\n * You may override this method to dispose the room in your own way.\n *\n * Once process reaches room count of 0, the room process will be terminated.\n */\n public onBeforeShutdown() {\n this.disconnect(\n (isDevMode)\n ? CloseCode.MAY_TRY_RECONNECT\n : CloseCode.SERVER_SHUTDOWN\n ).catch(() => {});\n }\n\n /**\n * devMode: When `devMode` is enabled, `onCacheRoom` method is called during\n * graceful shutdown.\n *\n * Implement this method to return custom data to be cached. `onRestoreRoom`\n * will be called with the data returned by `onCacheRoom`\n */\n public onCacheRoom?(): any;\n\n /**\n * devMode: When `devMode` is enabled, `onRestoreRoom` method is called during\n * process startup, with the data returned by the `onCacheRoom` method.\n */\n public onRestoreRoom?(cached?: any): void;\n\n /**\n * Returns whether the sum of connected clients and reserved seats exceeds maximum number of clients.\n *\n * @returns boolean\n */\n public hasReachedMaxClients(): boolean {\n return (\n (this.clients.length + Object.keys(this._reservedSeats).length) >= this.#_maxClients ||\n this._internalState === RoomInternalState.DISPOSING\n );\n }\n\n /**\n * @deprecated Use `seatReservationTimeout=` instead.\n */\n public setSeatReservationTime(seconds: number) {\n console.warn(`DEPRECATED: .setSeatReservationTime(${seconds}) is deprecated. Assign a .seatReservationTimeout property value instead.`);\n this.seatReservationTimeout = seconds;\n return this;\n }\n\n public hasReservedSeat(sessionId: string, reconnectionToken?: string): boolean {\n const reservedSeat = this._reservedSeats[sessionId];\n\n if (reservedSeat) {\n // seat reservation is present\n return (\n // not consumed\n (reservedSeat[2] === false) ||\n // reconnection is allowed and the reconnection token is valid.\n (reservedSeat[3] && this._reconnections[reconnectionToken]?.[0] === sessionId)\n )\n\n } else if (typeof(reconnectionToken) === \"string\") {\n // potentially a stale client reference, so a reconnection attempt is possible.\n return this.clients.getById(sessionId)?.reconnectionToken === reconnectionToken;\n }\n\n return false;\n }\n\n public checkReconnectionToken(reconnectionToken: string) {\n const sessionId = this._reconnections[reconnectionToken]?.[0];\n const reservedSeat = this._reservedSeats[sessionId];\n\n if (reservedSeat && reservedSeat[3]) {\n return sessionId;\n }\n\n const client = this.clients.find((client) => client.reconnectionToken === reconnectionToken);\n if (client) {\n this.#_forciblyCloseClient(client as ExtractRoomClient<T> & ClientPrivate, CloseCode.WITH_ERROR);\n return client.sessionId;\n }\n\n return undefined;\n }\n\n /**\n * (Optional) Set a simulation interval that can change the state of the game.\n * The simulation interval is your game loop.\n *\n * @default 16.6ms (60fps)\n *\n * @param onTickCallback - You can implement your physics or world updates here!\n * This is a good place to update the room state.\n * @param delay - Interval delay on executing `onTickCallback` in milliseconds.\n */\n public setSimulationInterval(onTickCallback?: SimulationCallback, delay: number = DEFAULT_SIMULATION_INTERVAL): void {\n // clear previous interval in case called setSimulationInterval more than once\n if (this._simulationInterval) { clearInterval(this._simulationInterval); }\n\n if (onTickCallback) {\n if (this.onUncaughtException !== undefined) {\n onTickCallback = wrapTryCatch(onTickCallback, this.onUncaughtException.bind(this), SimulationIntervalException, 'setSimulationInterval');\n }\n\n this._simulationInterval = setInterval(() => {\n this.clock.tick();\n onTickCallback(this.clock.deltaTime);\n }, delay);\n }\n }\n\n /**\n * Run a fixed-rate simulation tagged with a monotonic server tick number.\n * Combine with `room.input(sessionId).at(tick)` to retrieve each client's\n * input *for a specific tick* \u2014 the building block for lockstep / rollback\n * netcode.\n *\n * Replaces any previous {@link setSimulationInterval}. The current tick is\n * exposed via {@link tick}.\n *\n * @example\n * ```typescript\n * class LockstepRoom extends Room<{ input: MoveInput }> {\n * input = this.defineInput(MoveInput, { seqField: \"tick\", bufferMaxSize: 64 });\n *\n * onCreate() {\n * this.setTickedSimulation((tick, dt) => {\n * for (const c of this.clients) {\n * const snapshot = this.input(c.sessionId).at(tick);\n * if (snapshot) this.apply(c, snapshot);\n * // else: predict, freeze, etc. \u2014 game-level decision\n * }\n * }, 1000 / 60);\n * }\n * }\n * ```\n */\n public setTickedSimulation(\n onTickCallback: (tick: number, deltaTime: number) => void,\n delay: number = DEFAULT_SIMULATION_INTERVAL,\n startTick: number = 0,\n ): void {\n this.#_tick = startTick;\n this.setSimulationInterval((dt) => {\n onTickCallback(this.#_tick, dt);\n this.#_tick++;\n }, delay);\n }\n\n /**\n * Current server tick. Incremented by {@link setTickedSimulation} after each\n * tick callback returns. Returns 0 when no ticked simulation is running.\n */\n public get tick(): number { return this.#_tick; }\n #_tick: number = 0;\n\n /**\n * @deprecated Use `.patchRate=` instead.\n */\n public setPatchRate(milliseconds: number | null): void {\n this.patchRate = milliseconds;\n }\n\n /**\n * @deprecated Use `.state =` instead.\n */\n public setState(newState: ExtractRoomState<T>) {\n this.state = newState;\n }\n\n public setSerializer(serializer: Serializer<ExtractRoomState<T>>) {\n this._serializer = serializer;\n }\n\n public async setMetadata(meta: ExtractRoomMetadata<T>, persist: boolean = true) {\n this._listing.metadata = meta;\n\n if (persist && this._internalState === RoomInternalState.CREATED) {\n await matchMaker.driver.persist(this._listing);\n\n // emit metadata-change event to update lobby listing\n this._events.emit('metadata-change');\n }\n }\n\n public async setPrivate(bool: boolean = true, persist: boolean = true) {\n if (this._listing.private === bool) return;\n\n this._listing.private = bool;\n\n if (persist && this._internalState === RoomInternalState.CREATED) {\n await matchMaker.driver.persist(this._listing);\n }\n\n // emit visibility-change event to update lobby listing\n this._events.emit('visibility-change', bool);\n }\n\n /**\n * Update multiple matchmaking/listing properties at once with a single persist operation.\n * This is the recommended way to update room listing properties.\n *\n * @param updates - Object containing the properties to update\n *\n * @example\n * ```typescript\n * // Update multiple properties at once\n * await this.setMatchmaking({\n * metadata: { difficulty: \"hard\", rating: 1500 },\n * private: true,\n * locked: true,\n * maxClients: 10\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Update only metadata\n * await this.setMatchmaking({\n * metadata: { status: \"in_progress\" }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Merging with existing metadata: spread `this.metadata` yourself.\n * // `metadata` is always REPLACED (not merged) by setMatchmaking()/setMetadata().\n * await this.setMatchmaking({\n * metadata: { ...this.metadata, round: this.metadata.round + 1 }\n * });\n * ```\n */\n public async setMatchmaking(updates: {\n metadata?: ExtractRoomMetadata<T>;\n private?: boolean;\n locked?: boolean;\n maxClients?: number;\n unlisted?: boolean;\n [key: string]: any;\n }) {\n for (const key in updates) {\n if (!updates.hasOwnProperty(key)) { continue; }\n\n switch (key) {\n case 'metadata': {\n this.setMetadata(updates.metadata, false);\n break;\n }\n\n case 'private': {\n this.setPrivate(updates.private, false);\n break;\n }\n\n case 'locked': {\n if (updates[key]) {\n // @ts-ignore\n this.lock.call(this, true);\n this._lockedExplicitly = true;\n } else {\n // @ts-ignore\n this.unlock.call(this, true);\n this._lockedExplicitly = false;\n }\n break;\n }\n\n case 'maxClients': {\n this.#_maxClients = updates.maxClients;\n this._listing.maxClients = updates.maxClients;\n\n const hasReachedMaxClients = this.hasReachedMaxClients();\n\n // unlock room if maxClients has been increased\n if (!this._lockedExplicitly && this.#_maxClientsReached && !hasReachedMaxClients) {\n this.#_maxClientsReached = false;\n this.#_locked = false;\n this._listing.locked = false;\n updates.locked = false;\n }\n\n // lock room if maxClients has been decreased\n if (hasReachedMaxClients) {\n this.#_maxClientsReached = true;\n this.#_locked = true;\n this._listing.locked = true;\n updates.locked = true;\n }\n\n break;\n }\n\n case 'clients': {\n console.warn(\"setMatchmaking() does not allow updating 'clients' property.\");\n break;\n }\n\n default: {\n // Allow any other listing properties to be updated\n this._listing[key] = updates[key];\n break;\n }\n }\n }\n\n // Only persist if room is not CREATING\n if (this._internalState === RoomInternalState.CREATED) {\n await matchMaker.driver.update(this._listing, { $set: updates });\n\n // emit metadata-change event to update lobby listing\n this._events.emit('metadata-change');\n }\n }\n\n /**\n * Lock the room. This prevents new clients from joining this room.\n */\n public async lock() {\n // rooms locked internally aren't explicit locks.\n this._lockedExplicitly = (arguments[0] === undefined);\n\n // skip if already locked.\n if (this.#_locked) { return; }\n\n this.#_locked = true;\n\n // Only persist if this is an explicit lock/unlock\n if (this._lockedExplicitly) {\n await matchMaker.driver.update(this._listing, {\n $set: { locked: this.#_locked },\n });\n }\n\n this._events.emit('lock');\n }\n\n /**\n * Unlock the room. This allows new clients to join this room, if maxClients is not reached.\n */\n public async unlock() {\n // only internal usage passes arguments to this function.\n if (arguments[0] === undefined) {\n this._lockedExplicitly = false;\n }\n\n // skip if already locked\n if (!this.#_locked) { return; }\n\n this.#_locked = false;\n\n // Only persist if this is an explicit lock/unlock\n if (arguments[0] === undefined) {\n await matchMaker.driver.update(this._listing, {\n $set: { locked: this.#_locked },\n });\n }\n\n this._events.emit('unlock');\n }\n\n /**\n * @deprecated Use `client.send(...)` instead.\n */\n public send(client: Client, type: string | number, message: any, options?: ISendOptions): void;\n public send(client: Client, messageOrType: any, messageOrOptions?: any | ISendOptions, options?: ISendOptions): void {\n logger.warn('DEPRECATION WARNING: use client.send(...) instead of this.send(client, ...)');\n client.send(messageOrType, messageOrOptions, options);\n }\n\n /**\n * Broadcast a message to all connected clients.\n * @param type - The type of the message.\n * @param message - The message to broadcast.\n * @param options - The options for the broadcast.\n *\n * @example\n * ```typescript\n * this.broadcast('message', { message: 'Hello, world!' });\n * ```\n */\n public broadcast<K extends keyof ExtractRoomClient<T>['~messages'] & string | number>(\n type: K,\n ...args: MessageArgs<ExtractRoomClient<T>['~messages'][K], IBroadcastOptions>\n ) {\n const [message, options] = args;\n if (options && options.afterNextPatch) {\n delete options.afterNextPatch;\n this._afterNextPatchQueue.push(['broadcast', [type, ...args]]);\n return;\n }\n\n this.broadcastMessageType(type, message, options);\n }\n\n /**\n * Broadcast bytes (UInt8Arrays) to a particular room\n */\n public broadcastBytes(type: string | number, message: Uint8Array, options: IBroadcastOptions) {\n if (options && options.afterNextPatch) {\n delete options.afterNextPatch;\n this._afterNextPatchQueue.push(['broadcastBytes', arguments]);\n return;\n }\n\n this.broadcastMessageType(type as string, message, options);\n }\n\n /**\n * Checks whether mutations have occurred in the state, and broadcast them to all connected clients.\n */\n public broadcastPatch() {\n if (this.onBeforePatch) {\n this.onBeforePatch(this.state);\n }\n\n if (!this._simulationInterval) {\n this.clock.tick();\n }\n\n if (!this.state) {\n return false;\n }\n\n const hasChanges = this._serializer.applyPatches(this.clients, this.state);\n\n // broadcast messages enqueued for \"after patch\"\n this._dequeueAfterPatchMessages();\n\n return hasChanges;\n }\n\n /**\n * Register a message handler for a specific message type.\n * This method is used to handle messages sent by clients to the room.\n * @param messageType - The type of the message.\n * @param callback - The callback to call when the message is received.\n * @returns A function to unbind the callback.\n *\n * @example\n * ```typescript\n * this.onMessage('message', (client, message) => {\n * console.log(message);\n * });\n * ```\n *\n * @example\n * ```typescript\n * const unbind = this.onMessage('message', (client, message) => {\n * console.log(message);\n * });\n *\n * // Unbind the callback when no longer needed\n * unbind();\n * ```\n */\n public onMessage<T = any, C extends Client = ExtractRoomClient<T>>(\n messageType: '*',\n callback: (client: C, type: string | number, message: T) => void\n );\n public onMessage<T = any, C extends Client = ExtractRoomClient<T>>(\n messageType: string | number,\n callback: (client: C, message: T) => void,\n );\n public onMessage<T = any, C extends Client = ExtractRoomClient<T>>(\n messageType: string | number,\n validationSchema: StandardSchemaV1<T>,\n callback: (client: C, message: T) => void,\n );\n public onMessage<T = any>(\n _messageType: '*' | string | number,\n _validationSchema: StandardSchemaV1<T> | ((...args: any[]) => void),\n _callback?: (...args: any[]) => void,\n ) {\n const messageType = _messageType.toString();\n\n const validationSchema = (typeof _callback === 'function')\n ? _validationSchema as StandardSchemaV1<T>\n : undefined;\n\n const callback = (validationSchema === undefined)\n ? _validationSchema as (...args: any[]) => void\n : _callback;\n\n const removeListener = this.onMessageEvents.on(messageType, (this.onUncaughtException !== undefined)\n ? wrapTryCatch(callback, this.onUncaughtException.bind(this), OnMessageException, 'onMessage', false, _messageType)\n : callback);\n\n if (validationSchema !== undefined) {\n this.onMessageValidators[messageType] = validationSchema;\n }\n\n // returns a method to unbind the callback\n return () => {\n removeListener();\n if (this.onMessageEvents.events[messageType].length === 0) {\n delete this.onMessageValidators[messageType];\n }\n };\n }\n\n public onMessageBytes<T = any, C extends Client = ExtractRoomClient<T>>(\n // public onMessageBytes<T = any, C extends Client = TClient>(\n messageType: string | number,\n callback: (client: C, message: T) => void,\n );\n public onMessageBytes<T = any, C extends Client = ExtractRoomClient<T>>(\n // public onMessageBytes<T = any, C extends Client = TClient>(\n messageType: string | number,\n validationSchema: StandardSchemaV1<T>,\n callback: (client: C, message: T) => void,\n );\n public onMessageBytes<T = any>(\n _messageType: string | number,\n _validationSchema: StandardSchemaV1<T> | ((...args: any[]) => void),\n _callback?: (...args: any[]) => void,\n ) {\n const messageType = `_$b${_messageType}`;\n\n const validationSchema = (typeof _callback === 'function')\n ? _validationSchema as StandardSchemaV1<T>\n : undefined;\n\n const callback = (validationSchema === undefined)\n ? _validationSchema as (...args: any[]) => void\n : _callback;\n\n if (validationSchema !== undefined) {\n return this.onMessage(messageType, validationSchema as any, callback as any);\n } else {\n return this.onMessage(messageType, callback as any);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Operator API \u2014 used by @colyseus/admin (and monitor in due course)\n // through `remoteRoomCall(roomId, methodName)`. Marked `@internal` because\n // they're framework-tooling primitives, not part of the game-code surface.\n // ---------------------------------------------------------------------------\n\n /**\n * Snapshot the room's live state for an inspector / admin UI. Includes:\n *\n * roomId, name, maxClients, locked, elapsedTime (ms),\n * metadata, clients (sessionId + per-client elapsed + userId when set),\n * state (the schema/json the SDK would see),\n * stateSize (bytes of the encoded full state, or 0 when no serializer).\n *\n * The payload is intentionally plain JSON \u2014 `remoteRoomCall` serializes\n * the return value across process boundaries.\n *\n * @internal Operator-only. Game code should not call this.\n */\n public getInspectorView(): {\n roomId: string;\n name: string;\n clients: number;\n maxClients: number;\n locked: boolean;\n elapsedTime: number;\n metadata: any;\n clientList: Array<{\n sessionId: string;\n userId: string | null;\n userEmail: string | null;\n elapsedTime: number;\n }>;\n state: any;\n stateSize: number;\n } {\n const elapsed = this.clock.elapsedTime;\n return {\n roomId: this.roomId,\n name: this.roomName,\n clients: this.clients.length,\n maxClients: this.maxClients,\n locked: this.#_locked,\n elapsedTime: elapsed,\n metadata: this.metadata ?? null,\n // Cast through `unknown`: `ExtractRoomClient<T>` vs `Client & ClientPrivate`\n // don't structurally overlap (the user's `client` generic may carry a\n // narrower userData/auth shape), but the runtime objects we walk here\n // always have the private join-time field. The narrow per-property\n // `(c as any)` reads below keep the cast scoped.\n //\n // userId / userEmail read straight off `client.auth` \u2014 the JWT\n // payload @colyseus/auth's default onAuth decodes carries both\n // when the user has them on file. Saves the admin a per-client\n // database round-trip; falls back to null when the client signed\n // in anonymously (or with a custom onAuth that returns a shape\n // without those fields).\n clientList: (this.clients as unknown as ReadonlyArray<Client & ClientPrivate>).map((c) => {\n const auth = (c as any).auth;\n return {\n sessionId: c.sessionId,\n userId: ((c as any).userId ?? auth?.id) ?? null,\n userEmail: auth?.email ?? null,\n elapsedTime: elapsed - ((c as any)._joinedAt ?? elapsed),\n };\n }),\n state: this.state ?? null,\n stateSize: this.#_inspectorStateSize(),\n };\n }\n\n /**\n * Force-disconnect a single client by sessionId. No-op when the client\n * isn't connected (idempotent \u2014 the caller doesn't need to race-check).\n *\n * @internal Operator-only. Game code disconnects clients by calling\n * `.leave()` on the Client object directly.\n */\n public kickClient(sessionId: string, closeCode: number = CloseCode.CONSENTED, reason?: string): void {\n // Same `unknown` indirection as in `getInspectorView` above \u2014\n // ExtractRoomClient<T> doesn't structurally include ClientPrivate.\n for (const client of this.clients as unknown as ReadonlyArray<Client & ClientPrivate>) {\n if (client.sessionId === sessionId) {\n this.#_forciblyCloseClient(client as ExtractRoomClient<T> & ClientPrivate, closeCode, reason);\n return;\n }\n }\n }\n\n /**\n * Best-effort byte size of the current full state. Falls back to `0`\n * when the room has no serializer or the serializer can't produce a\n * payload (raw rooms, very-early-onCreate, etc.). The serializer\n * detection mirrors `@colyseus/monitor`'s \u2014 we read whichever buffer\n * is available across schema v2 and v3.\n */\n #_inspectorStateSize(): number {\n const ser = this._serializer as any;\n if (!ser) { return 0; }\n const hasState = ser.encoder || ser.state;\n if (!hasState) { return 0; }\n try {\n const full = ser.getFullState?.();\n if (!full) { return 0; }\n // Buffer / Uint8Array have `byteLength`; raw arrays have `length`.\n return (full as any).byteLength ?? (full as any).length ?? 0;\n } catch {\n return 0;\n }\n }\n\n /**\n * Disconnect all connected clients, and then dispose the room.\n *\n * @param closeCode WebSocket close code (default = 4000, which is a \"consented leave\")\n * @returns Promise<void>\n */\n public disconnect(closeCode: number = CloseCode.CONSENTED): Promise<any> {\n // skip if already disposing\n if (this._internalState === RoomInternalState.DISPOSING) {\n return Promise.resolve(`disconnect() ignored: room (${this.roomId}) is already disposing.`);\n\n } else if (this._internalState === RoomInternalState.CREATING) {\n throw new Error(\"cannot disconnect during onCreate()\");\n }\n\n this._internalState = RoomInternalState.DISPOSING;\n matchMaker.driver.remove(this._listing.roomId);\n\n this.#_autoDispose = true;\n\n const delayedDisconnection = new Promise<void>((resolve) =>\n this._events.once('disconnect', () => resolve()));\n\n // reject pending reconnections\n this._rejectPendingReconnections(\"disconnecting\");\n\n let numClients = this.clients.length;\n if (numClients > 0) {\n // clients may have `async onLeave`, room will be disposed after they're fulfilled\n while (numClients--) {\n this.#_forciblyCloseClient(this.clients[numClients] as ExtractRoomClient<T> & ClientPrivate, closeCode);\n }\n\n } else {\n // no clients connected, dispose immediately.\n this._events.emit('dispose');\n }\n\n return delayedDisconnection;\n }\n\n private _rejectPendingReconnections(message: string) {\n for (const [_, reconnection] of Object.values(this._reconnections)) {\n reconnection.reject(new ServerError(CloseCode.NORMAL_CLOSURE, message));\n // Suppress unhandled rejection \u2014 expected during shutdown/devMode\n // restart, handled downstream by _onLeave's .catch() handler.\n reconnection.catch(() => {});\n }\n }\n\n private async _onJoin(\n client: ExtractRoomClient<T> & ClientPrivate,\n authContext: AuthContext,\n connectionOptions?: { reconnectionToken?: string, skipHandshake?: boolean }\n ) {\n const sessionId = client.sessionId;\n\n // generate unique private reconnection token\n // (each new reconnection receives a new reconnection token)\n client.reconnectionToken = generateId();\n\n // Allocate per-client input instance + decoder if the Room called `defineInput()`.\n // Done early so onJoin can reference room.input(sessionId).latest.\n if (this.inputOptions !== undefined) {\n client._input = new this.inputOptions.ctor();\n client._inputDecoder = new InputDecoder(client._input);\n // Buffer is opt-in via bufferMaxSize > 0 (rollback / lockstep).\n const maxSize = this.inputOptions.bufferMaxSize;\n if (maxSize > 0) {\n client._inputBuffer = new InputBufferImpl(maxSize, this.inputOptions.seqField);\n }\n client._inputAccessor = new InputAccessorImpl(client);\n }\n\n if (this._reservedSeatTimeouts[sessionId]) {\n clearTimeout(this._reservedSeatTimeouts[sessionId]);\n delete this._reservedSeatTimeouts[sessionId];\n }\n\n // clear auto-dispose timeout.\n if (this._autoDisposeTimeout) {\n clearTimeout(this._autoDisposeTimeout);\n this._autoDisposeTimeout = undefined;\n }\n\n //\n // user may be trying to reconnect while the old connection is still open (stale)\n // (e.g. during network switches, where the old connection is still open while a new reconnection attempt is being made)\n //\n if (\n this._reservedSeats[sessionId] === undefined &&\n connectionOptions?.reconnectionToken &&\n this.clients.getById(sessionId)?.reconnectionToken === connectionOptions.reconnectionToken\n ) {\n debugMatchMaking('attempting to reconnect client with a stale previous connection - sessionId: \\'%s\\', roomId: \\'%s\\'', client.sessionId, this.roomId);\n this._reconnectionAttempts[connectionOptions.reconnectionToken] = new Deferred();\n\n const reconnectionAttemptTimeout = setTimeout(() => {\n this._reconnectionAttempts[connectionOptions.reconnectionToken]?.reject(new ServerError(CloseCode.MAY_TRY_RECONNECT, 'Reconnection attempt timed out'));\n }, this.seatReservationTimeout * 1000);\n\n const cleanup = () => {\n clearTimeout(reconnectionAttemptTimeout);\n delete this._reconnectionAttempts[connectionOptions.reconnectionToken];\n }\n\n await this._reconnectionAttempts[connectionOptions.reconnectionToken]\n .then(() => cleanup())\n .catch(() => cleanup());\n\n if (!this._reservedSeats[sessionId]) {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, \"failed to reconnect\");\n }\n }\n\n // get seat reservation options and clear it\n const [joinOptions, authData, isConsumed, isWaitingReconnection] = this._reservedSeats[sessionId];\n\n //\n // TODO: remove this check on 1.0.0\n // - the seat reservation is used to keep track of number of clients and their pending seats (see `hasReachedMaxClients`)\n // - when we fully migrate to static onAuth(), the seat reservation can be removed immediately here\n // - if async onAuth() is in use, the seat reservation is removed after onAuth() is fulfilled.\n // - mark reservation as \"consumed\"\n //\n if (isConsumed) {\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, \"already consumed\");\n }\n this._reservedSeats[sessionId][2] = true; // flag seat reservation as \"consumed\"\n debugMatchMaking('consuming seat reservation, sessionId: \\'%s\\' (roomId: %s)', client.sessionId, this.roomId);\n\n // share \"after next patch queue\" reference with every client.\n client._afterNextPatchQueue = this._afterNextPatchQueue;\n\n // add temporary callback to keep track of disconnections during `onJoin`.\n client.ref['onleave'] = (_) => client.state = ClientState.LEAVING;\n client.ref.once('close', client.ref['onleave']);\n\n if (isWaitingReconnection) {\n const reconnectionToken = connectionOptions?.reconnectionToken;\n if (reconnectionToken && this._reconnections[reconnectionToken]?.[0] === sessionId) {\n this.clients.push(client);\n\n //\n // await for reconnection:\n // (end user may customize the reconnection token at this step)\n //\n await this._reconnections[reconnectionToken]?.[1].resolve(client);\n\n try {\n if (this.onReconnect) {\n await this.onReconnect(client);\n }\n\n // FIXME: we shouldn't rely on WebSocket specific API here (make it transport agnostic)\n if (client.readyState !== WebSocket.OPEN) {\n throw new Error(\"reconnection denied\");\n }\n\n // client.leave() may have been called during onReconnect()\n if (client.state === ClientState.RECONNECTING) {\n // switch client state from RECONNECTING to JOINING\n // (to allow to attach messages to the client again)\n client.state = ClientState.JOINING;\n }\n\n } catch (e) {\n await this._onLeave(client, CloseCode.FAILED_TO_RECONNECT);\n throw e;\n }\n\n } else {\n const errorMessage = (process.env.NODE_ENV === 'production')\n ? \"already consumed\" // trick possible fraudsters...\n : \"bad reconnection token\" // ...or developers\n throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, errorMessage);\n }\n\n } else {\n try {\n if (authData) {\n client.auth = authData;\n\n } else if (this.onAuth !== Room.prototype.onAuth) {\n try {\n client.auth = await this.onAuth(client, joinOptions, authContext);\n\n if (!client.auth) {\n throw new ServerError(ErrorCode.AUTH_FAILED, 'onAuth failed');\n }\n\n } catch (e) {\n // remove seat reservation\n delete this._reservedSeats[sessionId];\n await this.#_decrementClientCount();\n throw e;\n }\n }\n\n //\n // On async onAuth, client may have been disconnected.\n //\n if (client.state === ClientState.LEAVING) {\n throw new ServerError(CloseCode.WITH_ERROR, 'already disconnected');\n }\n\n this.clients.push(client);\n\n //\n // Flag sessionId as non-enumarable so hasReachedMaxClients() doesn't count it\n // (https://github.com/colyseus/colyseus/issues/726)\n //\n Object.defineProperty(this._reservedSeats, sessionId, {\n value: this._reservedSeats[sessionId],\n enumerable: false,\n });\n\n if (this.onJoin) {\n // TODO: deprecate auth as 3rd argument on Colyseus 1.0\n await this.onJoin(client, joinOptions, client.auth);\n }\n\n // @ts-ignore: client left during `onJoin`, call _onLeave immediately.\n if (client.state === ClientState.LEAVING) {\n throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, \"early_leave\");\n\n } else {\n // remove seat reservation\n delete this._reservedSeats[sessionId];\n\n // emit 'join' to room handler\n this._events.emit('join', client);\n }\n\n } catch (e: any) {\n await this._onLeave(client, CloseCode.WITH_ERROR);\n\n // remove seat reservation\n delete this._reservedSeats[sessionId];\n\n // make sure an error code is provided.\n if (!e.code) {\n e.code = ErrorCode.APPLICATION_ERROR;\n }\n\n throw e;\n }\n }\n\n // state might already be ClientState.LEAVING here\n if (client.state === ClientState.JOINING) {\n client.ref.removeListener('close', client.ref['onleave']);\n\n // only bind _onLeave after onJoin has been successful\n client.ref['onleave'] = this._onLeave.bind(this, client);\n client.ref.once('close', client.ref['onleave']);\n\n // allow client to send messages after onJoin has succeeded.\n client.ref.on('message', this._onMessage.bind(this, client));\n\n // Append input reflection as a tagged section when the room declared\n // input. The SDK uses these bytes to materialize a constructor for\n // `conn.input()` calls that don't pass an explicit `type`.\n let extraSections: Array<{ tag: number; bytes: Uint8Array }> | undefined;\n if (!connectionOptions?.skipHandshake && this.inputOptions !== undefined) {\n const inputBytes = _inputReflectionCache.get(this.inputOptions.ctor);\n if (inputBytes !== undefined) {\n extraSections = [{ tag: HandshakeSection.INPUT_REFLECTION, bytes: inputBytes }];\n }\n }\n\n // confirm room id that matches the room name requested to join\n client.raw(getMessageBytes[Protocol.JOIN_ROOM](\n client.reconnectionToken,\n this._serializer.id,\n /**\n * if skipHandshake is true, we don't need to send the handshake\n * (in case client already has handshake data)\n */\n (connectionOptions?.skipHandshake)\n ? undefined\n : this._serializer.handshake && this._serializer.handshake(),\n extraSections,\n ));\n }\n }\n\n /**\n * Allow the specified client to reconnect into the room. Must be used inside `onLeave()` method.\n * If seconds is provided, the reconnection is going to be cancelled after the provided amount of seconds.\n *\n * @param client - The client that is allowed to reconnect into the room.\n * @param seconds - The time in seconds that the client is allowed to reconnect into the room.\n *\n * @returns Deferred<Client> - The differed is a promise like type.\n * This type can forcibly reject the promise by calling `.reject()`.\n *\n * @example\n * ```typescript\n * onDrop(client: Client, code: CloseCode) {\n * // Allow the client to reconnect into the room with a 15 seconds timeout.\n * this.allowReconnection(client, 15);\n * }\n * ```\n */\n public allowReconnection(previousClient: Client, seconds: number | \"manual\"): Deferred<Client> {\n //\n // Return rejected promise if client has never fully JOINED.\n //\n // (having `_enqueuedMessages !== undefined` means that the client has never been at \"ClientState.JOINED\" state)\n //\n if ((previousClient as unknown as ClientPrivate)._enqueuedMessages !== undefined) {\n // @ts-ignore\n return Promise.reject(new ServerError(\"not joined\"));\n }\n\n if (seconds === undefined) { // TODO: remove this check\n console.warn(\"DEPRECATED: allowReconnection() requires a second argument. Using \\\"manual\\\" mode.\");\n seconds = \"manual\";\n }\n\n if (seconds === \"manual\") {\n seconds = Infinity;\n }\n\n if (this._internalState === RoomInternalState.DISPOSING) {\n // @ts-ignore\n return Promise.reject(new Error(\"disposing\"));\n }\n\n const sessionId = previousClient.sessionId;\n const reconnectionToken = previousClient.reconnectionToken;\n\n //\n // prevent duplicate .allowReconnection() calls\n // (may occur during network switches, where the old connection is still\n // open while a new reconnection attempt is being made)\n //\n if (this._reconnections[reconnectionToken]) {\n debugMatchMaking('skipping duplicate .allowReconnection() call for client - sessionId: \\'%s\\', roomId: \\'%s\\'', sessionId, this.roomId);\n return this._reconnections[reconnectionToken][1];\n }\n\n this._reserveSeat(sessionId, true, previousClient.auth, seconds, true);\n\n // keep reconnection reference in case the user reconnects into this room.\n const reconnection = new Deferred<Client & ClientPrivate>();\n this._reconnections[reconnectionToken] = [sessionId, reconnection];\n\n if (seconds !== Infinity) {\n // expire seat reservation after timeout\n this._reservedSeatTimeouts[sessionId] = setTimeout(() =>\n reconnection.reject(false), seconds * 1000);\n }\n\n const cleanup = () => {\n delete this._reconnections[reconnectionToken];\n delete this._reservedSeats[sessionId];\n delete this._reservedSeatTimeouts[sessionId];\n };\n\n reconnection.then((newClient) => {\n newClient.auth = previousClient.auth;\n newClient.userData = previousClient.userData;\n newClient.view = previousClient.view;\n newClient.state = ClientState.RECONNECTING;\n\n // for convenience: populate previous client reference with new client\n previousClient.state = ClientState.RECONNECTED;\n previousClient.ref = newClient.ref;\n previousClient.reconnectionToken = newClient.reconnectionToken;\n clearTimeout(this._reservedSeatTimeouts[sessionId]);\n\n }, () => {\n this.resetAutoDisposeTimeout();\n\n }).finally(() => {\n cleanup();\n });\n\n //\n // If a reconnection attempt is already in progress, resolve it\n //\n // This step ensures reconnection works when network changes (e.g.,\n // switching Wi-Fi), as the original connection may still be open while a\n // new reconnection attempt is being made.\n //\n if (this._reconnectionAttempts[reconnectionToken] !== undefined) {\n debugMatchMaking('resolving reconnection attempt for client - sessionId: \\'%s\\', roomId: \\'%s\\'', sessionId, this.roomId);\n this._reconnectionAttempts[reconnectionToken].resolve(true);\n }\n\n return reconnection;\n }\n\n private resetAutoDisposeTimeout(timeoutInSeconds: number = 1) {\n clearTimeout(this._autoDisposeTimeout);\n\n if (!this.#_autoDispose) {\n return;\n }\n\n this._autoDisposeTimeout = setTimeout(() => {\n this._autoDisposeTimeout = undefined;\n this.#_disposeIfEmpty();\n }, timeoutInSeconds * 1000);\n }\n\n private broadcastMessageType(type: number | string, message?: any | Uint8Array, options: IBroadcastOptions = {}) {\n debugMessage(\"broadcast: %O (roomId: %s)\", message, this.roomId);\n\n const encodedMessage = (message instanceof Uint8Array)\n ? getMessageBytes.raw(Protocol.ROOM_DATA_BYTES, type, undefined, message)\n : getMessageBytes.raw(Protocol.ROOM_DATA, type, message)\n\n const except = (typeof (options.except) !== \"undefined\")\n ? Array.isArray(options.except)\n ? options.except\n : [options.except]\n : undefined;\n\n let numClients = this.clients.length;\n while (numClients--) {\n const client = this.clients[numClients];\n\n if (!except || !except.includes(client)) {\n client.enqueueRaw(encodedMessage);\n }\n }\n }\n\n // Encode and enqueue a ROOM_RESPONSE for a client request. If the client has\n // already left, `enqueueRaw` is a no-op \u2014 no response is needed.\n #replyToRequest(client: Client, requestId: number, status: ResponseStatus, payload?: any) {\n debugMessage(\"response #%d: status=%d -> %j (roomId: %s)\", requestId, status, payload, this.roomId);\n client.enqueueRaw(getMessageBytes[Protocol.ROOM_RESPONSE](requestId, status, payload));\n }\n\n private sendFullState(client: Client): void {\n client.raw(this._serializer.getFullState(client));\n }\n\n private _dequeueAfterPatchMessages() {\n const length = this._afterNextPatchQueue.length;\n\n if (length > 0) {\n for (let i = 0; i < length; i++) {\n const [target, args] = this._afterNextPatchQueue[i];\n\n if (target === \"broadcast\") {\n this.broadcast.apply(this, args as any);\n\n } else {\n (target as Client).raw.apply(target, args as any);\n }\n }\n\n // new messages may have been added in the meantime,\n // let's splice the ones that have been processed\n this._afterNextPatchQueue.splice(0, length);\n }\n }\n\n private async _reserveSeat(\n sessionId: string,\n joinOptions: any = true,\n authData: any = undefined,\n seconds: number = this.seatReservationTimeout,\n allowReconnection: boolean = false,\n devModeReconnectionToken?: string,\n ) {\n if (!allowReconnection && this.hasReachedMaxClients()) {\n return false;\n }\n\n debugMatchMaking(\n 'reserving seat on \\'%s\\' - sessionId: \\'%s\\', roomId: \\'%s\\', processId: \\'%s\\'',\n this.roomName, sessionId, this.roomId, matchMaker.processId,\n );\n\n this._reservedSeats[sessionId] = [joinOptions, authData, false, allowReconnection];\n\n if (!allowReconnection) {\n await this.#_incrementClientCount();\n\n this._reservedSeatTimeouts[sessionId] = setTimeout(async () => {\n delete this._reservedSeats[sessionId];\n delete this._reservedSeatTimeouts[sessionId];\n await this.#_decrementClientCount();\n }, seconds * 1000);\n\n this.resetAutoDisposeTimeout(seconds);\n }\n\n if (devModeReconnectionToken) {\n const reconnection = new Deferred<Client & ClientPrivate>();\n this._reconnections[devModeReconnectionToken] = [sessionId, reconnection];\n\n // If the client doesn't reconnect within the timeout, call onLeave\n // so the room can clean up stale state (e.g. delete player data).\n clearTimeout(this._reservedSeatTimeouts[sessionId]);\n this._reservedSeatTimeouts[sessionId] = setTimeout(async () => {\n if (!this._reconnections[devModeReconnectionToken]) { return; }\n\n delete this._reconnections[devModeReconnectionToken];\n delete this._reservedSeats[sessionId];\n delete this._reservedSeatTimeouts[sessionId];\n\n if (!allowReconnection) {\n await this.#_decrementClientCount();\n }\n\n this.onLeave?.({ sessionId } as any, CloseCode.MAY_TRY_RECONNECT);\n }, seconds * 1000);\n }\n\n return true;\n }\n\n private async _reserveMultipleSeats(\n multipleSessionIds: string[],\n multipleJoinOptions: any = true,\n multipleAuthData: any = undefined,\n seconds: number = this.seatReservationTimeout,\n ) {\n let promises: Promise<boolean>[] = [];\n\n for (let i = 0; i < multipleSessionIds.length; i++) {\n promises.push(this._reserveSeat(multipleSessionIds[i], multipleJoinOptions[i], multipleAuthData[i], seconds));\n }\n\n return await Promise.all(promises);\n }\n\n #_disposeIfEmpty() {\n const willDispose = (\n this.#_onLeaveConcurrent === 0 && // no \"onLeave\" calls in progress\n this.#_autoDispose &&\n this._autoDisposeTimeout === undefined &&\n this.clients.length === 0 &&\n Object.keys(this._reservedSeats).length === 0\n );\n\n if (willDispose) {\n this._events.emit('dispose');\n }\n\n return willDispose;\n }\n\n async #_dispose(): Promise<any> {\n this._internalState = RoomInternalState.DISPOSING;\n\n // If the room is still CREATING, the roomId is not yet set.\n if (this._listing?.roomId !== undefined) {\n await matchMaker.driver.remove(this._listing.roomId);\n }\n\n let userReturnData;\n if (this.onDispose) {\n userReturnData = this.onDispose();\n }\n\n if (this.#_patchInterval) {\n clearInterval(this.#_patchInterval);\n this.#_patchInterval = undefined;\n }\n\n if (this._simulationInterval) {\n clearInterval(this._simulationInterval);\n this._simulationInterval = undefined;\n }\n\n if (this._autoDisposeTimeout) {\n clearInterval(this._autoDisposeTimeout);\n this._autoDisposeTimeout = undefined;\n }\n\n // clear all timeouts/intervals + force to stop ticking\n this.clock.clear();\n this.clock.stop();\n\n return await (userReturnData || Promise.resolve());\n }\n\n /**\n * After the decoder has mutated `client._input`, push a clone into the\n * per-client buffer (when buffering is enabled). Honors\n * `inputOptions.seqField` for dedupe of redundant frames.\n */\n #captureInput(client: ClientPrivate) {\n const buf = client._inputBuffer;\n if (!buf) { return; } // no consumer registered \u2014 skip the clone allocation\n const inst = client._input!;\n const seqField = this.inputOptions?.seqField;\n if (seqField !== undefined) {\n const value = (inst as any)[seqField] as number;\n if (typeof value === 'number' && !buf.accept(value)) { return; }\n }\n buf.push(inst.clone() as any);\n }\n\n private _onMessage(client: ExtractRoomClient<T> & ClientPrivate, buffer: Buffer) {\n // skip if client is on LEAVING state.\n if (client.state === ClientState.LEAVING) { return; }\n\n if (!buffer) {\n debugAndPrintError(`${this.roomName} (roomId: ${this.roomId}), couldn't decode message: ${buffer}`);\n return;\n }\n\n // reset message count every second\n if (this.clock.currentTime - client._lastMessageTime >= 1000) {\n client._numMessagesLastSecond = 0;\n client._lastMessageTime = this.clock.currentTime;\n } else if (++client._numMessagesLastSecond > this.maxMessagesPerSecond) {\n // drop client if it sends more messages than the maximum allowed per second\n debugMatchMaking('dropping client - sessionId: \\'%s\\' (roomId: %s), too many messages per second', client.sessionId, this.roomId);\n return this.#_forciblyCloseClient(client, CloseCode.WITH_ERROR);\n }\n\n const it: Iterator = { offset: 1 };\n const code = buffer[0];\n\n if (code === Protocol.ROOM_DATA) {\n const messageType = (decode.stringCheck(buffer, it))\n ? decode.string(buffer, it)\n : decode.number(buffer, it);\n\n let message;\n try {\n message = (buffer.byteLength > it.offset)\n ? unpack(buffer.subarray(it.offset, buffer.byteLength))\n : undefined;\n debugMessage(\"received: '%s' -> %j (roomId: %s)\", messageType, message, this.roomId);\n\n // custom message validation\n if (this.onMessageValidators[messageType] !== undefined) {\n message = standardValidate(this.onMessageValidators[messageType], message);\n }\n\n } catch (e: any) {\n debugAndPrintError(e);\n client.leave(CloseCode.WITH_ERROR);\n return;\n }\n\n if (this.onMessageEvents.events[messageType]) {\n this.onMessageEvents.emit(messageType as string, client, message);\n\n } else if (this.onMessageEvents.events['*']) {\n this.onMessageEvents.emit('*', client, messageType, message);\n\n } else {\n this.onMessageFallbacks['__no_message_handler'](client, messageType, message);\n }\n\n } else if (code === Protocol.ROOM_REQUEST) {\n // A request reuses the same `onMessage(type, ...)` handlers as a plain\n // ROOM_DATA message \u2014 the only difference is the client opted in to a\n // reply (by passing a callback / using `room.request()`), so the wire\n // carries a `requestId` we must echo back. The handler's return value\n // (awaited) becomes the response payload.\n const requestId = decode.number(buffer, it);\n\n const messageType = (decode.stringCheck(buffer, it))\n ? decode.string(buffer, it)\n : decode.number(buffer, it);\n\n let message;\n try {\n message = (buffer.byteLength > it.offset)\n ? unpack(buffer.subarray(it.offset, buffer.byteLength))\n : undefined;\n debugMessage(\"request #%d: '%s' -> %j (roomId: %s)\", requestId, messageType, message, this.roomId);\n\n // custom message validation (shared with the ROOM_DATA path)\n if (this.onMessageValidators[messageType] !== undefined) {\n message = standardValidate(this.onMessageValidators[messageType], message);\n }\n\n } catch (e: any) {\n // Reply with an error so the client's pending request settles instead\n // of timing out. (A plain ROOM_DATA would drop the client here, but a\n // request has a caller waiting on the other end.)\n debugAndPrintError(e);\n this.#replyToRequest(client, requestId, ResponseStatus.ERROR, toResponseError(e));\n return;\n }\n\n // A request is answered by the FIRST handler registered for its type.\n // `onMessageEvents.emit` would run every handler and discard returns, so\n // we invoke directly to capture the value. Wildcard ('*') handlers are\n // not eligible \u2014 their (client, type, message) shape has no response\n // contract \u2014 so a type with only a wildcard handler gets `no_handler`.\n const handler = this.onMessageEvents.events[messageType as string]?.[0];\n\n if (handler === undefined) {\n this.#replyToRequest(client, requestId, ResponseStatus.ERROR, {\n name: \"no_handler\",\n message: `room \"${this.roomName}\" has no onMessage(\"${messageType}\") handler to answer this request.`,\n });\n return;\n }\n\n // `Promise.resolve().then(...)` normalizes sync throws and async\n // rejections into the same rejection path. When `onUncaughtException`\n // is configured the handler is wrapped (see `onMessage`) and swallows\n // its own errors, so the request resolves with `undefined` and the\n // exception is reported there instead of as an ERROR response.\n Promise.resolve().then(() => handler(client, message)).then(\n (response) => this.#replyToRequest(client, requestId, ResponseStatus.OK, response),\n (e) => {\n debugAndPrintError(e);\n this.#replyToRequest(client, requestId, ResponseStatus.ERROR, toResponseError(e));\n },\n );\n\n } else if (code === Protocol.ROOM_DATA_BYTES) {\n const messageType = (decode.stringCheck(buffer, it))\n ? decode.string(buffer, it)\n : decode.number(buffer, it);\n\n let message: any = buffer.subarray(it.offset, buffer.byteLength);\n debugMessage(\"received: '%s' -> %j (roomId: %s)\", messageType, message, this.roomId);\n\n const bytesMessageType = `_$b${messageType}`;\n\n // custom message validation\n try {\n if (this.onMessageValidators[bytesMessageType] !== undefined) {\n message = standardValidate(this.onMessageValidators[bytesMessageType], message);\n }\n } catch (e: any) {\n debugAndPrintError(e);\n client.leave(CloseCode.WITH_ERROR);\n return;\n }\n\n if (this.onMessageEvents.events[bytesMessageType]) {\n this.onMessageEvents.emit(bytesMessageType, client, message);\n\n } else if (this.onMessageEvents.events['*']) {\n this.onMessageEvents.emit('*', client, messageType, message);\n\n } else {\n this.onMessageFallbacks['__no_message_handler'](client, messageType, message);\n }\n\n } else if (code === Protocol.ROOM_INPUT_RELIABLE) {\n if (client._inputDecoder) {\n try {\n client._inputDecoder.decode(buffer.subarray(1));\n } catch (e: any) {\n debugAndPrintError(e);\n return;\n }\n this.#captureInput(client);\n }\n\n } else if (code === Protocol.ROOM_INPUT_UNRELIABLE) {\n if (client._inputDecoder) {\n try {\n client._inputDecoder.decodeAll(buffer.subarray(1), () => this.#captureInput(client));\n } catch (e: any) {\n debugAndPrintError(e);\n return;\n }\n }\n\n } else if (code === Protocol.JOIN_ROOM && client.state === ClientState.JOINING) {\n // join room has been acknowledged by the client\n client.state = ClientState.JOINED;\n client._joinedAt = this.clock.elapsedTime;\n\n // send current state when new client joins the room\n if (this.state) {\n this.sendFullState(client);\n }\n\n // dequeue messages sent before client has joined effectively (on user-defined `onJoin`)\n if (client._enqueuedMessages.length > 0) {\n client._enqueuedMessages.forEach((enqueued) => client.raw(enqueued));\n }\n delete client._enqueuedMessages;\n\n } else if (code === Protocol.PING) {\n client.raw(getMessageBytes[Protocol.PING]());\n\n } else if (code === Protocol.LEAVE_ROOM) {\n this.#_forciblyCloseClient(client, CloseCode.CONSENTED);\n }\n }\n\n #_forciblyCloseClient(client: ExtractRoomClient<T> & ClientPrivate, closeCode: number, reason?: string) {\n // stop receiving messages from this client\n client.ref.removeAllListeners('message');\n\n // prevent \"onLeave\" from being called twice if player asks to leave\n client.ref.removeListener('close', client.ref['onleave']);\n\n // only effectively close connection when \"onLeave\" is fulfilled\n this._onLeave(client, closeCode).then(() => (client as any).leave(closeCode, reason));\n }\n\n private async _onLeave(client: ExtractRoomClient<T>, code?: number): Promise<any> {\n // reconnecting check is required here to allow user to deny reconnection via onReconnect()\n const method = (code === CloseCode.CONSENTED || client.state === ClientState.RECONNECTING)\n ? this.onLeave\n : (this.onDrop || this.onLeave);\n\n client.state = ClientState.LEAVING;\n\n if (!this.clients.delete(client)) {\n // skip if client already left the room\n return;\n }\n\n if (method) {\n debugMatchMaking(`${method.name}, sessionId: \\'%s\\' (close code: %d, roomId: %s)`, client.sessionId, code, this.roomId);\n\n try {\n this.#_onLeaveConcurrent++;\n await method.call(this, client, code);\n\n } catch (e: any) {\n const serverError = (!(e instanceof ServerError))\n ? new ServerError(CloseCode.WITH_ERROR, `${method.name} error`, { cause: e })\n : e;\n debugAndPrintError(serverError);\n\n } finally {\n this.#_onLeaveConcurrent--;\n }\n }\n\n // check for manual \"reconnection\" flow\n if (this._reconnections[client.reconnectionToken]) {\n this._reconnections[client.reconnectionToken][1].catch(async () => {\n await this.#_onAfterLeave(client, code, method === this.onDrop);\n });\n\n // @ts-ignore (client.state may be modified at onLeave())\n } else if (client.state !== ClientState.RECONNECTED) {\n await this.#_onAfterLeave(client, code, method === this.onDrop);\n }\n }\n\n async #_onAfterLeave(client: ExtractRoomClient<T>, code?: number, isDrop: boolean = false) {\n if (isDrop && this.onLeave) {\n await this.onLeave(client, code);\n }\n\n // try to dispose immediately if client reconnection isn't set up.\n const willDispose = await this.#_decrementClientCount();\n\n // trigger 'leave' only if seat reservation has been fully consumed\n if (this._reservedSeats[client.sessionId] === undefined) {\n this._events.emit('leave', client, willDispose);\n }\n }\n\n async #_incrementClientCount() {\n // lock automatically when maxClients is reached\n if (!this.#_locked && this.hasReachedMaxClients()) {\n this.#_maxClientsReached = true;\n\n // @ts-ignore\n this.lock.call(this, true);\n }\n\n await matchMaker.driver.update(this._listing, {\n $inc: { clients: 1 },\n $set: { locked: this.#_locked },\n });\n }\n\n async #_decrementClientCount() {\n const willDispose = this.#_disposeIfEmpty();\n\n if (this._internalState === RoomInternalState.DISPOSING) {\n return true;\n }\n\n // unlock if room is available for new connections\n if (!willDispose) {\n if (this.#_maxClientsReached && !this._lockedExplicitly) {\n this.#_maxClientsReached = false;\n\n // @ts-ignore\n this.unlock.call(this, true);\n }\n\n // update room listing cache\n await matchMaker.driver.update(this._listing, {\n $inc: { clients: -1 },\n $set: { locked: this.#_locked },\n });\n }\n\n return willDispose;\n }\n\n #registerUncaughtExceptionHandlers() {\n const onUncaughtException = this.onUncaughtException.bind(this);\n const originalSetTimeout = this.clock.setTimeout;\n this.clock.setTimeout = (cb, timeout, ...args) => {\n return originalSetTimeout.call(this.clock, wrapTryCatch(cb, onUncaughtException, TimedEventException, 'setTimeout'), timeout, ...args);\n };\n\n const originalSetInterval = this.clock.setInterval;\n this.clock.setInterval = (cb, timeout, ...args) => {\n return originalSetInterval.call(this.clock, wrapTryCatch(cb, onUncaughtException, TimedEventException, 'setInterval'), timeout, ...args);\n };\n\n if (this.onCreate !== undefined) {\n this.onCreate = wrapTryCatch(this.onCreate.bind(this), onUncaughtException, OnCreateException, 'onCreate', true);\n }\n\n if (this.onAuth !== undefined) {\n this.onAuth = wrapTryCatch(this.onAuth.bind(this), onUncaughtException, OnAuthException, 'onAuth', true);\n }\n\n if (this.onJoin !== undefined) {\n this.onJoin = wrapTryCatch(this.onJoin.bind(this), onUncaughtException, OnJoinException, 'onJoin', true);\n }\n\n if (this.onLeave !== undefined) {\n this.onLeave = wrapTryCatch(this.onLeave.bind(this), onUncaughtException, OnLeaveException, 'onLeave', true);\n }\n\n if (this.onDrop !== undefined) {\n this.onDrop = wrapTryCatch(this.onDrop.bind(this), onUncaughtException, OnDropException, 'onDrop', true);\n }\n\n if (this.onReconnect !== undefined) {\n this.onReconnect = wrapTryCatch(this.onReconnect.bind(this), onUncaughtException, OnReconnectException, 'onReconnect', true);\n }\n\n if (this.onDispose !== undefined) {\n this.onDispose = wrapTryCatch(this.onDispose.bind(this), onUncaughtException, OnDisposeException, 'onDispose');\n }\n }\n\n}\n\n/**\n * (WIP) Alternative, method-based room definition.\n * We should be able to define\n */\n\ntype RoomLifecycleMethods =\n | 'messages'\n | 'onCreate'\n | 'onJoin'\n | 'onLeave'\n | 'onDispose'\n | 'onCacheRoom'\n | 'onRestoreRoom'\n | 'onDrop'\n | 'onReconnect'\n | 'onUncaughtException'\n | 'onAuth'\n | 'onBeforeShutdown'\n | 'onBeforePatch';\n\ntype DefineRoomOptions<T extends RoomOptions = RoomOptions> =\n Partial<Pick<Room<T>, RoomLifecycleMethods>> &\n { state?: ExtractRoomState<T> | (() => ExtractRoomState<T>); } &\n ThisType<Exclude<Room<T>, RoomLifecycleMethods>> &\n ThisType<Room<T>>\n;\n\nexport function room<T>(options: DefineRoomOptions<T>) {\n class _ extends Room<T> {\n messages = options.messages;\n\n constructor() {\n super();\n if (options.state && typeof options.state === 'function') {\n this.state = options.state();\n }\n }\n }\n\n // Copy all methods to the prototype\n for (const key in options) {\n if (typeof options[key] === 'function') {\n _.prototype[key] = options[key];\n }\n }\n\n return _ as typeof Room<T>;\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_InputBuffer", "import_RoomPlugin", "Clock", "client"]
|
|
7
7
|
}
|