{
  "version": 3,
  "sources": ["../src/Room.ts"],
  "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}"],
  "mappings": "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",
  "names": ["Clock", "client"]
}
