@colyseus/core 0.16.12 → 0.16.14

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/Room.js CHANGED
@@ -618,6 +618,7 @@ class Room {
618
618
  reconnection.then((newClient) => {
619
619
  newClient.auth = previousClient.auth;
620
620
  newClient.userData = previousClient.userData;
621
+ newClient.view = previousClient.view;
621
622
  previousClient.state = import_Transport.ClientState.RECONNECTED;
622
623
  previousClient.ref = newClient.ref;
623
624
  previousClient.reconnectionToken = newClient.reconnectionToken;
package/build/Room.js.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';\n\nimport Clock from '@colyseus/timer';\nimport { EventEmitter } from 'events';\nimport { logger } from './Logger.js';\n\nimport { Presence } from './presence/Presence.js';\n\nimport { NoneSerializer } from './serializer/NoneSerializer.js';\nimport { SchemaSerializer } from './serializer/SchemaSerializer.js';\nimport { Serializer } from './serializer/Serializer.js';\n\nimport { ErrorCode, getMessageBytes, Protocol } from './Protocol.js';\nimport { Deferred, generateId, wrapTryCatch } from './utils/Utils.js';\nimport { isDevMode } from './utils/DevMode.js';\n\nimport { debugAndPrintError, debugMatchMaking, debugMessage } from './Debug.js';\nimport { RoomCache } from './matchmaker/driver/api.js';\nimport { ServerError } from './errors/ServerError.js';\nimport { AuthContext, Client, ClientPrivate, ClientArray, ClientState, ISendOptions } from './Transport.js';\nimport { OnAuthException, OnCreateException, OnDisposeException, OnJoinException, OnLeaveException, OnMessageException, RoomException, SimulationIntervalException, TimedEventException } from './errors/RoomExceptions.js';\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 IBroadcastOptions extends ISendOptions {\n except?: Client | Client[];\n}\n\nexport enum RoomInternalState {\n CREATING = 0,\n CREATED = 1,\n DISPOSING = 2,\n}\n\nexport type ExtractUserData<T> = T extends ClientArray<infer U> ? U : never;\nexport type ExtractAuthData<T> = T extends ClientArray<infer _, infer U> ? U : never;\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 */\nexport abstract class Room<State extends object= any, Metadata= any, UserData = any, AuthData = any> {\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 public get metadata() {\n return this.listing.metadata;\n }\n\n public listing: RoomCache<Metadata>;\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 = DEFAULT_PATCH_RATE;\n #_patchRate: number;\n #_patchInterval: NodeJS.Timeout;\n\n /**\n * The state instance you provided to `setState()`.\n */\n public state: State;\n #_state: State;\n\n /**\n * The presence instance. Check Presence API for more details.\n *\n * @see {@link https://docs.colyseus.io/colyseus/server/presence/|Presence API}\n */\n public presence: Presence;\n\n /**\n * The array of connected clients.\n *\n * @see {@link https://docs.colyseus.io/colyseus/server/room/#client|Client instance}\n */\n public clients: ClientArray<UserData, AuthData> = new ClientArray();\n\n /** @internal */\n public _events = new EventEmitter();\n\n // seat reservation & reconnection\n protected seatReservationTime: number = DEFAULT_SEAT_RESERVATION_TIME;\n protected reservedSeats: { [sessionId: string]: [any, any, boolean?, boolean?] } = {};\n protected reservedSeatTimeouts: { [sessionId: string]: NodeJS.Timeout } = {};\n\n protected _reconnections: { [reconnectionToken: string]: [string, Deferred] } = {};\n private _reconnectingSessionId = new Map<string, string>();\n\n private onMessageHandlers: {\n [id: string]: {\n callback: (...args: any[]) => void,\n validate?: (data: unknown) => any,\n }\n } = {\n '__no_message_handler': {\n callback: (client: Client, messageType: string, _: unknown) => {\n const errorMessage = `room onMessage for \"${messageType}\" not registered.`;\n debugAndPrintError(`${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(Protocol.WS_CLOSE_WITH_ERROR, errorMessage);\n }\n }\n }\n };\n\n private _serializer: Serializer<State> = noneSerializer;\n private _afterNextPatchQueue: Array<[string | Client, IArguments]> = [];\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 protected __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: State) => {\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.#_maxClients = value;\n\n if (this._internalState === RoomInternalState.CREATED) {\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 }\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 }\n\n this.listing.maxClients = value;\n this.listing.save();\n }\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 }\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 // set default _autoDisposeTimeout\n this.resetAutoDisposeTimeout(this.seatReservationTime);\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 public onBeforePatch?(state: State): void | Promise<any>;\n public onCreate?(options: any): void | Promise<any>;\n public onJoin?(client: Client<UserData, AuthData>, options?: any, auth?: AuthData): void | Promise<any>;\n public onLeave?(client: Client<UserData, AuthData>, consented?: boolean): void | Promise<any>;\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<this>, methodName: 'onCreate' | 'onAuth' | 'onJoin' | 'onLeave' | 'onDispose' | 'onMessage' | 'setSimulationInterval' | 'setInterval' | 'setTimeout'): void;\n\n public onAuth(\n client: Client<UserData, AuthData>,\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 ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : Protocol.WS_CLOSE_CONSENTED\n );\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 * 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 * @param seconds - number of seconds.\n * @returns The modified Room object.\n */\n public setSeatReservationTime(seconds: number) {\n this.seatReservationTime = seconds;\n return this;\n }\n\n public hasReservedSeat(sessionId: string, reconnectionToken?: string): boolean {\n const reservedSeat = this.reservedSeats[sessionId];\n\n // seat reservation not found / expired\n if (reservedSeat === undefined) {\n return false;\n }\n\n if (reservedSeat[3]) {\n // reconnection\n return (\n reconnectionToken &&\n this._reconnections[reconnectionToken]?.[0] === sessionId &&\n this._reconnectingSessionId.has(sessionId)\n );\n\n } else {\n // seat reservation not consumed\n return reservedSeat[2] === false;\n }\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 this._reconnectingSessionId.set(sessionId, reconnectionToken);\n return sessionId;\n\n } else {\n return undefined;\n }\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: State) {\n this.state = newState;\n }\n\n public setSerializer(serializer: Serializer<State>) {\n this._serializer = serializer;\n }\n\n public async setMetadata(meta: Partial<Metadata>) {\n if (!this.listing.metadata) {\n this.listing.metadata = meta as Metadata;\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 (this._internalState === RoomInternalState.CREATED) {\n await this.listing.save();\n }\n }\n\n public async setPrivate(bool: boolean = true) {\n if (this.listing.private === bool) return;\n\n this.listing.private = bool;\n\n if (this._internalState === RoomInternalState.CREATED) {\n await this.listing.save();\n }\n\n this._events.emit('visibility-change', bool);\n }\n\n /**\n * Locking the room will remove it from the pool of available rooms for new clients to connect to.\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 await this.listing.updateOne({\n $set: { locked: this.#_locked },\n });\n\n this._events.emit('lock');\n }\n\n /**\n * Unlocking the room returns it to the pool of available rooms for new clients to connect to.\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 await this.listing.updateOne({\n $set: { locked: this.#_locked },\n });\n\n this._events.emit('unlock');\n }\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 public broadcast(type: string | number, message?: any, options?: IBroadcastOptions) {\n if (options && options.afterNextPatch) {\n delete options.afterNextPatch;\n this._afterNextPatchQueue.push(['broadcast', arguments]);\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 public onMessage<T = any>(\n messageType: '*',\n callback: (client: Client<UserData, AuthData>, type: string | number, message: T) => void\n );\n public onMessage<T = any>(\n messageType: string | number,\n callback: (client: Client<UserData, AuthData>, message: T) => void,\n validate?: (message: unknown) => T,\n );\n public onMessage<T = any>(\n messageType: '*' | string | number,\n callback: (...args: any[]) => void,\n validate?: (message: unknown) => T,\n ) {\n this.onMessageHandlers[messageType] = (this.onUncaughtException !== undefined)\n ? { validate, callback: wrapTryCatch(callback, this.onUncaughtException.bind(this), OnMessageException, 'onMessage', false, messageType) }\n : { validate, callback };\n\n\n // returns a method to unbind the callback\n return () => delete this.onMessageHandlers[messageType];\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 = Protocol.WS_CLOSE_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 this.listing.remove();\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 for (const [_, reconnection] of Object.values(this._reconnections)) {\n reconnection.reject(new Error(\"disconnecting\"));\n }\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 Client & 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 public async ['_onJoin'](client: Client & ClientPrivate, authContext: AuthContext) {\n const sessionId = client.sessionId;\n\n // generate unique private 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 // 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 previousReconnectionToken = this._reconnectingSessionId.get(sessionId);\n if (previousReconnectionToken) {\n this.clients.push(client);\n //\n // await for reconnection:\n // (end user may customize the reconnection token at this step)\n //\n await this._reconnections[previousReconnectionToken]?.[1].resolve(client);\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(Protocol.WS_CLOSE_GOING_AWAY, '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 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 Error(\"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) {\n await this._onLeave(client, Protocol.WS_CLOSE_GOING_AWAY);\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 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 previousClient - The client which is to be waiting until re-connection happens.\n * @param seconds - Timeout period on re-connection in seconds.\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 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 Error(\"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 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 this._reconnectingSessionId.delete(sessionId);\n };\n\n reconnection.\n then((newClient) => {\n newClient.auth = previousClient.auth;\n newClient.userData = previousClient.userData;\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 cleanup();\n }).\n catch(() => {\n cleanup();\n this.resetAutoDisposeTimeout();\n });\n\n return reconnection;\n }\n\n protected 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 protected sendFullState(client: Client): void {\n client.raw(this._serializer.getFullState(client));\n }\n\n protected _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);\n\n } else {\n (target as Client).raw.apply(target, args);\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 protected async _reserveSeat(\n sessionId: string,\n joinOptions: any = true,\n authData: any = undefined,\n seconds: number = this.seatReservationTime,\n allowReconnection: boolean = false,\n devModeReconnection?: boolean,\n ) {\n if (!allowReconnection && this.hasReachedMaxClients()) {\n return false;\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 //\n // isDevMode workaround to allow players to reconnect on devMode\n //\n if (devModeReconnection) {\n this._reconnectingSessionId.set(sessionId, sessionId);\n }\n\n return true;\n }\n\n protected _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 protected async _dispose(): Promise<any> {\n this._internalState = RoomInternalState.DISPOSING;\n\n this.listing.remove();\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 protected _onMessage(client: Client & ClientPrivate, buffer: Buffer) {\n // skip if client is on LEAVING state.\n if (client.state === ClientState.LEAVING) { return; }\n\n const it: Iterator = { offset: 1 };\n const code = buffer[0];\n\n if (!buffer) {\n debugAndPrintError(`${this.roomName} (roomId: ${this.roomId}), couldn't decode message: ${buffer}`);\n return;\n }\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 const messageTypeHandler = this.onMessageHandlers[messageType];\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 (messageTypeHandler?.validate !== undefined) {\n message = messageTypeHandler.validate(message);\n }\n\n } catch (e) {\n debugAndPrintError(e);\n client.leave(Protocol.WS_CLOSE_WITH_ERROR);\n return;\n }\n\n if (messageTypeHandler) {\n messageTypeHandler.callback(client, message);\n\n } else {\n (this.onMessageHandlers['*'] || this.onMessageHandlers['__no_message_handler']).callback(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 const messageTypeHandler = this.onMessageHandlers[messageType];\n\n let message = buffer.subarray(it.offset, buffer.byteLength);\n debugMessage(\"received: '%s' -> %j (roomId: %s)\", messageType, message, this.roomId);\n\n // custom message validation\n if (messageTypeHandler?.validate !== undefined) {\n message = messageTypeHandler.validate(message);\n }\n\n if (messageTypeHandler) {\n messageTypeHandler.callback(client, message);\n\n } else {\n (this.onMessageHandlers['*'] || this.onMessageHandlers['__no_message_handler']).callback(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.LEAVE_ROOM) {\n this._forciblyCloseClient(client, Protocol.WS_CLOSE_CONSENTED);\n }\n\n }\n\n protected _forciblyCloseClient(client: Client & 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 protected async _onLeave(client: Client, code?: number): Promise<any> {\n debugMatchMaking('onLeave, sessionId: \\'%s\\' (close code: %d, roomId: %s)', client.sessionId, code, this.roomId);\n\n // call 'onLeave' method only if the client has been successfully accepted.\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 (this.onLeave) {\n try {\n this.#_onLeaveConcurrent++;\n await this.onLeave(client, (code === Protocol.WS_CLOSE_CONSENTED));\n\n } catch (e) {\n debugAndPrintError(`onLeave error: ${(e && e.message || e || 'promise rejected')} (roomId: ${this.roomId})`);\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);\n });\n\n // @ts-ignore (client.state may be modified at onLeave())\n } else if (client.state !== ClientState.RECONNECTED) {\n await this._onAfterLeave(client);\n }\n }\n\n protected async _onAfterLeave(client: Client) {\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 protected async _incrementClientCount() {\n // lock automatically when maxClients is reached\n if (!this.#_locked && this.hasReachedMaxClients()) {\n this.#_maxClientsReached = true;\n this.lock.call(this, true);\n }\n\n await this.listing.updateOne({\n $inc: { clients: 1 },\n $set: { locked: this.#_locked },\n });\n }\n\n protected 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 this.unlock.call(this, true);\n }\n\n // update room listing cache\n await this.listing.updateOne({\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.onDispose !== undefined) {\n this.onDispose = wrapTryCatch(this.onDispose.bind(this), onUncaughtException, OnDisposeException, 'onDispose');\n }\n }\n\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { unpack } from '@colyseus/msgpackr';\nimport { decode, type Iterator, $changes } from '@colyseus/schema';\n\nimport Clock from '@colyseus/timer';\nimport { EventEmitter } from 'events';\nimport { logger } from './Logger.js';\n\nimport { Presence } from './presence/Presence.js';\n\nimport { NoneSerializer } from './serializer/NoneSerializer.js';\nimport { SchemaSerializer } from './serializer/SchemaSerializer.js';\nimport { Serializer } from './serializer/Serializer.js';\n\nimport { ErrorCode, getMessageBytes, Protocol } from './Protocol.js';\nimport { Deferred, generateId, wrapTryCatch } from './utils/Utils.js';\nimport { isDevMode } from './utils/DevMode.js';\n\nimport { debugAndPrintError, debugMatchMaking, debugMessage } from './Debug.js';\nimport { RoomCache } from './matchmaker/driver/api.js';\nimport { ServerError } from './errors/ServerError.js';\nimport { AuthContext, Client, ClientPrivate, ClientArray, ClientState, ISendOptions } from './Transport.js';\nimport { OnAuthException, OnCreateException, OnDisposeException, OnJoinException, OnLeaveException, OnMessageException, RoomException, SimulationIntervalException, TimedEventException } from './errors/RoomExceptions.js';\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 IBroadcastOptions extends ISendOptions {\n except?: Client | Client[];\n}\n\nexport enum RoomInternalState {\n CREATING = 0,\n CREATED = 1,\n DISPOSING = 2,\n}\n\nexport type ExtractUserData<T> = T extends ClientArray<infer U> ? U : never;\nexport type ExtractAuthData<T> = T extends ClientArray<infer _, infer U> ? U : never;\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 */\nexport abstract class Room<State extends object= any, Metadata= any, UserData = any, AuthData = any> {\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 public get metadata() {\n return this.listing.metadata;\n }\n\n public listing: RoomCache<Metadata>;\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 = DEFAULT_PATCH_RATE;\n #_patchRate: number;\n #_patchInterval: NodeJS.Timeout;\n\n /**\n * The state instance you provided to `setState()`.\n */\n public state: State;\n #_state: State;\n\n /**\n * The presence instance. Check Presence API for more details.\n *\n * @see {@link https://docs.colyseus.io/colyseus/server/presence/|Presence API}\n */\n public presence: Presence;\n\n /**\n * The array of connected clients.\n *\n * @see {@link https://docs.colyseus.io/colyseus/server/room/#client|Client instance}\n */\n public clients: ClientArray<UserData, AuthData> = new ClientArray();\n\n /** @internal */\n public _events = new EventEmitter();\n\n // seat reservation & reconnection\n protected seatReservationTime: number = DEFAULT_SEAT_RESERVATION_TIME;\n protected reservedSeats: { [sessionId: string]: [any, any, boolean?, boolean?] } = {};\n protected reservedSeatTimeouts: { [sessionId: string]: NodeJS.Timeout } = {};\n\n protected _reconnections: { [reconnectionToken: string]: [string, Deferred] } = {};\n private _reconnectingSessionId = new Map<string, string>();\n\n private onMessageHandlers: {\n [id: string]: {\n callback: (...args: any[]) => void,\n validate?: (data: unknown) => any,\n }\n } = {\n '__no_message_handler': {\n callback: (client: Client, messageType: string, _: unknown) => {\n const errorMessage = `room onMessage for \"${messageType}\" not registered.`;\n debugAndPrintError(`${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(Protocol.WS_CLOSE_WITH_ERROR, errorMessage);\n }\n }\n }\n };\n\n private _serializer: Serializer<State> = noneSerializer;\n private _afterNextPatchQueue: Array<[string | Client, IArguments]> = [];\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 protected __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: State) => {\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.#_maxClients = value;\n\n if (this._internalState === RoomInternalState.CREATED) {\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 }\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 }\n\n this.listing.maxClients = value;\n this.listing.save();\n }\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 }\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 // set default _autoDisposeTimeout\n this.resetAutoDisposeTimeout(this.seatReservationTime);\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 public onBeforePatch?(state: State): void | Promise<any>;\n public onCreate?(options: any): void | Promise<any>;\n public onJoin?(client: Client<UserData, AuthData>, options?: any, auth?: AuthData): void | Promise<any>;\n public onLeave?(client: Client<UserData, AuthData>, consented?: boolean): void | Promise<any>;\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<this>, methodName: 'onCreate' | 'onAuth' | 'onJoin' | 'onLeave' | 'onDispose' | 'onMessage' | 'setSimulationInterval' | 'setInterval' | 'setTimeout'): void;\n\n public onAuth(\n client: Client<UserData, AuthData>,\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 ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : Protocol.WS_CLOSE_CONSENTED\n );\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 * 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 * @param seconds - number of seconds.\n * @returns The modified Room object.\n */\n public setSeatReservationTime(seconds: number) {\n this.seatReservationTime = seconds;\n return this;\n }\n\n public hasReservedSeat(sessionId: string, reconnectionToken?: string): boolean {\n const reservedSeat = this.reservedSeats[sessionId];\n\n // seat reservation not found / expired\n if (reservedSeat === undefined) {\n return false;\n }\n\n if (reservedSeat[3]) {\n // reconnection\n return (\n reconnectionToken &&\n this._reconnections[reconnectionToken]?.[0] === sessionId &&\n this._reconnectingSessionId.has(sessionId)\n );\n\n } else {\n // seat reservation not consumed\n return reservedSeat[2] === false;\n }\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 this._reconnectingSessionId.set(sessionId, reconnectionToken);\n return sessionId;\n\n } else {\n return undefined;\n }\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: State) {\n this.state = newState;\n }\n\n public setSerializer(serializer: Serializer<State>) {\n this._serializer = serializer;\n }\n\n public async setMetadata(meta: Partial<Metadata>) {\n if (!this.listing.metadata) {\n this.listing.metadata = meta as Metadata;\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 (this._internalState === RoomInternalState.CREATED) {\n await this.listing.save();\n }\n }\n\n public async setPrivate(bool: boolean = true) {\n if (this.listing.private === bool) return;\n\n this.listing.private = bool;\n\n if (this._internalState === RoomInternalState.CREATED) {\n await this.listing.save();\n }\n\n this._events.emit('visibility-change', bool);\n }\n\n /**\n * Locking the room will remove it from the pool of available rooms for new clients to connect to.\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 await this.listing.updateOne({\n $set: { locked: this.#_locked },\n });\n\n this._events.emit('lock');\n }\n\n /**\n * Unlocking the room returns it to the pool of available rooms for new clients to connect to.\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 await this.listing.updateOne({\n $set: { locked: this.#_locked },\n });\n\n this._events.emit('unlock');\n }\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 public broadcast(type: string | number, message?: any, options?: IBroadcastOptions) {\n if (options && options.afterNextPatch) {\n delete options.afterNextPatch;\n this._afterNextPatchQueue.push(['broadcast', arguments]);\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 public onMessage<T = any>(\n messageType: '*',\n callback: (client: Client<UserData, AuthData>, type: string | number, message: T) => void\n );\n public onMessage<T = any>(\n messageType: string | number,\n callback: (client: Client<UserData, AuthData>, message: T) => void,\n validate?: (message: unknown) => T,\n );\n public onMessage<T = any>(\n messageType: '*' | string | number,\n callback: (...args: any[]) => void,\n validate?: (message: unknown) => T,\n ) {\n this.onMessageHandlers[messageType] = (this.onUncaughtException !== undefined)\n ? { validate, callback: wrapTryCatch(callback, this.onUncaughtException.bind(this), OnMessageException, 'onMessage', false, messageType) }\n : { validate, callback };\n\n\n // returns a method to unbind the callback\n return () => delete this.onMessageHandlers[messageType];\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 = Protocol.WS_CLOSE_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 this.listing.remove();\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 for (const [_, reconnection] of Object.values(this._reconnections)) {\n reconnection.reject(new Error(\"disconnecting\"));\n }\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 Client & 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 public async ['_onJoin'](client: Client & ClientPrivate, authContext: AuthContext) {\n const sessionId = client.sessionId;\n\n // generate unique private 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 // 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 previousReconnectionToken = this._reconnectingSessionId.get(sessionId);\n if (previousReconnectionToken) {\n this.clients.push(client);\n //\n // await for reconnection:\n // (end user may customize the reconnection token at this step)\n //\n await this._reconnections[previousReconnectionToken]?.[1].resolve(client);\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(Protocol.WS_CLOSE_GOING_AWAY, '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 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 Error(\"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) {\n await this._onLeave(client, Protocol.WS_CLOSE_GOING_AWAY);\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 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 previousClient - The client which is to be waiting until re-connection happens.\n * @param seconds - Timeout period on re-connection in seconds.\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 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 Error(\"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 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 this._reconnectingSessionId.delete(sessionId);\n };\n\n reconnection.\n then((newClient) => {\n newClient.auth = previousClient.auth;\n newClient.userData = previousClient.userData;\n newClient.view = previousClient.view;\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 cleanup();\n }).\n catch(() => {\n cleanup();\n this.resetAutoDisposeTimeout();\n });\n\n return reconnection;\n }\n\n protected 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 protected sendFullState(client: Client): void {\n client.raw(this._serializer.getFullState(client));\n }\n\n protected _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);\n\n } else {\n (target as Client).raw.apply(target, args);\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 protected async _reserveSeat(\n sessionId: string,\n joinOptions: any = true,\n authData: any = undefined,\n seconds: number = this.seatReservationTime,\n allowReconnection: boolean = false,\n devModeReconnection?: boolean,\n ) {\n if (!allowReconnection && this.hasReachedMaxClients()) {\n return false;\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 //\n // isDevMode workaround to allow players to reconnect on devMode\n //\n if (devModeReconnection) {\n this._reconnectingSessionId.set(sessionId, sessionId);\n }\n\n return true;\n }\n\n protected _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 protected async _dispose(): Promise<any> {\n this._internalState = RoomInternalState.DISPOSING;\n\n this.listing.remove();\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 protected _onMessage(client: Client & ClientPrivate, buffer: Buffer) {\n // skip if client is on LEAVING state.\n if (client.state === ClientState.LEAVING) { return; }\n\n const it: Iterator = { offset: 1 };\n const code = buffer[0];\n\n if (!buffer) {\n debugAndPrintError(`${this.roomName} (roomId: ${this.roomId}), couldn't decode message: ${buffer}`);\n return;\n }\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 const messageTypeHandler = this.onMessageHandlers[messageType];\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 (messageTypeHandler?.validate !== undefined) {\n message = messageTypeHandler.validate(message);\n }\n\n } catch (e) {\n debugAndPrintError(e);\n client.leave(Protocol.WS_CLOSE_WITH_ERROR);\n return;\n }\n\n if (messageTypeHandler) {\n messageTypeHandler.callback(client, message);\n\n } else {\n (this.onMessageHandlers['*'] || this.onMessageHandlers['__no_message_handler']).callback(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 const messageTypeHandler = this.onMessageHandlers[messageType];\n\n let message = buffer.subarray(it.offset, buffer.byteLength);\n debugMessage(\"received: '%s' -> %j (roomId: %s)\", messageType, message, this.roomId);\n\n // custom message validation\n if (messageTypeHandler?.validate !== undefined) {\n message = messageTypeHandler.validate(message);\n }\n\n if (messageTypeHandler) {\n messageTypeHandler.callback(client, message);\n\n } else {\n (this.onMessageHandlers['*'] || this.onMessageHandlers['__no_message_handler']).callback(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.LEAVE_ROOM) {\n this._forciblyCloseClient(client, Protocol.WS_CLOSE_CONSENTED);\n }\n\n }\n\n protected _forciblyCloseClient(client: Client & 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 protected async _onLeave(client: Client, code?: number): Promise<any> {\n debugMatchMaking('onLeave, sessionId: \\'%s\\' (close code: %d, roomId: %s)', client.sessionId, code, this.roomId);\n\n // call 'onLeave' method only if the client has been successfully accepted.\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 (this.onLeave) {\n try {\n this.#_onLeaveConcurrent++;\n await this.onLeave(client, (code === Protocol.WS_CLOSE_CONSENTED));\n\n } catch (e) {\n debugAndPrintError(`onLeave error: ${(e && e.message || e || 'promise rejected')} (roomId: ${this.roomId})`);\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);\n });\n\n // @ts-ignore (client.state may be modified at onLeave())\n } else if (client.state !== ClientState.RECONNECTED) {\n await this._onAfterLeave(client);\n }\n }\n\n protected async _onAfterLeave(client: Client) {\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 protected async _incrementClientCount() {\n // lock automatically when maxClients is reached\n if (!this.#_locked && this.hasReachedMaxClients()) {\n this.#_maxClientsReached = true;\n this.lock.call(this, true);\n }\n\n await this.listing.updateOne({\n $inc: { clients: 1 },\n $set: { locked: this.#_locked },\n });\n }\n\n protected 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 this.unlock.call(this, true);\n }\n\n // update room listing cache\n await this.listing.updateOne({\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.onDispose !== undefined) {\n this.onDispose = wrapTryCatch(this.onDispose.bind(this), onUncaughtException, OnDisposeException, 'onDispose');\n }\n }\n\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["RoomInternalState", "Clock"]
7
7
  }
package/build/Room.mjs CHANGED
@@ -585,6 +585,7 @@ var Room = class _Room {
585
585
  reconnection.then((newClient) => {
586
586
  newClient.auth = previousClient.auth;
587
587
  newClient.userData = previousClient.userData;
588
+ newClient.view = previousClient.view;
588
589
  previousClient.state = ClientState.RECONNECTED;
589
590
  previousClient.ref = newClient.ref;
590
591
  previousClient.reconnectionToken = newClient.reconnectionToken;
@@ -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';\n\nimport Clock from '@colyseus/timer';\nimport { EventEmitter } from 'events';\nimport { logger } from './Logger.js';\n\nimport { Presence } from './presence/Presence.js';\n\nimport { NoneSerializer } from './serializer/NoneSerializer.js';\nimport { SchemaSerializer } from './serializer/SchemaSerializer.js';\nimport { Serializer } from './serializer/Serializer.js';\n\nimport { ErrorCode, getMessageBytes, Protocol } from './Protocol.js';\nimport { Deferred, generateId, wrapTryCatch } from './utils/Utils.js';\nimport { isDevMode } from './utils/DevMode.js';\n\nimport { debugAndPrintError, debugMatchMaking, debugMessage } from './Debug.js';\nimport { RoomCache } from './matchmaker/driver/api.js';\nimport { ServerError } from './errors/ServerError.js';\nimport { AuthContext, Client, ClientPrivate, ClientArray, ClientState, ISendOptions } from './Transport.js';\nimport { OnAuthException, OnCreateException, OnDisposeException, OnJoinException, OnLeaveException, OnMessageException, RoomException, SimulationIntervalException, TimedEventException } from './errors/RoomExceptions.js';\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 IBroadcastOptions extends ISendOptions {\n except?: Client | Client[];\n}\n\nexport enum RoomInternalState {\n CREATING = 0,\n CREATED = 1,\n DISPOSING = 2,\n}\n\nexport type ExtractUserData<T> = T extends ClientArray<infer U> ? U : never;\nexport type ExtractAuthData<T> = T extends ClientArray<infer _, infer U> ? U : never;\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 */\nexport abstract class Room<State extends object= any, Metadata= any, UserData = any, AuthData = any> {\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 public get metadata() {\n return this.listing.metadata;\n }\n\n public listing: RoomCache<Metadata>;\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 = DEFAULT_PATCH_RATE;\n #_patchRate: number;\n #_patchInterval: NodeJS.Timeout;\n\n /**\n * The state instance you provided to `setState()`.\n */\n public state: State;\n #_state: State;\n\n /**\n * The presence instance. Check Presence API for more details.\n *\n * @see {@link https://docs.colyseus.io/colyseus/server/presence/|Presence API}\n */\n public presence: Presence;\n\n /**\n * The array of connected clients.\n *\n * @see {@link https://docs.colyseus.io/colyseus/server/room/#client|Client instance}\n */\n public clients: ClientArray<UserData, AuthData> = new ClientArray();\n\n /** @internal */\n public _events = new EventEmitter();\n\n // seat reservation & reconnection\n protected seatReservationTime: number = DEFAULT_SEAT_RESERVATION_TIME;\n protected reservedSeats: { [sessionId: string]: [any, any, boolean?, boolean?] } = {};\n protected reservedSeatTimeouts: { [sessionId: string]: NodeJS.Timeout } = {};\n\n protected _reconnections: { [reconnectionToken: string]: [string, Deferred] } = {};\n private _reconnectingSessionId = new Map<string, string>();\n\n private onMessageHandlers: {\n [id: string]: {\n callback: (...args: any[]) => void,\n validate?: (data: unknown) => any,\n }\n } = {\n '__no_message_handler': {\n callback: (client: Client, messageType: string, _: unknown) => {\n const errorMessage = `room onMessage for \"${messageType}\" not registered.`;\n debugAndPrintError(`${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(Protocol.WS_CLOSE_WITH_ERROR, errorMessage);\n }\n }\n }\n };\n\n private _serializer: Serializer<State> = noneSerializer;\n private _afterNextPatchQueue: Array<[string | Client, IArguments]> = [];\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 protected __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: State) => {\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.#_maxClients = value;\n\n if (this._internalState === RoomInternalState.CREATED) {\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 }\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 }\n\n this.listing.maxClients = value;\n this.listing.save();\n }\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 }\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 // set default _autoDisposeTimeout\n this.resetAutoDisposeTimeout(this.seatReservationTime);\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 public onBeforePatch?(state: State): void | Promise<any>;\n public onCreate?(options: any): void | Promise<any>;\n public onJoin?(client: Client<UserData, AuthData>, options?: any, auth?: AuthData): void | Promise<any>;\n public onLeave?(client: Client<UserData, AuthData>, consented?: boolean): void | Promise<any>;\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<this>, methodName: 'onCreate' | 'onAuth' | 'onJoin' | 'onLeave' | 'onDispose' | 'onMessage' | 'setSimulationInterval' | 'setInterval' | 'setTimeout'): void;\n\n public onAuth(\n client: Client<UserData, AuthData>,\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 ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : Protocol.WS_CLOSE_CONSENTED\n );\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 * 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 * @param seconds - number of seconds.\n * @returns The modified Room object.\n */\n public setSeatReservationTime(seconds: number) {\n this.seatReservationTime = seconds;\n return this;\n }\n\n public hasReservedSeat(sessionId: string, reconnectionToken?: string): boolean {\n const reservedSeat = this.reservedSeats[sessionId];\n\n // seat reservation not found / expired\n if (reservedSeat === undefined) {\n return false;\n }\n\n if (reservedSeat[3]) {\n // reconnection\n return (\n reconnectionToken &&\n this._reconnections[reconnectionToken]?.[0] === sessionId &&\n this._reconnectingSessionId.has(sessionId)\n );\n\n } else {\n // seat reservation not consumed\n return reservedSeat[2] === false;\n }\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 this._reconnectingSessionId.set(sessionId, reconnectionToken);\n return sessionId;\n\n } else {\n return undefined;\n }\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: State) {\n this.state = newState;\n }\n\n public setSerializer(serializer: Serializer<State>) {\n this._serializer = serializer;\n }\n\n public async setMetadata(meta: Partial<Metadata>) {\n if (!this.listing.metadata) {\n this.listing.metadata = meta as Metadata;\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 (this._internalState === RoomInternalState.CREATED) {\n await this.listing.save();\n }\n }\n\n public async setPrivate(bool: boolean = true) {\n if (this.listing.private === bool) return;\n\n this.listing.private = bool;\n\n if (this._internalState === RoomInternalState.CREATED) {\n await this.listing.save();\n }\n\n this._events.emit('visibility-change', bool);\n }\n\n /**\n * Locking the room will remove it from the pool of available rooms for new clients to connect to.\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 await this.listing.updateOne({\n $set: { locked: this.#_locked },\n });\n\n this._events.emit('lock');\n }\n\n /**\n * Unlocking the room returns it to the pool of available rooms for new clients to connect to.\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 await this.listing.updateOne({\n $set: { locked: this.#_locked },\n });\n\n this._events.emit('unlock');\n }\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 public broadcast(type: string | number, message?: any, options?: IBroadcastOptions) {\n if (options && options.afterNextPatch) {\n delete options.afterNextPatch;\n this._afterNextPatchQueue.push(['broadcast', arguments]);\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 public onMessage<T = any>(\n messageType: '*',\n callback: (client: Client<UserData, AuthData>, type: string | number, message: T) => void\n );\n public onMessage<T = any>(\n messageType: string | number,\n callback: (client: Client<UserData, AuthData>, message: T) => void,\n validate?: (message: unknown) => T,\n );\n public onMessage<T = any>(\n messageType: '*' | string | number,\n callback: (...args: any[]) => void,\n validate?: (message: unknown) => T,\n ) {\n this.onMessageHandlers[messageType] = (this.onUncaughtException !== undefined)\n ? { validate, callback: wrapTryCatch(callback, this.onUncaughtException.bind(this), OnMessageException, 'onMessage', false, messageType) }\n : { validate, callback };\n\n\n // returns a method to unbind the callback\n return () => delete this.onMessageHandlers[messageType];\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 = Protocol.WS_CLOSE_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 this.listing.remove();\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 for (const [_, reconnection] of Object.values(this._reconnections)) {\n reconnection.reject(new Error(\"disconnecting\"));\n }\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 Client & 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 public async ['_onJoin'](client: Client & ClientPrivate, authContext: AuthContext) {\n const sessionId = client.sessionId;\n\n // generate unique private 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 // 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 previousReconnectionToken = this._reconnectingSessionId.get(sessionId);\n if (previousReconnectionToken) {\n this.clients.push(client);\n //\n // await for reconnection:\n // (end user may customize the reconnection token at this step)\n //\n await this._reconnections[previousReconnectionToken]?.[1].resolve(client);\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(Protocol.WS_CLOSE_GOING_AWAY, '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 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 Error(\"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) {\n await this._onLeave(client, Protocol.WS_CLOSE_GOING_AWAY);\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 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 previousClient - The client which is to be waiting until re-connection happens.\n * @param seconds - Timeout period on re-connection in seconds.\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 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 Error(\"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 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 this._reconnectingSessionId.delete(sessionId);\n };\n\n reconnection.\n then((newClient) => {\n newClient.auth = previousClient.auth;\n newClient.userData = previousClient.userData;\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 cleanup();\n }).\n catch(() => {\n cleanup();\n this.resetAutoDisposeTimeout();\n });\n\n return reconnection;\n }\n\n protected 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 protected sendFullState(client: Client): void {\n client.raw(this._serializer.getFullState(client));\n }\n\n protected _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);\n\n } else {\n (target as Client).raw.apply(target, args);\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 protected async _reserveSeat(\n sessionId: string,\n joinOptions: any = true,\n authData: any = undefined,\n seconds: number = this.seatReservationTime,\n allowReconnection: boolean = false,\n devModeReconnection?: boolean,\n ) {\n if (!allowReconnection && this.hasReachedMaxClients()) {\n return false;\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 //\n // isDevMode workaround to allow players to reconnect on devMode\n //\n if (devModeReconnection) {\n this._reconnectingSessionId.set(sessionId, sessionId);\n }\n\n return true;\n }\n\n protected _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 protected async _dispose(): Promise<any> {\n this._internalState = RoomInternalState.DISPOSING;\n\n this.listing.remove();\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 protected _onMessage(client: Client & ClientPrivate, buffer: Buffer) {\n // skip if client is on LEAVING state.\n if (client.state === ClientState.LEAVING) { return; }\n\n const it: Iterator = { offset: 1 };\n const code = buffer[0];\n\n if (!buffer) {\n debugAndPrintError(`${this.roomName} (roomId: ${this.roomId}), couldn't decode message: ${buffer}`);\n return;\n }\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 const messageTypeHandler = this.onMessageHandlers[messageType];\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 (messageTypeHandler?.validate !== undefined) {\n message = messageTypeHandler.validate(message);\n }\n\n } catch (e) {\n debugAndPrintError(e);\n client.leave(Protocol.WS_CLOSE_WITH_ERROR);\n return;\n }\n\n if (messageTypeHandler) {\n messageTypeHandler.callback(client, message);\n\n } else {\n (this.onMessageHandlers['*'] || this.onMessageHandlers['__no_message_handler']).callback(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 const messageTypeHandler = this.onMessageHandlers[messageType];\n\n let message = buffer.subarray(it.offset, buffer.byteLength);\n debugMessage(\"received: '%s' -> %j (roomId: %s)\", messageType, message, this.roomId);\n\n // custom message validation\n if (messageTypeHandler?.validate !== undefined) {\n message = messageTypeHandler.validate(message);\n }\n\n if (messageTypeHandler) {\n messageTypeHandler.callback(client, message);\n\n } else {\n (this.onMessageHandlers['*'] || this.onMessageHandlers['__no_message_handler']).callback(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.LEAVE_ROOM) {\n this._forciblyCloseClient(client, Protocol.WS_CLOSE_CONSENTED);\n }\n\n }\n\n protected _forciblyCloseClient(client: Client & 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 protected async _onLeave(client: Client, code?: number): Promise<any> {\n debugMatchMaking('onLeave, sessionId: \\'%s\\' (close code: %d, roomId: %s)', client.sessionId, code, this.roomId);\n\n // call 'onLeave' method only if the client has been successfully accepted.\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 (this.onLeave) {\n try {\n this.#_onLeaveConcurrent++;\n await this.onLeave(client, (code === Protocol.WS_CLOSE_CONSENTED));\n\n } catch (e) {\n debugAndPrintError(`onLeave error: ${(e && e.message || e || 'promise rejected')} (roomId: ${this.roomId})`);\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);\n });\n\n // @ts-ignore (client.state may be modified at onLeave())\n } else if (client.state !== ClientState.RECONNECTED) {\n await this._onAfterLeave(client);\n }\n }\n\n protected async _onAfterLeave(client: Client) {\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 protected async _incrementClientCount() {\n // lock automatically when maxClients is reached\n if (!this.#_locked && this.hasReachedMaxClients()) {\n this.#_maxClientsReached = true;\n this.lock.call(this, true);\n }\n\n await this.listing.updateOne({\n $inc: { clients: 1 },\n $set: { locked: this.#_locked },\n });\n }\n\n protected 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 this.unlock.call(this, true);\n }\n\n // update room listing cache\n await this.listing.updateOne({\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.onDispose !== undefined) {\n this.onDispose = wrapTryCatch(this.onDispose.bind(this), onUncaughtException, OnDisposeException, 'onDispose');\n }\n }\n\n}\n"],
5
- "mappings": ";AAAA,SAAS,cAAc;AACvB,SAAS,QAAuB,gBAAgB;AAEhD,OAAO,WAAW;AAClB,SAAS,oBAAoB;AAC7B,SAAS,cAAc;AAIvB,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AAGjC,SAAS,WAAW,iBAAiB,gBAAgB;AACrD,SAAS,UAAU,YAAY,oBAAoB;AACnD,SAAS,iBAAiB;AAE1B,SAAS,oBAAoB,kBAAkB,oBAAoB;AAEnE,SAAS,mBAAmB;AAC5B,SAA6C,aAAa,mBAAiC;AAC3F,SAAS,iBAAiB,mBAAmB,oBAAoB,iBAAiB,kBAAkB,oBAAmC,6BAA6B,2BAA2B;AAE/L,IAAM,qBAAqB,MAAO;AAClC,IAAM,8BAA8B,MAAO;AAC3C,IAAM,iBAAiB,IAAI,eAAe;AAEnC,IAAM,gCAAgC,OAAO,QAAQ,IAAI,kCAAkC,EAAE;AAQ7F,IAAK,oBAAL,kBAAKA,uBAAL;AACL,EAAAA,sCAAA,cAAW,KAAX;AACA,EAAAA,sCAAA,aAAU,KAAV;AACA,EAAAA,sCAAA,eAAY,KAAZ;AAHU,SAAAA;AAAA,GAAA;AAgBL,IAAe,OAAf,MAAe,MAA+E;AAAA,EA2HnG,cAAc;AApGd;AAAA;AAAA;AAAA;AAAA,SAAO,QAAe,IAAI,MAAM;AAIhC,+BAA8B;AAO9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAO,aAAqB;AAC5B,+BAA+B;AAQ/B;AAAA;AAAA;AAAA;AAAA;AAAA,SAAO,cAAuB;AAQ9B;AAAA;AAAA;AAAA;AAAA;AAAA,SAAO,YAAoB;AAsB3B;AAAA;AAAA;AAAA;AAAA;AAAA,SAAO,UAA2C,IAAI,YAAY;AAGlE;AAAA,SAAO,UAAU,IAAI,aAAa;AAGlC;AAAA,SAAU,sBAA8B;AACxC,SAAU,gBAAyE,CAAC;AACpF,SAAU,uBAAgE,CAAC;AAE3E,SAAU,iBAAsE,CAAC;AACjF,SAAQ,yBAAyB,oBAAI,IAAoB;AAEzD,SAAQ,oBAKJ;AAAA,MACA,wBAAwB;AAAA,QACtB,UAAU,CAAC,QAAgB,aAAqB,MAAe;AAC7D,gBAAM,eAAe,uBAAuB,WAAW;AACvD,6BAAmB,GAAG,YAAY,aAAa,KAAK,MAAM,GAAG;AAE7D,cAAI,WAAW;AAEb,mBAAO,MAAM,UAAU,iBAAiB,YAAY;AAAA,UAEtD,OAAO;AAEL,mBAAO,MAAM,SAAS,qBAAqB,YAAY;AAAA,UACzD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEF,SAAQ,cAAiC;AACzC,SAAQ,uBAA6D,CAAC;AAItE,SAAQ,iBAAoC;AAE5C,SAAQ,oBAA6B;AACrC,oBAAoB;AAOlB,SAAK,QAAQ,KAAK,WAAW,MAAM;AACjC,WAAK,SAAS,EACX,MAAM,CAAC,MAAM,mBAAmB,oBAAqB,KAAK,EAAE,SAAS,EAAE,WAAW,KAAK,kBAAmB,aAAa,KAAK,MAAM,GAAG,CAAC,EACtI,QAAQ,MAAM,KAAK,QAAQ,KAAK,YAAY,CAAC;AAAA,IAClD,CAAC;AAKD,QAAI,KAAK,wBAAwB,QAAW;AAC1C,WAAK,mCAAmC;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA/HA,IAAW,SAAS;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAW,WAAW;AACpB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAUA;AAAA,EACA;AAAA,EACA;AAAA,EAQA;AAAA,EACA;AAAA,EAQA;AAAA,EAQA;AAAA,EACA;AAAA,EAMA;AAAA,EA0DA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyBU,SAAS;AACjB,SAAK,UAAU,KAAK;AACpB,SAAK,gBAAgB,KAAK;AAC1B,SAAK,cAAc,KAAK;AACxB,SAAK,eAAe,KAAK;AAEzB,WAAO,iBAAiB,MAAM;AAAA,MAC5B,OAAO;AAAA,QACL,YAAY;AAAA,QACZ,KAAK,MAAM,KAAK;AAAA,QAChB,KAAK,CAAC,aAAoB;AACxB,cAAI,UAAU,YAAY,OAAO,QAAQ,MAAM,UAAa,SAAS,QAAQ,MAAM,QAAW;AAC5F,iBAAK,cAAc,IAAI,iBAAiB,CAAC;AAAA,UAC3C,WAAW,iBAAiB,UAAU;AACpC,kBAAM,IAAI,MAAM,gFAAgF;AAAA,UAClG,WAAW,aAAa,QAAW;AACjC,kBAAM,IAAI,MAAM,+HAA+H;AAAA,UACjJ;AACA,eAAK,YAAY,MAAM,QAAQ;AAC/B,eAAK,UAAU;AAAA,QACjB;AAAA,MACF;AAAA,MAEA,YAAY;AAAA,QACV,YAAY;AAAA,QACZ,KAAK,MAAM,KAAK;AAAA,QAChB,KAAK,CAAC,UAAkB;AACtB,eAAK,eAAe;AAEpB,cAAI,KAAK,mBAAmB,iBAA2B;AACrD,kBAAM,uBAAuB,KAAK,qBAAqB;AAGvD,gBAAI,CAAC,KAAK,qBAAqB,KAAK,uBAAuB,CAAC,sBAAsB;AAChF,mBAAK,sBAAsB;AAC3B,mBAAK,WAAW;AAChB,mBAAK,QAAQ,SAAS;AAAA,YACxB;AAGA,gBAAI,sBAAsB;AACxB,mBAAK,sBAAsB;AAC3B,mBAAK,WAAW;AAChB,mBAAK,QAAQ,SAAS;AAAA,YACxB;AAEA,iBAAK,QAAQ,aAAa;AAC1B,iBAAK,QAAQ,KAAK;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAAA,MAEA,aAAa;AAAA,QACX,YAAY;AAAA,QACZ,KAAK,MAAM,KAAK;AAAA,QAChB,KAAK,CAAC,UAAmB;AACvB,cACE,UAAU,KAAK,iBACf,KAAK,mBAAmB,mBACxB;AACA,iBAAK,gBAAgB;AACrB,iBAAK,wBAAwB;AAAA,UAC/B;AAAA,QACF;AAAA,MACF;AAAA,MAEA,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,KAAK,MAAM,KAAK;AAAA,QAChB,KAAK,CAAC,iBAAyB;AAC7B,eAAK,cAAc;AAEnB,cAAI,KAAK,iBAAiB;AACxB,0BAAc,KAAK,eAAe;AAClC,iBAAK,kBAAkB;AAAA,UACzB;AACA,cAAI,iBAAiB,QAAQ,iBAAiB,GAAG;AAC/C,iBAAK,kBAAkB,YAAY,MAAM,KAAK,eAAe,GAAG,YAAY;AAAA,UAC9E;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,YAAY,KAAK;AAGtB,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,KAAK;AAAA,IACpB;AAGA,SAAK,wBAAwB,KAAK,mBAAmB;AAErD,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAW,WAAW;AAAE,WAAO,KAAK;AAAA,EAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhD,IAAW,SAAS,UAAkB;AACpC,QAAI,KAAK,YAAY;AAEnB,YAAM,IAAI,YAAY,UAAU,mBAAmB,mCAAmC;AAAA,IACxF;AACA,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAW,SAAS;AAAE,WAAO,KAAK;AAAA,EAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ5C,IAAW,OAAO,QAAgB;AAChC,QAAI,KAAK,mBAAmB,oBAA8B,CAAC,WAAW;AAEpE,YAAM,IAAI,YAAY,UAAU,mBAAmB,qDAAqD;AAAA,IAC1G;AACA,SAAK,WAAW;AAAA,EAClB;AAAA,EAuBO,OACL,QACA,SACA,SACoB;AACpB,WAAO;AAAA,EACT;AAAA,EAEA,aAAa,OACX,OACA,SACA,SACkB;AAClB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,mBAAmB;AACxB,SAAK;AAAA,MACF,YACG,SAAS,2BACT,SAAS;AAAA,IACf;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBO,uBAAgC;AACrC,WACG,KAAK,QAAQ,SAAS,OAAO,KAAK,KAAK,aAAa,EAAE,UAAW,KAAK,cACvE,KAAK,mBAAmB;AAAA,EAE5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaO,uBAAuB,SAAiB;AAC7C,SAAK,sBAAsB;AAC3B,WAAO;AAAA,EACT;AAAA,EAEO,gBAAgB,WAAmB,mBAAqC;AAC7E,UAAM,eAAe,KAAK,cAAc,SAAS;AAGjD,QAAI,iBAAiB,QAAW;AAC9B,aAAO;AAAA,IACT;AAEA,QAAI,aAAa,CAAC,GAAG;AAEnB,aACE,qBACA,KAAK,eAAe,iBAAiB,IAAI,CAAC,MAAM,aAChD,KAAK,uBAAuB,IAAI,SAAS;AAAA,IAG7C,OAAO;AAEL,aAAO,aAAa,CAAC,MAAM;AAAA,IAC7B;AAAA,EACF;AAAA,EAEO,uBAAuB,mBAA2B;AACvD,UAAM,YAAY,KAAK,eAAe,iBAAiB,IAAI,CAAC;AAC5D,UAAM,eAAe,KAAK,cAAc,SAAS;AAEjD,QAAI,gBAAgB,aAAa,CAAC,GAAG;AACnC,WAAK,uBAAuB,IAAI,WAAW,iBAAiB;AAC5D,aAAO;AAAA,IAET,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYO,sBAAsB,gBAAqC,QAAgB,6BAAmC;AAEnH,QAAI,KAAK,qBAAqB;AAAE,oBAAc,KAAK,mBAAmB;AAAA,IAAG;AAEzE,QAAI,gBAAgB;AAClB,UAAI,KAAK,wBAAwB,QAAW;AAC1C,yBAAiB,aAAa,gBAAgB,KAAK,oBAAoB,KAAK,IAAI,GAAG,6BAA6B,uBAAuB;AAAA,MACzI;AAEA,WAAK,sBAAsB,YAAY,MAAM;AAC3C,aAAK,MAAM,KAAK;AAChB,uBAAe,KAAK,MAAM,SAAS;AAAA,MACrC,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,aAAa,cAAmC;AACrD,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKO,SAAS,UAAiB;AAC/B,SAAK,QAAQ;AAAA,EACf;AAAA,EAEO,cAAc,YAA+B;AAClD,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,MAAa,YAAY,MAAyB;AAChD,QAAI,CAAC,KAAK,QAAQ,UAAU;AAC1B,WAAK,QAAQ,WAAW;AAAA,IAE1B,OAAO;AACL,iBAAW,SAAS,MAAM;AACxB,YAAI,CAAC,KAAK,eAAe,KAAK,GAAG;AAAE;AAAA,QAAU;AAC7C,aAAK,QAAQ,SAAS,KAAK,IAAI,KAAK,KAAK;AAAA,MAC3C;AAGA,UAAI,kBAAkB,KAAK,SAAS;AAClC,QAAC,KAAK,QAAgB,aAAa,UAAU;AAAA,MAC/C;AAAA,IACF;AAEA,QAAI,KAAK,mBAAmB,iBAA2B;AACrD,YAAM,KAAK,QAAQ,KAAK;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,MAAa,WAAW,OAAgB,MAAM;AAC5C,QAAI,KAAK,QAAQ,YAAY,KAAM;AAEnC,SAAK,QAAQ,UAAU;AAEvB,QAAI,KAAK,mBAAmB,iBAA2B;AACrD,YAAM,KAAK,QAAQ,KAAK;AAAA,IAC1B;AAEA,SAAK,QAAQ,KAAK,qBAAqB,IAAI;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,OAAO;AAElB,SAAK,oBAAqB,UAAU,CAAC,MAAM;AAG3C,QAAI,KAAK,UAAU;AAAE;AAAA,IAAQ;AAE7B,SAAK,WAAW;AAEhB,UAAM,KAAK,QAAQ,UAAU;AAAA,MAC3B,MAAM,EAAE,QAAQ,KAAK,SAAS;AAAA,IAChC,CAAC;AAED,SAAK,QAAQ,KAAK,MAAM;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,SAAS;AAEpB,QAAI,UAAU,CAAC,MAAM,QAAW;AAC9B,WAAK,oBAAoB;AAAA,IAC3B;AAGA,QAAI,CAAC,KAAK,UAAU;AAAE;AAAA,IAAQ;AAE9B,SAAK,WAAW;AAEhB,UAAM,KAAK,QAAQ,UAAU;AAAA,MAC3B,MAAM,EAAE,QAAQ,KAAK,SAAS;AAAA,IAChC,CAAC;AAED,SAAK,QAAQ,KAAK,QAAQ;AAAA,EAC5B;AAAA,EAGO,KAAK,QAAgB,eAAoB,kBAAuC,SAA8B;AACnH,WAAO,KAAK,6EAA6E;AACzF,WAAO,KAAK,eAAe,kBAAkB,OAAO;AAAA,EACtD;AAAA,EAEO,UAAU,MAAuB,SAAe,SAA6B;AAClF,QAAI,WAAW,QAAQ,gBAAgB;AACrC,aAAO,QAAQ;AACf,WAAK,qBAAqB,KAAK,CAAC,aAAa,SAAS,CAAC;AACvD;AAAA,IACF;AAEA,SAAK,qBAAqB,MAAM,SAAS,OAAO;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKO,eAAe,MAAuB,SAAqB,SAA4B;AAC5F,QAAI,WAAW,QAAQ,gBAAgB;AACrC,aAAO,QAAQ;AACf,WAAK,qBAAqB,KAAK,CAAC,kBAAkB,SAAS,CAAC;AAC5D;AAAA,IACF;AAEA,SAAK,qBAAqB,MAAgB,SAAS,OAAO;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKO,iBAAiB;AACtB,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,KAAK,KAAK;AAAA,IAC/B;AAEA,QAAI,CAAC,KAAK,qBAAqB;AAC7B,WAAK,MAAM,KAAK;AAAA,IAClB;AAEA,QAAI,CAAC,KAAK,OAAO;AACf,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,KAAK,YAAY,aAAa,KAAK,SAAS,KAAK,KAAK;AAGzE,SAAK,2BAA2B;AAEhC,WAAO;AAAA,EACT;AAAA,EAWO,UACL,aACA,UACA,UACA;AACA,SAAK,kBAAkB,WAAW,IAAK,KAAK,wBAAwB,SAChE,EAAE,UAAU,UAAU,aAAa,UAAU,KAAK,oBAAoB,KAAK,IAAI,GAAG,oBAAoB,aAAa,OAAO,WAAW,EAAE,IACvI,EAAE,UAAU,SAAS;AAIzB,WAAO,MAAM,OAAO,KAAK,kBAAkB,WAAW;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,WAAW,YAAoB,SAAS,oBAAkC;AAE/E,QAAI,KAAK,mBAAmB,mBAA6B;AACvD,aAAO,QAAQ,QAAQ,+BAA+B,KAAK,MAAM,yBAAyB;AAAA,IAE5F,WAAW,KAAK,mBAAmB,kBAA4B;AAC7D,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAEA,SAAK,iBAAiB;AACtB,SAAK,QAAQ,OAAO;AAEpB,SAAK,gBAAgB;AAErB,UAAM,uBAAuB,IAAI,QAAc,CAAC,YAC9C,KAAK,QAAQ,KAAK,cAAc,MAAM,QAAQ,CAAC,CAAC;AAGlD,eAAW,CAAC,GAAG,YAAY,KAAK,OAAO,OAAO,KAAK,cAAc,GAAG;AAClE,mBAAa,OAAO,IAAI,MAAM,eAAe,CAAC;AAAA,IAChD;AAEA,QAAI,aAAa,KAAK,QAAQ;AAC9B,QAAI,aAAa,GAAG;AAElB,aAAO,cAAc;AACnB,aAAK,qBAAqB,KAAK,QAAQ,UAAU,GAA6B,SAAS;AAAA,MACzF;AAAA,IAEF,OAAO;AAEL,WAAK,QAAQ,KAAK,SAAS;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,OAAc,SAAS,EAAE,QAAgC,aAA0B;AACjF,UAAM,YAAY,OAAO;AAGzB,WAAO,oBAAoB,WAAW;AAEtC,QAAI,KAAK,qBAAqB,SAAS,GAAG;AACxC,mBAAa,KAAK,qBAAqB,SAAS,CAAC;AACjD,aAAO,KAAK,qBAAqB,SAAS;AAAA,IAC5C;AAGA,QAAI,KAAK,qBAAqB;AAC5B,mBAAa,KAAK,mBAAmB;AACrC,WAAK,sBAAsB;AAAA,IAC7B;AAGA,UAAM,CAAC,aAAa,UAAU,YAAY,qBAAqB,IAAI,KAAK,cAAc,SAAS;AAS/F,QAAI,YAAY;AACd,YAAM,IAAI,YAAY,UAAU,mBAAmB,kBAAkB;AAAA,IACvE;AACA,SAAK,cAAc,SAAS,EAAE,CAAC,IAAI;AACnC,qBAAiB,4DAA8D,OAAO,WAAW,KAAK,MAAM;AAG5G,WAAO,uBAAuB,KAAK;AAGnC,WAAO,IAAI,SAAS,IAAI,CAAC,MAAM,OAAO,QAAQ,YAAY;AAC1D,WAAO,IAAI,KAAK,SAAS,OAAO,IAAI,SAAS,CAAC;AAE9C,QAAI,uBAAuB;AACzB,YAAM,4BAA4B,KAAK,uBAAuB,IAAI,SAAS;AAC3E,UAAI,2BAA2B;AAC7B,aAAK,QAAQ,KAAK,MAAM;AAKxB,cAAM,KAAK,eAAe,yBAAyB,IAAI,CAAC,EAAE,QAAQ,MAAM;AAAA,MAE1E,OAAO;AACL,cAAM,eAAgB,QAAQ,IAAI,aAAa,eAC3C,qBACA;AACJ,cAAM,IAAI,YAAY,UAAU,mBAAmB,YAAY;AAAA,MACjE;AAAA,IAEF,OAAO;AACL,UAAI;AACF,YAAI,UAAU;AACZ,iBAAO,OAAO;AAAA,QAEhB,WAAW,KAAK,WAAW,MAAK,UAAU,QAAQ;AAChD,cAAI;AACF,mBAAO,OAAO,MAAM,KAAK,OAAO,QAAQ,aAAa,WAAW;AAEhE,gBAAI,CAAC,OAAO,MAAM;AAChB,oBAAM,IAAI,YAAY,UAAU,aAAa,eAAe;AAAA,YAC9D;AAAA,UAEF,SAAS,GAAG;AAEV,mBAAO,KAAK,cAAc,SAAS;AACnC,kBAAM,KAAK,sBAAsB;AACjC,kBAAM;AAAA,UACR;AAAA,QACF;AAKA,YAAI,OAAO,UAAU,YAAY,SAAS;AACxC,gBAAM,IAAI,YAAY,SAAS,qBAAqB,sBAAsB;AAAA,QAC5E;AAEA,aAAK,QAAQ,KAAK,MAAM;AAMxB,eAAO,eAAe,KAAK,eAAe,WAAW;AAAA,UACnD,OAAO,KAAK,cAAc,SAAS;AAAA,UACnC,YAAY;AAAA,QACd,CAAC;AAED,YAAI,KAAK,QAAQ;AACf,gBAAM,KAAK,OAAO,QAAQ,aAAa,OAAO,IAAI;AAAA,QACpD;AAGA,YAAI,OAAO,UAAU,YAAY,SAAS;AACxC,gBAAM,IAAI,MAAM,aAAa;AAAA,QAE/B,OAAO;AAEL,iBAAO,KAAK,cAAc,SAAS;AAGnC,eAAK,QAAQ,KAAK,QAAQ,MAAM;AAAA,QAClC;AAAA,MAEF,SAAS,GAAG;AACV,cAAM,KAAK,SAAS,QAAQ,SAAS,mBAAmB;AAGxD,eAAO,KAAK,cAAc,SAAS;AAGnC,YAAI,CAAC,EAAE,MAAM;AACX,YAAE,OAAO,UAAU;AAAA,QACrB;AAEA,cAAM;AAAA,MACR;AAAA,IACF;AAGA,QAAI,OAAO,UAAU,YAAY,SAAS;AACxC,aAAO,IAAI,eAAe,SAAS,OAAO,IAAI,SAAS,CAAC;AAGxD,aAAO,IAAI,SAAS,IAAI,KAAK,SAAS,KAAK,MAAM,MAAM;AACvD,aAAO,IAAI,KAAK,SAAS,OAAO,IAAI,SAAS,CAAC;AAG9C,aAAO,IAAI,GAAG,WAAW,KAAK,WAAW,KAAK,MAAM,MAAM,CAAC;AAG3D,aAAO,IAAI,gBAAgB,SAAS,SAAS;AAAA,QAC3C,OAAO;AAAA,QACP,KAAK,YAAY;AAAA,QACjB,KAAK,YAAY,aAAa,KAAK,YAAY,UAAU;AAAA,MAC3D,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYO,kBAAkB,gBAAwB,SAA8C;AAM7F,QAAK,eAA4C,sBAAsB,QAAW;AAEhF,aAAO,QAAQ,OAAO,IAAI,MAAM,YAAY,CAAC;AAAA,IAC/C;AAEA,QAAI,YAAY,QAAW;AACzB,cAAQ,KAAK,kFAAoF;AACjG,gBAAU;AAAA,IACZ;AAEA,QAAI,YAAY,UAAU;AACxB,gBAAU;AAAA,IACZ;AAEA,QAAI,KAAK,mBAAmB,mBAA6B;AAEvD,aAAO,QAAQ,OAAO,IAAI,MAAM,WAAW,CAAC;AAAA,IAC9C;AAEA,UAAM,YAAY,eAAe;AACjC,UAAM,oBAAoB,eAAe;AAEzC,SAAK,aAAa,WAAW,MAAM,eAAe,MAAM,SAAS,IAAI;AAGrE,UAAM,eAAe,IAAI,SAAiC;AAC1D,SAAK,eAAe,iBAAiB,IAAI,CAAC,WAAW,YAAY;AAEjE,QAAI,YAAY,UAAU;AAExB,WAAK,qBAAqB,SAAS,IAAI,WAAW,MAChD,aAAa,OAAO,KAAK,GAAG,UAAU,GAAI;AAAA,IAC9C;AAEA,UAAM,UAAU,MAAM;AACpB,aAAO,KAAK,eAAe,iBAAiB;AAC5C,aAAO,KAAK,cAAc,SAAS;AACnC,aAAO,KAAK,qBAAqB,SAAS;AAC1C,WAAK,uBAAuB,OAAO,SAAS;AAAA,IAC9C;AAEA,iBACE,KAAK,CAAC,cAAc;AAClB,gBAAU,OAAO,eAAe;AAChC,gBAAU,WAAW,eAAe;AAGpC,qBAAe,QAAQ,YAAY;AACnC,qBAAe,MAAM,UAAU;AAC/B,qBAAe,oBAAoB,UAAU;AAC7C,mBAAa,KAAK,qBAAqB,SAAS,CAAC;AACjD,cAAQ;AAAA,IACV,CAAC,EACD,MAAM,MAAM;AACV,cAAQ;AACR,WAAK,wBAAwB;AAAA,IAC/B,CAAC;AAEH,WAAO;AAAA,EACT;AAAA,EAEU,wBAAwB,mBAA2B,GAAG;AAC9D,iBAAa,KAAK,mBAAmB;AAErC,QAAI,CAAC,KAAK,eAAe;AACvB;AAAA,IACF;AAEA,SAAK,sBAAsB,WAAW,MAAM;AAC1C,WAAK,sBAAsB;AAC3B,WAAK,gBAAgB;AAAA,IACvB,GAAG,mBAAmB,GAAI;AAAA,EAC5B;AAAA,EAEQ,qBAAqB,MAAuB,SAA4B,UAA6B,CAAC,GAAG;AAC/G,iBAAa,8BAA8B,SAAS,KAAK,MAAM;AAE/D,UAAM,iBAAkB,mBAAmB,aACvC,gBAAgB,IAAI,SAAS,iBAAiB,MAAM,QAAW,OAAO,IACtE,gBAAgB,IAAI,SAAS,WAAW,MAAM,OAAO;AAEzD,UAAM,SAAU,OAAQ,QAAQ,WAAY,cACxC,MAAM,QAAQ,QAAQ,MAAM,IAC1B,QAAQ,SACR,CAAC,QAAQ,MAAM,IACjB;AAEJ,QAAI,aAAa,KAAK,QAAQ;AAC9B,WAAO,cAAc;AACnB,YAAM,SAAS,KAAK,QAAQ,UAAU;AAEtC,UAAI,CAAC,UAAU,CAAC,OAAO,SAAS,MAAM,GAAG;AACvC,eAAO,WAAW,cAAc;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA,EAEU,cAAc,QAAsB;AAC5C,WAAO,IAAI,KAAK,YAAY,aAAa,MAAM,CAAC;AAAA,EAClD;AAAA,EAEU,6BAA6B;AACrC,UAAM,SAAS,KAAK,qBAAqB;AAEzC,QAAI,SAAS,GAAG;AACd,eAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,cAAM,CAAC,QAAQ,IAAI,IAAI,KAAK,qBAAqB,CAAC;AAElD,YAAI,WAAW,aAAa;AAC1B,eAAK,UAAU,MAAM,MAAM,IAAI;AAAA,QAEjC,OAAO;AACL,UAAC,OAAkB,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC3C;AAAA,MACF;AAIA,WAAK,qBAAqB,OAAO,GAAG,MAAM;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,MAAgB,aACd,WACA,cAAmB,MACnB,WAAgB,QAChB,UAAkB,KAAK,qBACvB,oBAA6B,OAC7B,qBACA;AACA,QAAI,CAAC,qBAAqB,KAAK,qBAAqB,GAAG;AACrD,aAAO;AAAA,IACT;AAEA,SAAK,cAAc,SAAS,IAAI,CAAC,aAAa,UAAU,OAAO,iBAAiB;AAEhF,QAAI,CAAC,mBAAmB;AACtB,YAAM,KAAK,sBAAsB;AAEjC,WAAK,qBAAqB,SAAS,IAAI,WAAW,YAAY;AAC5D,eAAO,KAAK,cAAc,SAAS;AACnC,eAAO,KAAK,qBAAqB,SAAS;AAC1C,cAAM,KAAK,sBAAsB;AAAA,MACnC,GAAG,UAAU,GAAI;AAEjB,WAAK,wBAAwB,OAAO;AAAA,IACtC;AAKA,QAAI,qBAAqB;AACvB,WAAK,uBAAuB,IAAI,WAAW,SAAS;AAAA,IACtD;AAEA,WAAO;AAAA,EACT;AAAA,EAEU,kBAAkB;AAC1B,UAAM,cACJ,KAAK,wBAAwB;AAAA,IAC7B,KAAK,iBACL,KAAK,wBAAwB,UAC7B,KAAK,QAAQ,WAAW,KACxB,OAAO,KAAK,KAAK,aAAa,EAAE,WAAW;AAG7C,QAAI,aAAa;AACf,WAAK,QAAQ,KAAK,SAAS;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAgB,WAAyB;AACvC,SAAK,iBAAiB;AAEtB,SAAK,QAAQ,OAAO;AAEpB,QAAI;AACJ,QAAI,KAAK,WAAW;AAClB,uBAAiB,KAAK,UAAU;AAAA,IAClC;AAEA,QAAI,KAAK,iBAAiB;AACxB,oBAAc,KAAK,eAAe;AAClC,WAAK,kBAAkB;AAAA,IACzB;AAEA,QAAI,KAAK,qBAAqB;AAC5B,oBAAc,KAAK,mBAAmB;AACtC,WAAK,sBAAsB;AAAA,IAC7B;AAEA,QAAI,KAAK,qBAAqB;AAC5B,oBAAc,KAAK,mBAAmB;AACtC,WAAK,sBAAsB;AAAA,IAC7B;AAGA,SAAK,MAAM,MAAM;AACjB,SAAK,MAAM,KAAK;AAEhB,WAAO,OAAO,kBAAkB,QAAQ,QAAQ;AAAA,EAClD;AAAA,EAEU,WAAW,QAAgC,QAAgB;AAEnE,QAAI,OAAO,UAAU,YAAY,SAAS;AAAE;AAAA,IAAQ;AAEpD,UAAM,KAAe,EAAE,QAAQ,EAAE;AACjC,UAAM,OAAO,OAAO,CAAC;AAErB,QAAI,CAAC,QAAQ;AACX,yBAAmB,GAAG,KAAK,QAAQ,aAAa,KAAK,MAAM,+BAA+B,MAAM,EAAE;AAClG;AAAA,IACF;AAEA,QAAI,SAAS,SAAS,WAAW;AAC/B,YAAM,cAAe,OAAO,YAAY,QAAQ,EAAE,IAC9C,OAAO,OAAO,QAAQ,EAAE,IACxB,OAAO,OAAO,QAAQ,EAAE;AAC5B,YAAM,qBAAqB,KAAK,kBAAkB,WAAW;AAE7D,UAAI;AACJ,UAAI;AACF,kBAAW,OAAO,aAAa,GAAG,SAC9B,OAAO,OAAO,SAAS,GAAG,QAAQ,OAAO,UAAU,CAAC,IACpD;AACJ,qBAAa,qCAAqC,aAAa,SAAS,KAAK,MAAM;AAGnF,YAAI,oBAAoB,aAAa,QAAW;AAC9C,oBAAU,mBAAmB,SAAS,OAAO;AAAA,QAC/C;AAAA,MAEF,SAAS,GAAG;AACV,2BAAmB,CAAC;AACpB,eAAO,MAAM,SAAS,mBAAmB;AACzC;AAAA,MACF;AAEA,UAAI,oBAAoB;AACtB,2BAAmB,SAAS,QAAQ,OAAO;AAAA,MAE7C,OAAO;AACL,SAAC,KAAK,kBAAkB,GAAG,KAAK,KAAK,kBAAkB,sBAAsB,GAAG,SAAS,QAAQ,aAAa,OAAO;AAAA,MACvH;AAAA,IAEF,WAAW,SAAS,SAAS,iBAAiB;AAC5C,YAAM,cAAe,OAAO,YAAY,QAAQ,EAAE,IAC9C,OAAO,OAAO,QAAQ,EAAE,IACxB,OAAO,OAAO,QAAQ,EAAE;AAC5B,YAAM,qBAAqB,KAAK,kBAAkB,WAAW;AAE7D,UAAI,UAAU,OAAO,SAAS,GAAG,QAAQ,OAAO,UAAU;AAC1D,mBAAa,qCAAqC,aAAa,SAAS,KAAK,MAAM;AAGnF,UAAI,oBAAoB,aAAa,QAAW;AAC9C,kBAAU,mBAAmB,SAAS,OAAO;AAAA,MAC/C;AAEA,UAAI,oBAAoB;AACtB,2BAAmB,SAAS,QAAQ,OAAO;AAAA,MAE7C,OAAO;AACL,SAAC,KAAK,kBAAkB,GAAG,KAAK,KAAK,kBAAkB,sBAAsB,GAAG,SAAS,QAAQ,aAAa,OAAO;AAAA,MACvH;AAAA,IAEF,WAAW,SAAS,SAAS,aAAa,OAAO,UAAU,YAAY,SAAS;AAE9E,aAAO,QAAQ,YAAY;AAC3B,aAAO,YAAY,KAAK,MAAM;AAG9B,UAAI,KAAK,OAAO;AACd,aAAK,cAAc,MAAM;AAAA,MAC3B;AAGA,UAAI,OAAO,kBAAkB,SAAS,GAAG;AACvC,eAAO,kBAAkB,QAAQ,CAAC,aAAa,OAAO,IAAI,QAAQ,CAAC;AAAA,MACrE;AACA,aAAO,OAAO;AAAA,IAEhB,WAAW,SAAS,SAAS,YAAY;AACvC,WAAK,qBAAqB,QAAQ,SAAS,kBAAkB;AAAA,IAC/D;AAAA,EAEF;AAAA,EAEU,qBAAqB,QAAgC,WAAmB;AAEhF,WAAO,IAAI,mBAAmB,SAAS;AAGvC,WAAO,IAAI,eAAe,SAAS,OAAO,IAAI,SAAS,CAAC;AAGxD,SAAK,SAAS,QAAQ,SAAS,EAAE,KAAK,MAAM,OAAO,MAAM,SAAS,CAAC;AAAA,EACrE;AAAA,EAEA,MAAgB,SAAS,QAAgB,MAA6B;AACpE,qBAAiB,yDAA2D,OAAO,WAAW,MAAM,KAAK,MAAM;AAG/G,WAAO,QAAQ,YAAY;AAE3B,QAAI,CAAC,KAAK,QAAQ,OAAO,MAAM,GAAG;AAEhC;AAAA,IACF;AAEA,QAAI,KAAK,SAAS;AAChB,UAAI;AACF,aAAK;AACL,cAAM,KAAK,QAAQ,QAAS,SAAS,SAAS,kBAAmB;AAAA,MAEnE,SAAS,GAAG;AACV,2BAAmB,kBAAmB,KAAK,EAAE,WAAW,KAAK,kBAAmB,aAAa,KAAK,MAAM,GAAG;AAAA,MAE7G,UAAE;AACA,aAAK;AAAA,MACP;AAAA,IACF;AAGA,QAAI,KAAK,eAAe,OAAO,iBAAiB,GAAG;AACjD,WAAK,eAAe,OAAO,iBAAiB,EAAE,CAAC,EAAE,MAAM,YAAY;AACjE,cAAM,KAAK,cAAc,MAAM;AAAA,MACjC,CAAC;AAAA,IAGH,WAAW,OAAO,UAAU,YAAY,aAAa;AACnD,YAAM,KAAK,cAAc,MAAM;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,MAAgB,cAAc,QAAgB;AAE5C,UAAM,cAAc,MAAM,KAAK,sBAAsB;AAGrD,QAAI,KAAK,cAAc,OAAO,SAAS,MAAM,QAAW;AACtD,WAAK,QAAQ,KAAK,SAAS,QAAQ,WAAW;AAAA,IAChD;AAAA,EAEF;AAAA,EAEA,MAAgB,wBAAwB;AAEtC,QAAI,CAAC,KAAK,YAAY,KAAK,qBAAqB,GAAG;AACjD,WAAK,sBAAsB;AAC3B,WAAK,KAAK,KAAK,MAAM,IAAI;AAAA,IAC3B;AAEA,UAAM,KAAK,QAAQ,UAAU;AAAA,MAC3B,MAAM,EAAE,SAAS,EAAE;AAAA,MACnB,MAAM,EAAE,QAAQ,KAAK,SAAS;AAAA,IAChC,CAAC;AAAA,EACH;AAAA,EAEA,MAAgB,wBAAwB;AACtC,UAAM,cAAc,KAAK,gBAAgB;AAEzC,QAAI,KAAK,mBAAmB,mBAA6B;AACvD,aAAO;AAAA,IACT;AAGA,QAAI,CAAC,aAAa;AAChB,UAAI,KAAK,uBAAuB,CAAC,KAAK,mBAAmB;AACvD,aAAK,sBAAsB;AAC3B,aAAK,OAAO,KAAK,MAAM,IAAI;AAAA,MAC7B;AAGA,YAAM,KAAK,QAAQ,UAAU;AAAA,QAC3B,MAAM,EAAE,SAAS,GAAG;AAAA,QACpB,MAAM,EAAE,QAAQ,KAAK,SAAS;AAAA,MAChC,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,qCAAqC;AACnC,UAAM,sBAAsB,KAAK,oBAAoB,KAAK,IAAI;AAC9D,UAAM,qBAAqB,KAAK,MAAM;AACtC,SAAK,MAAM,aAAa,CAAC,IAAI,YAAY,SAAS;AAChD,aAAO,mBAAmB,KAAK,KAAK,OAAO,aAAa,IAAI,qBAAqB,qBAAqB,YAAY,GAAG,SAAS,GAAG,IAAI;AAAA,IACvI;AAEA,UAAM,sBAAsB,KAAK,MAAM;AACvC,SAAK,MAAM,cAAc,CAAC,IAAI,YAAY,SAAS;AACjD,aAAO,oBAAoB,KAAK,KAAK,OAAO,aAAa,IAAI,qBAAqB,qBAAqB,aAAa,GAAG,SAAS,GAAG,IAAI;AAAA,IACzI;AAEA,QAAI,KAAK,aAAa,QAAW;AAC/B,WAAK,WAAW,aAAa,KAAK,SAAS,KAAK,IAAI,GAAG,qBAAqB,mBAAmB,YAAY,IAAI;AAAA,IACjH;AAEA,QAAI,KAAK,WAAW,QAAW;AAC7B,WAAK,SAAS,aAAa,KAAK,OAAO,KAAK,IAAI,GAAG,qBAAqB,iBAAiB,UAAU,IAAI;AAAA,IACzG;AAEA,QAAI,KAAK,WAAW,QAAW;AAC7B,WAAK,SAAS,aAAa,KAAK,OAAO,KAAK,IAAI,GAAG,qBAAqB,iBAAiB,UAAU,IAAI;AAAA,IACzG;AAEA,QAAI,KAAK,YAAY,QAAW;AAC9B,WAAK,UAAU,aAAa,KAAK,QAAQ,KAAK,IAAI,GAAG,qBAAqB,kBAAkB,WAAW,IAAI;AAAA,IAC7G;AAEA,QAAI,KAAK,cAAc,QAAW;AAChC,WAAK,YAAY,aAAa,KAAK,UAAU,KAAK,IAAI,GAAG,qBAAqB,oBAAoB,WAAW;AAAA,IAC/G;AAAA,EACF;AAEF;",
4
+ "sourcesContent": ["import { unpack } from '@colyseus/msgpackr';\nimport { decode, type Iterator, $changes } from '@colyseus/schema';\n\nimport Clock from '@colyseus/timer';\nimport { EventEmitter } from 'events';\nimport { logger } from './Logger.js';\n\nimport { Presence } from './presence/Presence.js';\n\nimport { NoneSerializer } from './serializer/NoneSerializer.js';\nimport { SchemaSerializer } from './serializer/SchemaSerializer.js';\nimport { Serializer } from './serializer/Serializer.js';\n\nimport { ErrorCode, getMessageBytes, Protocol } from './Protocol.js';\nimport { Deferred, generateId, wrapTryCatch } from './utils/Utils.js';\nimport { isDevMode } from './utils/DevMode.js';\n\nimport { debugAndPrintError, debugMatchMaking, debugMessage } from './Debug.js';\nimport { RoomCache } from './matchmaker/driver/api.js';\nimport { ServerError } from './errors/ServerError.js';\nimport { AuthContext, Client, ClientPrivate, ClientArray, ClientState, ISendOptions } from './Transport.js';\nimport { OnAuthException, OnCreateException, OnDisposeException, OnJoinException, OnLeaveException, OnMessageException, RoomException, SimulationIntervalException, TimedEventException } from './errors/RoomExceptions.js';\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 IBroadcastOptions extends ISendOptions {\n except?: Client | Client[];\n}\n\nexport enum RoomInternalState {\n CREATING = 0,\n CREATED = 1,\n DISPOSING = 2,\n}\n\nexport type ExtractUserData<T> = T extends ClientArray<infer U> ? U : never;\nexport type ExtractAuthData<T> = T extends ClientArray<infer _, infer U> ? U : never;\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 */\nexport abstract class Room<State extends object= any, Metadata= any, UserData = any, AuthData = any> {\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 public get metadata() {\n return this.listing.metadata;\n }\n\n public listing: RoomCache<Metadata>;\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 = DEFAULT_PATCH_RATE;\n #_patchRate: number;\n #_patchInterval: NodeJS.Timeout;\n\n /**\n * The state instance you provided to `setState()`.\n */\n public state: State;\n #_state: State;\n\n /**\n * The presence instance. Check Presence API for more details.\n *\n * @see {@link https://docs.colyseus.io/colyseus/server/presence/|Presence API}\n */\n public presence: Presence;\n\n /**\n * The array of connected clients.\n *\n * @see {@link https://docs.colyseus.io/colyseus/server/room/#client|Client instance}\n */\n public clients: ClientArray<UserData, AuthData> = new ClientArray();\n\n /** @internal */\n public _events = new EventEmitter();\n\n // seat reservation & reconnection\n protected seatReservationTime: number = DEFAULT_SEAT_RESERVATION_TIME;\n protected reservedSeats: { [sessionId: string]: [any, any, boolean?, boolean?] } = {};\n protected reservedSeatTimeouts: { [sessionId: string]: NodeJS.Timeout } = {};\n\n protected _reconnections: { [reconnectionToken: string]: [string, Deferred] } = {};\n private _reconnectingSessionId = new Map<string, string>();\n\n private onMessageHandlers: {\n [id: string]: {\n callback: (...args: any[]) => void,\n validate?: (data: unknown) => any,\n }\n } = {\n '__no_message_handler': {\n callback: (client: Client, messageType: string, _: unknown) => {\n const errorMessage = `room onMessage for \"${messageType}\" not registered.`;\n debugAndPrintError(`${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(Protocol.WS_CLOSE_WITH_ERROR, errorMessage);\n }\n }\n }\n };\n\n private _serializer: Serializer<State> = noneSerializer;\n private _afterNextPatchQueue: Array<[string | Client, IArguments]> = [];\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 protected __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: State) => {\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.#_maxClients = value;\n\n if (this._internalState === RoomInternalState.CREATED) {\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 }\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 }\n\n this.listing.maxClients = value;\n this.listing.save();\n }\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 }\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 // set default _autoDisposeTimeout\n this.resetAutoDisposeTimeout(this.seatReservationTime);\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 public onBeforePatch?(state: State): void | Promise<any>;\n public onCreate?(options: any): void | Promise<any>;\n public onJoin?(client: Client<UserData, AuthData>, options?: any, auth?: AuthData): void | Promise<any>;\n public onLeave?(client: Client<UserData, AuthData>, consented?: boolean): void | Promise<any>;\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<this>, methodName: 'onCreate' | 'onAuth' | 'onJoin' | 'onLeave' | 'onDispose' | 'onMessage' | 'setSimulationInterval' | 'setInterval' | 'setTimeout'): void;\n\n public onAuth(\n client: Client<UserData, AuthData>,\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 ? Protocol.WS_CLOSE_DEVMODE_RESTART\n : Protocol.WS_CLOSE_CONSENTED\n );\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 * 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 * @param seconds - number of seconds.\n * @returns The modified Room object.\n */\n public setSeatReservationTime(seconds: number) {\n this.seatReservationTime = seconds;\n return this;\n }\n\n public hasReservedSeat(sessionId: string, reconnectionToken?: string): boolean {\n const reservedSeat = this.reservedSeats[sessionId];\n\n // seat reservation not found / expired\n if (reservedSeat === undefined) {\n return false;\n }\n\n if (reservedSeat[3]) {\n // reconnection\n return (\n reconnectionToken &&\n this._reconnections[reconnectionToken]?.[0] === sessionId &&\n this._reconnectingSessionId.has(sessionId)\n );\n\n } else {\n // seat reservation not consumed\n return reservedSeat[2] === false;\n }\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 this._reconnectingSessionId.set(sessionId, reconnectionToken);\n return sessionId;\n\n } else {\n return undefined;\n }\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: State) {\n this.state = newState;\n }\n\n public setSerializer(serializer: Serializer<State>) {\n this._serializer = serializer;\n }\n\n public async setMetadata(meta: Partial<Metadata>) {\n if (!this.listing.metadata) {\n this.listing.metadata = meta as Metadata;\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 (this._internalState === RoomInternalState.CREATED) {\n await this.listing.save();\n }\n }\n\n public async setPrivate(bool: boolean = true) {\n if (this.listing.private === bool) return;\n\n this.listing.private = bool;\n\n if (this._internalState === RoomInternalState.CREATED) {\n await this.listing.save();\n }\n\n this._events.emit('visibility-change', bool);\n }\n\n /**\n * Locking the room will remove it from the pool of available rooms for new clients to connect to.\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 await this.listing.updateOne({\n $set: { locked: this.#_locked },\n });\n\n this._events.emit('lock');\n }\n\n /**\n * Unlocking the room returns it to the pool of available rooms for new clients to connect to.\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 await this.listing.updateOne({\n $set: { locked: this.#_locked },\n });\n\n this._events.emit('unlock');\n }\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 public broadcast(type: string | number, message?: any, options?: IBroadcastOptions) {\n if (options && options.afterNextPatch) {\n delete options.afterNextPatch;\n this._afterNextPatchQueue.push(['broadcast', arguments]);\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 public onMessage<T = any>(\n messageType: '*',\n callback: (client: Client<UserData, AuthData>, type: string | number, message: T) => void\n );\n public onMessage<T = any>(\n messageType: string | number,\n callback: (client: Client<UserData, AuthData>, message: T) => void,\n validate?: (message: unknown) => T,\n );\n public onMessage<T = any>(\n messageType: '*' | string | number,\n callback: (...args: any[]) => void,\n validate?: (message: unknown) => T,\n ) {\n this.onMessageHandlers[messageType] = (this.onUncaughtException !== undefined)\n ? { validate, callback: wrapTryCatch(callback, this.onUncaughtException.bind(this), OnMessageException, 'onMessage', false, messageType) }\n : { validate, callback };\n\n\n // returns a method to unbind the callback\n return () => delete this.onMessageHandlers[messageType];\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 = Protocol.WS_CLOSE_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 this.listing.remove();\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 for (const [_, reconnection] of Object.values(this._reconnections)) {\n reconnection.reject(new Error(\"disconnecting\"));\n }\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 Client & 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 public async ['_onJoin'](client: Client & ClientPrivate, authContext: AuthContext) {\n const sessionId = client.sessionId;\n\n // generate unique private 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 // 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 previousReconnectionToken = this._reconnectingSessionId.get(sessionId);\n if (previousReconnectionToken) {\n this.clients.push(client);\n //\n // await for reconnection:\n // (end user may customize the reconnection token at this step)\n //\n await this._reconnections[previousReconnectionToken]?.[1].resolve(client);\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(Protocol.WS_CLOSE_GOING_AWAY, '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 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 Error(\"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) {\n await this._onLeave(client, Protocol.WS_CLOSE_GOING_AWAY);\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 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 previousClient - The client which is to be waiting until re-connection happens.\n * @param seconds - Timeout period on re-connection in seconds.\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 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 Error(\"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 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 this._reconnectingSessionId.delete(sessionId);\n };\n\n reconnection.\n then((newClient) => {\n newClient.auth = previousClient.auth;\n newClient.userData = previousClient.userData;\n newClient.view = previousClient.view;\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 cleanup();\n }).\n catch(() => {\n cleanup();\n this.resetAutoDisposeTimeout();\n });\n\n return reconnection;\n }\n\n protected 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 protected sendFullState(client: Client): void {\n client.raw(this._serializer.getFullState(client));\n }\n\n protected _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);\n\n } else {\n (target as Client).raw.apply(target, args);\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 protected async _reserveSeat(\n sessionId: string,\n joinOptions: any = true,\n authData: any = undefined,\n seconds: number = this.seatReservationTime,\n allowReconnection: boolean = false,\n devModeReconnection?: boolean,\n ) {\n if (!allowReconnection && this.hasReachedMaxClients()) {\n return false;\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 //\n // isDevMode workaround to allow players to reconnect on devMode\n //\n if (devModeReconnection) {\n this._reconnectingSessionId.set(sessionId, sessionId);\n }\n\n return true;\n }\n\n protected _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 protected async _dispose(): Promise<any> {\n this._internalState = RoomInternalState.DISPOSING;\n\n this.listing.remove();\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 protected _onMessage(client: Client & ClientPrivate, buffer: Buffer) {\n // skip if client is on LEAVING state.\n if (client.state === ClientState.LEAVING) { return; }\n\n const it: Iterator = { offset: 1 };\n const code = buffer[0];\n\n if (!buffer) {\n debugAndPrintError(`${this.roomName} (roomId: ${this.roomId}), couldn't decode message: ${buffer}`);\n return;\n }\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 const messageTypeHandler = this.onMessageHandlers[messageType];\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 (messageTypeHandler?.validate !== undefined) {\n message = messageTypeHandler.validate(message);\n }\n\n } catch (e) {\n debugAndPrintError(e);\n client.leave(Protocol.WS_CLOSE_WITH_ERROR);\n return;\n }\n\n if (messageTypeHandler) {\n messageTypeHandler.callback(client, message);\n\n } else {\n (this.onMessageHandlers['*'] || this.onMessageHandlers['__no_message_handler']).callback(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 const messageTypeHandler = this.onMessageHandlers[messageType];\n\n let message = buffer.subarray(it.offset, buffer.byteLength);\n debugMessage(\"received: '%s' -> %j (roomId: %s)\", messageType, message, this.roomId);\n\n // custom message validation\n if (messageTypeHandler?.validate !== undefined) {\n message = messageTypeHandler.validate(message);\n }\n\n if (messageTypeHandler) {\n messageTypeHandler.callback(client, message);\n\n } else {\n (this.onMessageHandlers['*'] || this.onMessageHandlers['__no_message_handler']).callback(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.LEAVE_ROOM) {\n this._forciblyCloseClient(client, Protocol.WS_CLOSE_CONSENTED);\n }\n\n }\n\n protected _forciblyCloseClient(client: Client & 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 protected async _onLeave(client: Client, code?: number): Promise<any> {\n debugMatchMaking('onLeave, sessionId: \\'%s\\' (close code: %d, roomId: %s)', client.sessionId, code, this.roomId);\n\n // call 'onLeave' method only if the client has been successfully accepted.\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 (this.onLeave) {\n try {\n this.#_onLeaveConcurrent++;\n await this.onLeave(client, (code === Protocol.WS_CLOSE_CONSENTED));\n\n } catch (e) {\n debugAndPrintError(`onLeave error: ${(e && e.message || e || 'promise rejected')} (roomId: ${this.roomId})`);\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);\n });\n\n // @ts-ignore (client.state may be modified at onLeave())\n } else if (client.state !== ClientState.RECONNECTED) {\n await this._onAfterLeave(client);\n }\n }\n\n protected async _onAfterLeave(client: Client) {\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 protected async _incrementClientCount() {\n // lock automatically when maxClients is reached\n if (!this.#_locked && this.hasReachedMaxClients()) {\n this.#_maxClientsReached = true;\n this.lock.call(this, true);\n }\n\n await this.listing.updateOne({\n $inc: { clients: 1 },\n $set: { locked: this.#_locked },\n });\n }\n\n protected 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 this.unlock.call(this, true);\n }\n\n // update room listing cache\n await this.listing.updateOne({\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.onDispose !== undefined) {\n this.onDispose = wrapTryCatch(this.onDispose.bind(this), onUncaughtException, OnDisposeException, 'onDispose');\n }\n }\n\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["RoomInternalState"]
7
7
  }
@@ -184,6 +184,6 @@ export interface Presence {
184
184
  /**
185
185
  * Removes and returns the last element of the list stored at key. If the list is empty, the execution is halted until an element is available or the timeout is reached.
186
186
  */
187
- brpop(...args: [...keys: string[], timeoutInSeconds: number]): Promise<[string, string]>;
187
+ brpop(...args: [...keys: string[], timeoutInSeconds: number]): Promise<[string, string] | null>;
188
188
  shutdown(): void;
189
189
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/presence/Presence.ts"],
4
- "sourcesContent": ["/**\n * When you need to scale your server on multiple processes and/or machines, you'd need to provide\n * the Presence option to the Server. The purpose of Presence is to allow communicating and\n * sharing data between different processes, specially during match-making.\n *\n * - Local presence - This is the default option. It's meant to be used when you're running Colyseus in\n * a single process.\n * - Redis presence - Use this option when you're running Colyseus on multiple processes and/or machines.\n *\n * @default Local presence\n */\nexport interface Presence {\n /**\n * Subscribes to the given topic. The callback will be triggered whenever a message is published on topic.\n *\n * @param topic - Topic name.\n * @param callback - Callback to trigger on subscribing.\n */\n subscribe(topic: string, callback: Function);\n\n /**\n * Unsubscribe from given topic.\n *\n * @param topic - Topic name.\n * @param callback - Callback to trigger on topic unsubscribing.\n */\n unsubscribe(topic: string, callback?: Function);\n\n /**\n * Posts a message to given topic.\n *\n * @param topic - Topic name.\n * @param data - Message body/object.\n */\n publish(topic: string, data: any);\n\n /**\n * Returns if key exists.\n *\n * @param key\n */\n exists(key: string): Promise<boolean>;\n\n /**\n * Set key to hold the string value.\n *\n * @param key - Identifier.\n * @param value - Message body/object.\n */\n set(key: string, value: string);\n\n /**\n * Set key to hold the string value and set key to timeout after a given number of seconds.\n *\n * @param key - Identifier.\n * @param value - Message body/object.\n * @param seconds - Timeout value.\n */\n setex(key: string, value: string, seconds: number);\n\n /**\n * Expire the key in seconds.\n *\n * @param key - Identifier.\n * @param seconds - Seconds to expire the key.\n */\n expire(key: string, seconds: number);\n\n /**\n * Get the value of key.\n *\n * @param key - Identifier.\n */\n get(key: string);\n\n /**\n * Removes the specified key.\n *\n * @param key - Identifier of the object to removed.\n */\n del(key: string): void;\n\n /**\n * Add the specified members to the set stored at key. Specified members that are already\n * a member of this set are ignored. If key does not exist, a new set is created before\n * adding the specified members.\n *\n * @param key - Name/Identifier of the set.\n * @param value - Message body/object.\n */\n sadd(key: string, value: any);\n\n /**\n * Returns all the members of the set value stored at key.\n *\n * @param key - Name/Identifier of the set.\n */\n smembers(key: string): Promise<string[]>;\n\n /**\n * Returns if member is a member of the set stored at key.\n *\n * @param key - Name/Identifier of the set.\n * @param field - Key value within the set.\n * @returns `1` if the element is a member of the set else `0`.\n */\n sismember(key: string, field: string);\n\n /**\n * Remove the specified members from the set stored at key. Specified members that are not a\n * member of this set are ignored. If key does not exist, it is treated as an empty set\n * and this command returns 0.\n *\n * @param key - Name/Identifier of the set.\n * @param value - Key value within the set.\n */\n srem(key: string, value: any);\n\n /**\n * Returns the set cardinality (number of elements) of the set stored at key.\n *\n * @param key - Name/Identifier of the set.\n */\n scard(key: string);\n\n /**\n * Returns the members of the set resulting from the intersection of all the given sets.\n *\n * @param keys - Key values within the set.\n */\n sinter(...keys: string[]): Promise<string[]>;\n\n /**\n * Sets field in the hash stored at key to value. If key does not exist, a new key holding a hash is created.\n * If field already exists in the hash, it is overwritten.\n */\n hset(key: string, field: string, value: string);\n\n /**\n * Increments the number stored at field in the hash stored at key by increment. If key does not exist, a new key\n * holding a hash is created. If field does not exist the value is set to 0 before the operation is performed.\n */\n hincrby(key: string, field: string, value: number): number | Promise<number>;\n\n /**\n * WARNING: DO NOT USE THIS METHOD. It is meant for internal use only.\n * @private\n */\n hincrbyex(key: string, field: string, value: number, expireInSeconds: number): number | Promise<number>;\n\n /**\n * Returns the value associated with field in the hash stored at key.\n */\n hget(key: string, field: string): Promise<string>;\n\n /**\n * Returns all fields and values of the hash stored at key.\n */\n hgetall(key: string): Promise<{ [key: string]: string }>;\n\n /**\n * Removes the specified fields from the hash stored at key. Specified fields that do not exist within\n * this hash are ignored. If key does not exist, it is treated as an empty hash and this command returns 0.\n */\n hdel(key: string, field: string): boolean | Promise<boolean>;\n\n /**\n * Returns the number of fields contained in the hash stored at key\n */\n hlen(key: string): Promise<number>;\n\n /**\n * Increments the number stored at key by one. If the key does not exist, it is set to 0 before performing\n * the operation. An error is returned if the key contains a value of the wrong type or\n * contains a string that can not be represented as integer. This operation is limited to 64-bit signed integers.\n */\n incr(key: string): Promise<number>;\n\n /**\n * Decrements the number stored at key by one. If the key does not exist, it is set to 0 before performing\n * the operation. An error is returned if the key contains a value of the wrong type or contains a string\n * that can not be represented as integer. This operation is limited to 64-bit signed integers.\n */\n decr(key: string): Promise<number>;\n\n /**\n * Returns the length of the list stored at key.\n */\n llen(key: string): number | Promise<number>;\n\n /**\n * Adds the string value to the end of the list stored at key. If key does not exist, it is created as empty list before performing the push operation.\n */\n rpush(key: string, ...values: string[]): number | Promise<number>;\n\n /**\n * Adds the string value to the begginning of the list stored at key. If key does not exist, it is created as empty list before performing the push operation.\n */\n lpush(key: string, ...values: string[]): number | Promise<number>;\n\n /**\n * Removes and returns the last element of the list stored at key.\n */\n rpop(key: string): string | Promise<string>;\n\n /**\n * Removes and returns the first element of the list stored at key.\n */\n lpop(key: string): string | Promise<string>;\n\n /**\n * Removes and returns the last element of the list stored at key. If the list is empty, the execution is halted until an element is available or the timeout is reached.\n */\n brpop(...args: [...keys: string[], timeoutInSeconds: number]): Promise<[string, string]>;\n\n shutdown(): void;\n}\n"],
4
+ "sourcesContent": ["/**\n * When you need to scale your server on multiple processes and/or machines, you'd need to provide\n * the Presence option to the Server. The purpose of Presence is to allow communicating and\n * sharing data between different processes, specially during match-making.\n *\n * - Local presence - This is the default option. It's meant to be used when you're running Colyseus in\n * a single process.\n * - Redis presence - Use this option when you're running Colyseus on multiple processes and/or machines.\n *\n * @default Local presence\n */\nexport interface Presence {\n /**\n * Subscribes to the given topic. The callback will be triggered whenever a message is published on topic.\n *\n * @param topic - Topic name.\n * @param callback - Callback to trigger on subscribing.\n */\n subscribe(topic: string, callback: Function);\n\n /**\n * Unsubscribe from given topic.\n *\n * @param topic - Topic name.\n * @param callback - Callback to trigger on topic unsubscribing.\n */\n unsubscribe(topic: string, callback?: Function);\n\n /**\n * Posts a message to given topic.\n *\n * @param topic - Topic name.\n * @param data - Message body/object.\n */\n publish(topic: string, data: any);\n\n /**\n * Returns if key exists.\n *\n * @param key\n */\n exists(key: string): Promise<boolean>;\n\n /**\n * Set key to hold the string value.\n *\n * @param key - Identifier.\n * @param value - Message body/object.\n */\n set(key: string, value: string);\n\n /**\n * Set key to hold the string value and set key to timeout after a given number of seconds.\n *\n * @param key - Identifier.\n * @param value - Message body/object.\n * @param seconds - Timeout value.\n */\n setex(key: string, value: string, seconds: number);\n\n /**\n * Expire the key in seconds.\n *\n * @param key - Identifier.\n * @param seconds - Seconds to expire the key.\n */\n expire(key: string, seconds: number);\n\n /**\n * Get the value of key.\n *\n * @param key - Identifier.\n */\n get(key: string);\n\n /**\n * Removes the specified key.\n *\n * @param key - Identifier of the object to removed.\n */\n del(key: string): void;\n\n /**\n * Add the specified members to the set stored at key. Specified members that are already\n * a member of this set are ignored. If key does not exist, a new set is created before\n * adding the specified members.\n *\n * @param key - Name/Identifier of the set.\n * @param value - Message body/object.\n */\n sadd(key: string, value: any);\n\n /**\n * Returns all the members of the set value stored at key.\n *\n * @param key - Name/Identifier of the set.\n */\n smembers(key: string): Promise<string[]>;\n\n /**\n * Returns if member is a member of the set stored at key.\n *\n * @param key - Name/Identifier of the set.\n * @param field - Key value within the set.\n * @returns `1` if the element is a member of the set else `0`.\n */\n sismember(key: string, field: string);\n\n /**\n * Remove the specified members from the set stored at key. Specified members that are not a\n * member of this set are ignored. If key does not exist, it is treated as an empty set\n * and this command returns 0.\n *\n * @param key - Name/Identifier of the set.\n * @param value - Key value within the set.\n */\n srem(key: string, value: any);\n\n /**\n * Returns the set cardinality (number of elements) of the set stored at key.\n *\n * @param key - Name/Identifier of the set.\n */\n scard(key: string);\n\n /**\n * Returns the members of the set resulting from the intersection of all the given sets.\n *\n * @param keys - Key values within the set.\n */\n sinter(...keys: string[]): Promise<string[]>;\n\n /**\n * Sets field in the hash stored at key to value. If key does not exist, a new key holding a hash is created.\n * If field already exists in the hash, it is overwritten.\n */\n hset(key: string, field: string, value: string);\n\n /**\n * Increments the number stored at field in the hash stored at key by increment. If key does not exist, a new key\n * holding a hash is created. If field does not exist the value is set to 0 before the operation is performed.\n */\n hincrby(key: string, field: string, value: number): number | Promise<number>;\n\n /**\n * WARNING: DO NOT USE THIS METHOD. It is meant for internal use only.\n * @private\n */\n hincrbyex(key: string, field: string, value: number, expireInSeconds: number): number | Promise<number>;\n\n /**\n * Returns the value associated with field in the hash stored at key.\n */\n hget(key: string, field: string): Promise<string>;\n\n /**\n * Returns all fields and values of the hash stored at key.\n */\n hgetall(key: string): Promise<{ [key: string]: string }>;\n\n /**\n * Removes the specified fields from the hash stored at key. Specified fields that do not exist within\n * this hash are ignored. If key does not exist, it is treated as an empty hash and this command returns 0.\n */\n hdel(key: string, field: string): boolean | Promise<boolean>;\n\n /**\n * Returns the number of fields contained in the hash stored at key\n */\n hlen(key: string): Promise<number>;\n\n /**\n * Increments the number stored at key by one. If the key does not exist, it is set to 0 before performing\n * the operation. An error is returned if the key contains a value of the wrong type or\n * contains a string that can not be represented as integer. This operation is limited to 64-bit signed integers.\n */\n incr(key: string): Promise<number>;\n\n /**\n * Decrements the number stored at key by one. If the key does not exist, it is set to 0 before performing\n * the operation. An error is returned if the key contains a value of the wrong type or contains a string\n * that can not be represented as integer. This operation is limited to 64-bit signed integers.\n */\n decr(key: string): Promise<number>;\n\n /**\n * Returns the length of the list stored at key.\n */\n llen(key: string): number | Promise<number>;\n\n /**\n * Adds the string value to the end of the list stored at key. If key does not exist, it is created as empty list before performing the push operation.\n */\n rpush(key: string, ...values: string[]): number | Promise<number>;\n\n /**\n * Adds the string value to the begginning of the list stored at key. If key does not exist, it is created as empty list before performing the push operation.\n */\n lpush(key: string, ...values: string[]): number | Promise<number>;\n\n /**\n * Removes and returns the last element of the list stored at key.\n */\n rpop(key: string): string | Promise<string>;\n\n /**\n * Removes and returns the first element of the list stored at key.\n */\n lpop(key: string): string | Promise<string>;\n\n /**\n * Removes and returns the last element of the list stored at key. If the list is empty, the execution is halted until an element is available or the timeout is reached.\n */\n brpop(...args: [...keys: string[], timeoutInSeconds: number]): Promise<[string, string] | null>;\n\n shutdown(): void;\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -11,7 +11,7 @@ export declare class SchemaSerializer<T extends Schema> implements Serializer<T>
11
11
  protected fullEncodeBuffer: Buffer;
12
12
  protected fullEncodeCache: Buffer;
13
13
  protected sharedOffsetCache: Iterator;
14
- protected views: Map<StateView | typeof SHARED_VIEW, Buffer>;
14
+ protected encodedViews: Map<StateView | typeof SHARED_VIEW, Buffer>;
15
15
  reset(newState: T & Schema): void;
16
16
  getFullState(client?: Client): Buffer<ArrayBufferLike>;
17
17
  applyPatches(clients: Client[]): boolean;
@@ -40,7 +40,7 @@ class SchemaSerializer {
40
40
  this.hasFilters = this.encoder.context.hasFilters;
41
41
  this.fullEncodeBuffer[0] = import_Protocol.Protocol.ROOM_STATE;
42
42
  if (this.hasFilters) {
43
- this.views = /* @__PURE__ */ new Map();
43
+ this.encodedViews = /* @__PURE__ */ new Map();
44
44
  }
45
45
  }
46
46
  getFullState(client) {
@@ -88,14 +88,14 @@ class SchemaSerializer {
88
88
  continue;
89
89
  }
90
90
  const view = client.view || SHARED_VIEW;
91
- let encodedView = this.views.get(view);
91
+ let encodedView = this.encodedViews.get(view);
92
92
  if (encodedView === void 0) {
93
93
  encodedView = view === SHARED_VIEW ? encodedChanges : this.encoder.encodeView(client.view, sharedOffset, it);
94
- this.views.set(view, encodedView);
94
+ this.encodedViews.set(view, encodedView);
95
95
  }
96
96
  client.raw(encodedView);
97
97
  }
98
- this.views.clear();
98
+ this.encodedViews.clear();
99
99
  }
100
100
  this.encoder.discardChanges();
101
101
  if (import_Debug.debugPatch.enabled) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/serializer/SchemaSerializer.ts"],
4
- "sourcesContent": ["import { Serializer } from './Serializer.js';\n\nimport { Encoder, dumpChanges, Reflection, Schema, Iterator, StateView } from '@colyseus/schema';\nimport { debugPatch } from '../Debug.js';\nimport { Protocol } from '../Protocol.js';\nimport { Client, ClientState } from '../Transport.js';\n\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializer<T extends Schema> implements Serializer<T> {\n public id = 'schema';\n\n protected encoder: Encoder<T>;\n protected hasFilters: boolean = false;\n\n protected handshakeCache: Buffer;\n\n // flag to avoid re-encoding full state if no changes were made\n protected needFullEncode: boolean = true;\n\n // TODO: make this optional. allocating a new buffer for each room may not be always necessary.\n protected fullEncodeBuffer: Buffer = Buffer.allocUnsafe(Encoder.BUFFER_SIZE);\n protected fullEncodeCache: Buffer;\n protected sharedOffsetCache: Iterator = { offset: 0 };\n\n protected views: Map<StateView | typeof SHARED_VIEW, Buffer>;\n\n public reset(newState: T & Schema) {\n this.encoder = new Encoder(newState);\n this.hasFilters = this.encoder.context.hasFilters;\n\n // cache ROOM_STATE byte as part of the encoded buffer\n this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;\n\n if (this.hasFilters) {\n this.views = new Map();\n }\n }\n\n public getFullState(client?: Client) {\n if (this.needFullEncode || this.encoder.root.changes.length > 0) {\n this.sharedOffsetCache = { offset: 1 };\n this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);\n this.needFullEncode = false;\n }\n\n if (this.hasFilters && client?.view) {\n return this.encoder.encodeAllView(\n client.view,\n this.sharedOffsetCache.offset,\n { ...this.sharedOffsetCache },\n this.fullEncodeBuffer\n );\n\n } else {\n return this.fullEncodeCache;\n }\n }\n\n public applyPatches(clients: Client[]) {\n let numClients = clients.length;\n\n if (numClients == 0 || !this.encoder.hasChanges) {\n // skip patching state if:\n // - no clients are connected\n // - no changes were made\n // - no \"filtered changes\" were made when using filters\n return false;\n }\n\n this.needFullEncode = true;\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.encoder.state);\n }\n\n // get patch bytes\n const it: Iterator = { offset: 1 };\n this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;\n\n // encode changes once, for all clients\n const encodedChanges = this.encoder.encode(it);\n\n if (!this.hasFilters) {\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n client.raw(encodedChanges);\n }\n\n } else {\n // cache shared offset\n const sharedOffset = it.offset;\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n const view = client.view || SHARED_VIEW;\n\n let encodedView = this.views.get(view);\n\n // allow to pass the same encoded view for multiple clients\n if (encodedView === undefined) {\n encodedView = (view === SHARED_VIEW)\n ? encodedChanges\n : this.encoder.encodeView(client.view, sharedOffset, it);\n this.views.set(view, encodedView);\n }\n\n client.raw(encodedView);\n }\n\n // clear views\n this.views.clear();\n }\n\n // discard changes after sending\n this.encoder.discardChanges();\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n encodedChanges.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n\n return true;\n }\n\n public handshake() {\n /**\n * Cache handshake to avoid encoding it for each client joining\n */\n if (!this.handshakeCache) {\n //\n // TODO: re-use handshake buffer for all rooms of same type (?)\n //\n this.handshakeCache = (this.encoder.state && Reflection.encode(this.encoder));\n }\n\n return this.handshakeCache;\n }\n\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oBAA8E;AAC9E,mBAA2B;AAC3B,sBAAyB;AACzB,uBAAoC;AAEpC,MAAM,cAAc,CAAC;AAEd,MAAM,iBAA4D;AAAA,EAAlE;AACL,SAAO,KAAK;AAGZ,SAAU,aAAsB;AAKhC;AAAA,SAAU,iBAA0B;AAGpC;AAAA,SAAU,mBAA2B,OAAO,YAAY,sBAAQ,WAAW;AAE3E,SAAU,oBAA8B,EAAE,QAAQ,EAAE;AAAA;AAAA,EAI7C,MAAM,UAAsB;AACjC,SAAK,UAAU,IAAI,sBAAQ,QAAQ;AACnC,SAAK,aAAa,KAAK,QAAQ,QAAQ;AAGvC,SAAK,iBAAiB,CAAC,IAAI,yBAAS;AAEpC,QAAI,KAAK,YAAY;AACnB,WAAK,QAAQ,oBAAI,IAAI;AAAA,IACvB;AAAA,EACF;AAAA,EAEO,aAAa,QAAiB;AACnC,QAAI,KAAK,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,SAAS,GAAG;AAC/D,WAAK,oBAAoB,EAAE,QAAQ,EAAE;AACrC,WAAK,kBAAkB,KAAK,QAAQ,UAAU,KAAK,mBAAmB,KAAK,gBAAgB;AAC3F,WAAK,iBAAiB;AAAA,IACxB;AAEA,QAAI,KAAK,cAAc,QAAQ,MAAM;AACnC,aAAO,KAAK,QAAQ;AAAA,QAClB,OAAO;AAAA,QACP,KAAK,kBAAkB;AAAA,QACvB,EAAE,GAAG,KAAK,kBAAkB;AAAA,QAC5B,KAAK;AAAA,MACP;AAAA,IAEF,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEO,aAAa,SAAmB;AACrC,QAAI,aAAa,QAAQ;AAEzB,QAAI,cAAc,KAAK,CAAC,KAAK,QAAQ,YAAY;AAK/C,aAAO;AAAA,IACT;AAEA,SAAK,iBAAiB;AAGtB,QAAI,wBAAW,SAAS;AACtB,MAAC,wBAAmB,kBAAc,2BAAY,KAAK,QAAQ,KAAK;AAAA,IAClE;AAGA,UAAM,KAAe,EAAE,QAAQ,EAAE;AACjC,SAAK,QAAQ,aAAa,CAAC,IAAI,yBAAS;AAGxC,UAAM,iBAAiB,KAAK,QAAQ,OAAO,EAAE;AAE7C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ,UAAU;AAKjC,YAAI,OAAO,UAAU,6BAAY,QAAQ;AACvC;AAAA,QACF;AAEA,eAAO,IAAI,cAAc;AAAA,MAC3B;AAAA,IAEF,OAAO;AAEL,YAAM,eAAe,GAAG;AAGxB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ,UAAU;AAKjC,YAAI,OAAO,UAAU,6BAAY,QAAQ;AACvC;AAAA,QACF;AAEA,cAAM,OAAO,OAAO,QAAQ;AAE5B,YAAI,cAAc,KAAK,MAAM,IAAI,IAAI;AAGrC,YAAI,gBAAgB,QAAW;AAC7B,wBAAe,SAAS,cACpB,iBACA,KAAK,QAAQ,WAAW,OAAO,MAAM,cAAc,EAAE;AACzD,eAAK,MAAM,IAAI,MAAM,WAAW;AAAA,QAClC;AAEA,eAAO,IAAI,WAAW;AAAA,MACxB;AAGA,WAAK,MAAM,MAAM;AAAA,IACnB;AAGA,SAAK,QAAQ,eAAe;AAG5B,QAAI,wBAAW,SAAS;AACtB;AAAA,QACE;AAAA,QACA,eAAe;AAAA,QACf,QAAQ;AAAA,QACP,wBAAmB;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,YAAY;AAIjB,QAAI,CAAC,KAAK,gBAAgB;AAIxB,WAAK,iBAAkB,KAAK,QAAQ,SAAS,yBAAW,OAAO,KAAK,OAAO;AAAA,IAC7E;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
4
+ "sourcesContent": ["import { Serializer } from './Serializer.js';\n\nimport { Encoder, dumpChanges, Reflection, Schema, Iterator, StateView } from '@colyseus/schema';\nimport { debugPatch } from '../Debug.js';\nimport { Protocol } from '../Protocol.js';\nimport { Client, ClientState } from '../Transport.js';\n\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializer<T extends Schema> implements Serializer<T> {\n public id = 'schema';\n\n protected encoder: Encoder<T>;\n protected hasFilters: boolean = false;\n\n protected handshakeCache: Buffer;\n\n // flag to avoid re-encoding full state if no changes were made\n protected needFullEncode: boolean = true;\n\n // TODO: make this optional. allocating a new buffer for each room may not be always necessary.\n protected fullEncodeBuffer: Buffer = Buffer.allocUnsafe(Encoder.BUFFER_SIZE);\n protected fullEncodeCache: Buffer;\n protected sharedOffsetCache: Iterator = { offset: 0 };\n\n protected encodedViews: Map<StateView | typeof SHARED_VIEW, Buffer>;\n\n public reset(newState: T & Schema) {\n this.encoder = new Encoder(newState);\n this.hasFilters = this.encoder.context.hasFilters;\n\n // cache ROOM_STATE byte as part of the encoded buffer\n this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;\n\n if (this.hasFilters) {\n this.encodedViews = new Map();\n }\n }\n\n public getFullState(client?: Client) {\n if (this.needFullEncode || this.encoder.root.changes.length > 0) {\n this.sharedOffsetCache = { offset: 1 };\n this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);\n this.needFullEncode = false;\n }\n\n if (this.hasFilters && client?.view) {\n return this.encoder.encodeAllView(\n client.view,\n this.sharedOffsetCache.offset,\n { ...this.sharedOffsetCache },\n this.fullEncodeBuffer\n );\n\n } else {\n return this.fullEncodeCache;\n }\n }\n\n public applyPatches(clients: Client[]) {\n let numClients = clients.length;\n\n if (numClients == 0 || !this.encoder.hasChanges) {\n // skip patching state if:\n // - no clients are connected\n // - no changes were made\n // - no \"filtered changes\" were made when using filters\n return false;\n }\n\n this.needFullEncode = true;\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.encoder.state);\n }\n\n // get patch bytes\n const it: Iterator = { offset: 1 };\n this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;\n\n // encode changes once, for all clients\n const encodedChanges = this.encoder.encode(it);\n\n if (!this.hasFilters) {\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n client.raw(encodedChanges);\n }\n\n } else {\n // cache shared offset\n const sharedOffset = it.offset;\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n const view = client.view || SHARED_VIEW;\n\n let encodedView = this.encodedViews.get(view);\n\n // allow to pass the same encoded view for multiple clients\n if (encodedView === undefined) {\n encodedView = (view === SHARED_VIEW)\n ? encodedChanges\n : this.encoder.encodeView(client.view, sharedOffset, it);\n this.encodedViews.set(view, encodedView);\n }\n\n client.raw(encodedView);\n }\n\n // clear views\n this.encodedViews.clear();\n }\n\n // discard changes after sending\n this.encoder.discardChanges();\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n encodedChanges.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n\n return true;\n }\n\n public handshake() {\n /**\n * Cache handshake to avoid encoding it for each client joining\n */\n if (!this.handshakeCache) {\n //\n // TODO: re-use handshake buffer for all rooms of same type (?)\n //\n this.handshakeCache = (this.encoder.state && Reflection.encode(this.encoder));\n }\n\n return this.handshakeCache;\n }\n\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oBAA8E;AAC9E,mBAA2B;AAC3B,sBAAyB;AACzB,uBAAoC;AAEpC,MAAM,cAAc,CAAC;AAEd,MAAM,iBAA4D;AAAA,EAAlE;AACL,SAAO,KAAK;AAGZ,SAAU,aAAsB;AAKhC;AAAA,SAAU,iBAA0B;AAGpC;AAAA,SAAU,mBAA2B,OAAO,YAAY,sBAAQ,WAAW;AAE3E,SAAU,oBAA8B,EAAE,QAAQ,EAAE;AAAA;AAAA,EAI7C,MAAM,UAAsB;AACjC,SAAK,UAAU,IAAI,sBAAQ,QAAQ;AACnC,SAAK,aAAa,KAAK,QAAQ,QAAQ;AAGvC,SAAK,iBAAiB,CAAC,IAAI,yBAAS;AAEpC,QAAI,KAAK,YAAY;AACnB,WAAK,eAAe,oBAAI,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA,EAEO,aAAa,QAAiB;AACnC,QAAI,KAAK,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,SAAS,GAAG;AAC/D,WAAK,oBAAoB,EAAE,QAAQ,EAAE;AACrC,WAAK,kBAAkB,KAAK,QAAQ,UAAU,KAAK,mBAAmB,KAAK,gBAAgB;AAC3F,WAAK,iBAAiB;AAAA,IACxB;AAEA,QAAI,KAAK,cAAc,QAAQ,MAAM;AACnC,aAAO,KAAK,QAAQ;AAAA,QAClB,OAAO;AAAA,QACP,KAAK,kBAAkB;AAAA,QACvB,EAAE,GAAG,KAAK,kBAAkB;AAAA,QAC5B,KAAK;AAAA,MACP;AAAA,IAEF,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEO,aAAa,SAAmB;AACrC,QAAI,aAAa,QAAQ;AAEzB,QAAI,cAAc,KAAK,CAAC,KAAK,QAAQ,YAAY;AAK/C,aAAO;AAAA,IACT;AAEA,SAAK,iBAAiB;AAGtB,QAAI,wBAAW,SAAS;AACtB,MAAC,wBAAmB,kBAAc,2BAAY,KAAK,QAAQ,KAAK;AAAA,IAClE;AAGA,UAAM,KAAe,EAAE,QAAQ,EAAE;AACjC,SAAK,QAAQ,aAAa,CAAC,IAAI,yBAAS;AAGxC,UAAM,iBAAiB,KAAK,QAAQ,OAAO,EAAE;AAE7C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ,UAAU;AAKjC,YAAI,OAAO,UAAU,6BAAY,QAAQ;AACvC;AAAA,QACF;AAEA,eAAO,IAAI,cAAc;AAAA,MAC3B;AAAA,IAEF,OAAO;AAEL,YAAM,eAAe,GAAG;AAGxB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ,UAAU;AAKjC,YAAI,OAAO,UAAU,6BAAY,QAAQ;AACvC;AAAA,QACF;AAEA,cAAM,OAAO,OAAO,QAAQ;AAE5B,YAAI,cAAc,KAAK,aAAa,IAAI,IAAI;AAG5C,YAAI,gBAAgB,QAAW;AAC7B,wBAAe,SAAS,cACpB,iBACA,KAAK,QAAQ,WAAW,OAAO,MAAM,cAAc,EAAE;AACzD,eAAK,aAAa,IAAI,MAAM,WAAW;AAAA,QACzC;AAEA,eAAO,IAAI,WAAW;AAAA,MACxB;AAGA,WAAK,aAAa,MAAM;AAAA,IAC1B;AAGA,SAAK,QAAQ,eAAe;AAG5B,QAAI,wBAAW,SAAS;AACtB;AAAA,QACE;AAAA,QACA,eAAe;AAAA,QACf,QAAQ;AAAA,QACP,wBAAmB;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,YAAY;AAIjB,QAAI,CAAC,KAAK,gBAAgB;AAIxB,WAAK,iBAAkB,KAAK,QAAQ,SAAS,yBAAW,OAAO,KAAK,OAAO;AAAA,IAC7E;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
6
6
  "names": []
7
7
  }
@@ -19,7 +19,7 @@ var SchemaSerializer = class {
19
19
  this.hasFilters = this.encoder.context.hasFilters;
20
20
  this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;
21
21
  if (this.hasFilters) {
22
- this.views = /* @__PURE__ */ new Map();
22
+ this.encodedViews = /* @__PURE__ */ new Map();
23
23
  }
24
24
  }
25
25
  getFullState(client) {
@@ -67,14 +67,14 @@ var SchemaSerializer = class {
67
67
  continue;
68
68
  }
69
69
  const view = client.view || SHARED_VIEW;
70
- let encodedView = this.views.get(view);
70
+ let encodedView = this.encodedViews.get(view);
71
71
  if (encodedView === void 0) {
72
72
  encodedView = view === SHARED_VIEW ? encodedChanges : this.encoder.encodeView(client.view, sharedOffset, it);
73
- this.views.set(view, encodedView);
73
+ this.encodedViews.set(view, encodedView);
74
74
  }
75
75
  client.raw(encodedView);
76
76
  }
77
- this.views.clear();
77
+ this.encodedViews.clear();
78
78
  }
79
79
  this.encoder.discardChanges();
80
80
  if (debugPatch.enabled) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/serializer/SchemaSerializer.ts"],
4
- "sourcesContent": ["import { Serializer } from './Serializer.js';\n\nimport { Encoder, dumpChanges, Reflection, Schema, Iterator, StateView } from '@colyseus/schema';\nimport { debugPatch } from '../Debug.js';\nimport { Protocol } from '../Protocol.js';\nimport { Client, ClientState } from '../Transport.js';\n\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializer<T extends Schema> implements Serializer<T> {\n public id = 'schema';\n\n protected encoder: Encoder<T>;\n protected hasFilters: boolean = false;\n\n protected handshakeCache: Buffer;\n\n // flag to avoid re-encoding full state if no changes were made\n protected needFullEncode: boolean = true;\n\n // TODO: make this optional. allocating a new buffer for each room may not be always necessary.\n protected fullEncodeBuffer: Buffer = Buffer.allocUnsafe(Encoder.BUFFER_SIZE);\n protected fullEncodeCache: Buffer;\n protected sharedOffsetCache: Iterator = { offset: 0 };\n\n protected views: Map<StateView | typeof SHARED_VIEW, Buffer>;\n\n public reset(newState: T & Schema) {\n this.encoder = new Encoder(newState);\n this.hasFilters = this.encoder.context.hasFilters;\n\n // cache ROOM_STATE byte as part of the encoded buffer\n this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;\n\n if (this.hasFilters) {\n this.views = new Map();\n }\n }\n\n public getFullState(client?: Client) {\n if (this.needFullEncode || this.encoder.root.changes.length > 0) {\n this.sharedOffsetCache = { offset: 1 };\n this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);\n this.needFullEncode = false;\n }\n\n if (this.hasFilters && client?.view) {\n return this.encoder.encodeAllView(\n client.view,\n this.sharedOffsetCache.offset,\n { ...this.sharedOffsetCache },\n this.fullEncodeBuffer\n );\n\n } else {\n return this.fullEncodeCache;\n }\n }\n\n public applyPatches(clients: Client[]) {\n let numClients = clients.length;\n\n if (numClients == 0 || !this.encoder.hasChanges) {\n // skip patching state if:\n // - no clients are connected\n // - no changes were made\n // - no \"filtered changes\" were made when using filters\n return false;\n }\n\n this.needFullEncode = true;\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.encoder.state);\n }\n\n // get patch bytes\n const it: Iterator = { offset: 1 };\n this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;\n\n // encode changes once, for all clients\n const encodedChanges = this.encoder.encode(it);\n\n if (!this.hasFilters) {\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n client.raw(encodedChanges);\n }\n\n } else {\n // cache shared offset\n const sharedOffset = it.offset;\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n const view = client.view || SHARED_VIEW;\n\n let encodedView = this.views.get(view);\n\n // allow to pass the same encoded view for multiple clients\n if (encodedView === undefined) {\n encodedView = (view === SHARED_VIEW)\n ? encodedChanges\n : this.encoder.encodeView(client.view, sharedOffset, it);\n this.views.set(view, encodedView);\n }\n\n client.raw(encodedView);\n }\n\n // clear views\n this.views.clear();\n }\n\n // discard changes after sending\n this.encoder.discardChanges();\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n encodedChanges.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n\n return true;\n }\n\n public handshake() {\n /**\n * Cache handshake to avoid encoding it for each client joining\n */\n if (!this.handshakeCache) {\n //\n // TODO: re-use handshake buffer for all rooms of same type (?)\n //\n this.handshakeCache = (this.encoder.state && Reflection.encode(this.encoder));\n }\n\n return this.handshakeCache;\n }\n\n}\n"],
5
- "mappings": ";AAEA,SAAS,SAAS,aAAa,kBAA+C;AAC9E,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAiB,mBAAmB;AAEpC,IAAM,cAAc,CAAC;AAEd,IAAM,mBAAN,MAAkE;AAAA,EAAlE;AACL,SAAO,KAAK;AAGZ,SAAU,aAAsB;AAKhC;AAAA,SAAU,iBAA0B;AAGpC;AAAA,SAAU,mBAA2B,OAAO,YAAY,QAAQ,WAAW;AAE3E,SAAU,oBAA8B,EAAE,QAAQ,EAAE;AAAA;AAAA,EAI7C,MAAM,UAAsB;AACjC,SAAK,UAAU,IAAI,QAAQ,QAAQ;AACnC,SAAK,aAAa,KAAK,QAAQ,QAAQ;AAGvC,SAAK,iBAAiB,CAAC,IAAI,SAAS;AAEpC,QAAI,KAAK,YAAY;AACnB,WAAK,QAAQ,oBAAI,IAAI;AAAA,IACvB;AAAA,EACF;AAAA,EAEO,aAAa,QAAiB;AACnC,QAAI,KAAK,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,SAAS,GAAG;AAC/D,WAAK,oBAAoB,EAAE,QAAQ,EAAE;AACrC,WAAK,kBAAkB,KAAK,QAAQ,UAAU,KAAK,mBAAmB,KAAK,gBAAgB;AAC3F,WAAK,iBAAiB;AAAA,IACxB;AAEA,QAAI,KAAK,cAAc,QAAQ,MAAM;AACnC,aAAO,KAAK,QAAQ;AAAA,QAClB,OAAO;AAAA,QACP,KAAK,kBAAkB;AAAA,QACvB,EAAE,GAAG,KAAK,kBAAkB;AAAA,QAC5B,KAAK;AAAA,MACP;AAAA,IAEF,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEO,aAAa,SAAmB;AACrC,QAAI,aAAa,QAAQ;AAEzB,QAAI,cAAc,KAAK,CAAC,KAAK,QAAQ,YAAY;AAK/C,aAAO;AAAA,IACT;AAEA,SAAK,iBAAiB;AAGtB,QAAI,WAAW,SAAS;AACtB,MAAC,WAAmB,cAAc,YAAY,KAAK,QAAQ,KAAK;AAAA,IAClE;AAGA,UAAM,KAAe,EAAE,QAAQ,EAAE;AACjC,SAAK,QAAQ,aAAa,CAAC,IAAI,SAAS;AAGxC,UAAM,iBAAiB,KAAK,QAAQ,OAAO,EAAE;AAE7C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ,UAAU;AAKjC,YAAI,OAAO,UAAU,YAAY,QAAQ;AACvC;AAAA,QACF;AAEA,eAAO,IAAI,cAAc;AAAA,MAC3B;AAAA,IAEF,OAAO;AAEL,YAAM,eAAe,GAAG;AAGxB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ,UAAU;AAKjC,YAAI,OAAO,UAAU,YAAY,QAAQ;AACvC;AAAA,QACF;AAEA,cAAM,OAAO,OAAO,QAAQ;AAE5B,YAAI,cAAc,KAAK,MAAM,IAAI,IAAI;AAGrC,YAAI,gBAAgB,QAAW;AAC7B,wBAAe,SAAS,cACpB,iBACA,KAAK,QAAQ,WAAW,OAAO,MAAM,cAAc,EAAE;AACzD,eAAK,MAAM,IAAI,MAAM,WAAW;AAAA,QAClC;AAEA,eAAO,IAAI,WAAW;AAAA,MACxB;AAGA,WAAK,MAAM,MAAM;AAAA,IACnB;AAGA,SAAK,QAAQ,eAAe;AAG5B,QAAI,WAAW,SAAS;AACtB;AAAA,QACE;AAAA,QACA,eAAe;AAAA,QACf,QAAQ;AAAA,QACP,WAAmB;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,YAAY;AAIjB,QAAI,CAAC,KAAK,gBAAgB;AAIxB,WAAK,iBAAkB,KAAK,QAAQ,SAAS,WAAW,OAAO,KAAK,OAAO;AAAA,IAC7E;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
4
+ "sourcesContent": ["import { Serializer } from './Serializer.js';\n\nimport { Encoder, dumpChanges, Reflection, Schema, Iterator, StateView } from '@colyseus/schema';\nimport { debugPatch } from '../Debug.js';\nimport { Protocol } from '../Protocol.js';\nimport { Client, ClientState } from '../Transport.js';\n\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializer<T extends Schema> implements Serializer<T> {\n public id = 'schema';\n\n protected encoder: Encoder<T>;\n protected hasFilters: boolean = false;\n\n protected handshakeCache: Buffer;\n\n // flag to avoid re-encoding full state if no changes were made\n protected needFullEncode: boolean = true;\n\n // TODO: make this optional. allocating a new buffer for each room may not be always necessary.\n protected fullEncodeBuffer: Buffer = Buffer.allocUnsafe(Encoder.BUFFER_SIZE);\n protected fullEncodeCache: Buffer;\n protected sharedOffsetCache: Iterator = { offset: 0 };\n\n protected encodedViews: Map<StateView | typeof SHARED_VIEW, Buffer>;\n\n public reset(newState: T & Schema) {\n this.encoder = new Encoder(newState);\n this.hasFilters = this.encoder.context.hasFilters;\n\n // cache ROOM_STATE byte as part of the encoded buffer\n this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;\n\n if (this.hasFilters) {\n this.encodedViews = new Map();\n }\n }\n\n public getFullState(client?: Client) {\n if (this.needFullEncode || this.encoder.root.changes.length > 0) {\n this.sharedOffsetCache = { offset: 1 };\n this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);\n this.needFullEncode = false;\n }\n\n if (this.hasFilters && client?.view) {\n return this.encoder.encodeAllView(\n client.view,\n this.sharedOffsetCache.offset,\n { ...this.sharedOffsetCache },\n this.fullEncodeBuffer\n );\n\n } else {\n return this.fullEncodeCache;\n }\n }\n\n public applyPatches(clients: Client[]) {\n let numClients = clients.length;\n\n if (numClients == 0 || !this.encoder.hasChanges) {\n // skip patching state if:\n // - no clients are connected\n // - no changes were made\n // - no \"filtered changes\" were made when using filters\n return false;\n }\n\n this.needFullEncode = true;\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.encoder.state);\n }\n\n // get patch bytes\n const it: Iterator = { offset: 1 };\n this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;\n\n // encode changes once, for all clients\n const encodedChanges = this.encoder.encode(it);\n\n if (!this.hasFilters) {\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n client.raw(encodedChanges);\n }\n\n } else {\n // cache shared offset\n const sharedOffset = it.offset;\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n const view = client.view || SHARED_VIEW;\n\n let encodedView = this.encodedViews.get(view);\n\n // allow to pass the same encoded view for multiple clients\n if (encodedView === undefined) {\n encodedView = (view === SHARED_VIEW)\n ? encodedChanges\n : this.encoder.encodeView(client.view, sharedOffset, it);\n this.encodedViews.set(view, encodedView);\n }\n\n client.raw(encodedView);\n }\n\n // clear views\n this.encodedViews.clear();\n }\n\n // discard changes after sending\n this.encoder.discardChanges();\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n encodedChanges.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n\n return true;\n }\n\n public handshake() {\n /**\n * Cache handshake to avoid encoding it for each client joining\n */\n if (!this.handshakeCache) {\n //\n // TODO: re-use handshake buffer for all rooms of same type (?)\n //\n this.handshakeCache = (this.encoder.state && Reflection.encode(this.encoder));\n }\n\n return this.handshakeCache;\n }\n\n}\n"],
5
+ "mappings": ";AAEA,SAAS,SAAS,aAAa,kBAA+C;AAC9E,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAiB,mBAAmB;AAEpC,IAAM,cAAc,CAAC;AAEd,IAAM,mBAAN,MAAkE;AAAA,EAAlE;AACL,SAAO,KAAK;AAGZ,SAAU,aAAsB;AAKhC;AAAA,SAAU,iBAA0B;AAGpC;AAAA,SAAU,mBAA2B,OAAO,YAAY,QAAQ,WAAW;AAE3E,SAAU,oBAA8B,EAAE,QAAQ,EAAE;AAAA;AAAA,EAI7C,MAAM,UAAsB;AACjC,SAAK,UAAU,IAAI,QAAQ,QAAQ;AACnC,SAAK,aAAa,KAAK,QAAQ,QAAQ;AAGvC,SAAK,iBAAiB,CAAC,IAAI,SAAS;AAEpC,QAAI,KAAK,YAAY;AACnB,WAAK,eAAe,oBAAI,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA,EAEO,aAAa,QAAiB;AACnC,QAAI,KAAK,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,SAAS,GAAG;AAC/D,WAAK,oBAAoB,EAAE,QAAQ,EAAE;AACrC,WAAK,kBAAkB,KAAK,QAAQ,UAAU,KAAK,mBAAmB,KAAK,gBAAgB;AAC3F,WAAK,iBAAiB;AAAA,IACxB;AAEA,QAAI,KAAK,cAAc,QAAQ,MAAM;AACnC,aAAO,KAAK,QAAQ;AAAA,QAClB,OAAO;AAAA,QACP,KAAK,kBAAkB;AAAA,QACvB,EAAE,GAAG,KAAK,kBAAkB;AAAA,QAC5B,KAAK;AAAA,MACP;AAAA,IAEF,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEO,aAAa,SAAmB;AACrC,QAAI,aAAa,QAAQ;AAEzB,QAAI,cAAc,KAAK,CAAC,KAAK,QAAQ,YAAY;AAK/C,aAAO;AAAA,IACT;AAEA,SAAK,iBAAiB;AAGtB,QAAI,WAAW,SAAS;AACtB,MAAC,WAAmB,cAAc,YAAY,KAAK,QAAQ,KAAK;AAAA,IAClE;AAGA,UAAM,KAAe,EAAE,QAAQ,EAAE;AACjC,SAAK,QAAQ,aAAa,CAAC,IAAI,SAAS;AAGxC,UAAM,iBAAiB,KAAK,QAAQ,OAAO,EAAE;AAE7C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ,UAAU;AAKjC,YAAI,OAAO,UAAU,YAAY,QAAQ;AACvC;AAAA,QACF;AAEA,eAAO,IAAI,cAAc;AAAA,MAC3B;AAAA,IAEF,OAAO;AAEL,YAAM,eAAe,GAAG;AAGxB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ,UAAU;AAKjC,YAAI,OAAO,UAAU,YAAY,QAAQ;AACvC;AAAA,QACF;AAEA,cAAM,OAAO,OAAO,QAAQ;AAE5B,YAAI,cAAc,KAAK,aAAa,IAAI,IAAI;AAG5C,YAAI,gBAAgB,QAAW;AAC7B,wBAAe,SAAS,cACpB,iBACA,KAAK,QAAQ,WAAW,OAAO,MAAM,cAAc,EAAE;AACzD,eAAK,aAAa,IAAI,MAAM,WAAW;AAAA,QACzC;AAEA,eAAO,IAAI,WAAW;AAAA,MACxB;AAGA,WAAK,aAAa,MAAM;AAAA,IAC1B;AAGA,SAAK,QAAQ,eAAe;AAG5B,QAAI,WAAW,SAAS;AACtB;AAAA,QACE;AAAA,QACA,eAAe;AAAA,QACf,QAAQ;AAAA,QACP,WAAmB;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,YAAY;AAIjB,QAAI,CAAC,KAAK,gBAAgB;AAIxB,WAAK,iBAAkB,KAAK,QAAQ,SAAS,WAAW,OAAO,KAAK,OAAO;AAAA,IAC7E;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colyseus/core",
3
- "version": "0.16.12",
3
+ "version": "0.16.14",
4
4
  "description": "Multiplayer Framework for Node.js.",
5
5
  "input": "./src/index.ts",
6
6
  "main": "./build/index.js",