{
  "version": 3,
  "sources": ["../src/Room.ext.ts"],
  "sourcesContent": ["/**\n * Room.ts augmentations\n * Monkey-patches some Room methods to improve the testing experience.\n */\n\nimport { Deferred, Room, type Client } from \"@colyseus/core\";\nimport { Room as ClientRoom } from \"@colyseus/sdk\";\n\n// import timers from \"timers/promises\";\n\n// ----------------------------------------------------------------------------------------\n// SERVER-SIDE EXTENSIONS\n// ----------------------------------------------------------------------------------------\n\ndeclare module \"@colyseus/core\" {\n  interface Room {\n    waitForMessage(messageType: string): Promise<[Client, any]>;\n    waitForNextMessage(additionalDelay?: number): Promise<void>;\n    waitForNextPatch(additionalDelay?: number): Promise<void>;\n    waitForNextTimestep(): Promise<void>;\n    /** @deprecated Renamed to {@link Room.waitForNextTimestep}. Forwards unchanged. */\n    waitForNextSimulationTick(): Promise<void>;\n    _waitingForMessage: [number, Deferred];\n    _waitingForPatch: [number, Deferred];\n    _waitingForTimestep: Array<() => void>;\n  }\n}\n\n/*\n * Wait until receive message\n */\nconst _originalOnMessage = Room.prototype['_onMessage'];\nRoom.prototype['_onMessage'] = function(this: Room) {\n  _originalOnMessage.apply(this, arguments as any);\n  if (this._waitingForMessage) {\n    setTimeout(() => this._waitingForMessage[1].resolve(), this._waitingForMessage[0]);\n  }\n};\nRoom.prototype.waitForNextMessage = async function(this: Room, additionalDelay: number = 0) {\n  this._waitingForMessage = [additionalDelay, new Deferred()];\n  return this._waitingForMessage[1];\n}\n\nRoom.prototype.waitForMessage = async function(this: Room, type: string, rejectTimeout: number = 3000) {\n  const originalHandlers = this['onMessageEvents'].events[type] || [];\n  const room = this;\n\n  return new Promise<[Client, any]>((resolve, reject) => {\n    const rejectionTimeout = setTimeout(() => reject(new Error(`message '${type}' was not called. timed out (${rejectTimeout}ms)`)), rejectTimeout);\n\n    // Replace handlers with our interceptor\n    room['onMessageEvents'].events[type] = [\n      async function (client: Client, message: any) {\n        // clear rejection timeout\n        clearTimeout(rejectionTimeout);\n\n        // call original handlers\n        for (const handler of originalHandlers) {\n          await handler.call(room, client, message);\n        }\n\n        // revert to original handlers\n        room['onMessageEvents'].events[type] = originalHandlers;\n\n        // resolves waitForMessage promise.\n        resolve([client, message]);\n      }\n    ];\n  });\n}\n\n/**\n * Wait for the next timestep.\n *\n * Works with either loop \u2014 `setTimestep()` and `setFixedTimestep()` both drive\n * the same underlying interval.\n */\nRoom.prototype.waitForNextTimestep = async function(this: Room) {\n  if (!this['_simulationInterval']) {\n    console.warn(\"\u26A0\uFE0F waitForNextTimestep() - the room must call .setTimestep() or .setFixedTimestep().\");\n    return;\n  }\n  return new Promise<void>((resolve) => (this._waitingForTimestep ??= []).push(resolve));\n}\n\n/**\n * Resolve everyone waiting on a step, once that step has actually run.\n *\n * `setFixedTimestep` drives an accumulator, so a single interval can run zero\n * steps or several - sleeping for one interval says nothing about how many\n * executed. Hooking the callback is the only signal that means \"a step ran\".\n */\nfunction releaseTimestepWaiters(room: Room) {\n  const waiting = room._waitingForTimestep;\n  if (waiting === undefined || waiting.length === 0) { return; }\n  room._waitingForTimestep = [];\n  for (const resolve of waiting) { resolve(); }\n}\n\nconst _originalSetTimestep = Room.prototype.setTimestep;\nRoom.prototype.setTimestep = function(this: Room, onTickCallback?: any, delay?: number) {\n  if (onTickCallback === undefined) { return _originalSetTimestep.call(this, onTickCallback, delay); }\n  return _originalSetTimestep.call(this, (deltaTime: number) => {\n    try { return onTickCallback(deltaTime); }\n    finally { releaseTimestepWaiters(this); } // a throwing step must not strand the waiter\n  }, delay);\n}\n\nconst _originalSetFixedTimestep = Room.prototype.setFixedTimestep;\nRoom.prototype.setFixedTimestep = function(this: Room, step: any, tickRate?: number, opts?: any) {\n  return _originalSetFixedTimestep.call(this, (ctx: any) => {\n    try { return step(ctx); }\n    finally { releaseTimestepWaiters(this); }\n  }, tickRate, opts);\n}\n\n/**\n * @deprecated Renamed to `waitForNextTimestep()`, pairing with the\n * `setSimulationInterval()` \u2192 `setTimestep()` rename in 0.18. Forwards\n * unchanged; will be removed in 0.19.\n */\nRoom.prototype.waitForNextSimulationTick = function(this: Room) {\n  return this.waitForNextTimestep();\n}\n\n/**\n * Wait for next patch\n */\nconst _originalBroadcastPatch = Room.prototype['broadcastPatch'];\nRoom.prototype['broadcastPatch'] = function(this: Room) {\n  const retVal = _originalBroadcastPatch.call(this);\n  if (this._waitingForPatch) {\n    setTimeout(() => this._waitingForPatch[1].resolve(), this._waitingForPatch[0]);\n  }\n  return retVal;\n};\nRoom.prototype.waitForNextPatch = async function (this: Room, additionalDelay: number = 0) {\n  this._waitingForPatch = [additionalDelay, new Deferred()];\n  return this._waitingForPatch[1];\n}\n\n// ----------------------------------------------------------------------------------------\n// CLIENT-SIDE EXTENSIONS\n// ----------------------------------------------------------------------------------------\n\ndeclare module \"@colyseus/sdk\" {\n  interface Room {\n    waitForMessage(messageType: string, rejectTimeout?: number): Promise<any>;\n    waitForNextMessage(additionalDelay?: number): Promise<[string, any]>;\n    waitForNextPatch(additionalDelay?: number): Promise<void>;\n    waitForInitialState(): Promise<void>;\n    _waitingForMessage: [number, Deferred];\n  }\n}\n\nClientRoom.prototype.waitForMessage = async function(this: Room, type: string, rejectTimeout: number = 3000) {\n  return new Promise((resolve, reject) => {\n    const received = (message) => {\n      unbind();\n      resolve(message);\n      clearTimeout(rejectionTimeout);\n    }\n    const unbind = this['onMessageHandlers'].on(type, (message) => received(message));\n\n    const rejectionTimeout = setTimeout(() => {\n      unbind();\n      reject(new Error(`message '${type}' was not called. timed out (${rejectTimeout}ms)`));\n    }, rejectTimeout);\n  });\n}\n\nconst _originalClientOnMessage = ClientRoom.prototype['dispatchMessage'];\nClientRoom.prototype['dispatchMessage'] = function(this: ClientRoom) {\n  _originalClientOnMessage.apply(this, arguments as any);\n  if (this._waitingForMessage) {\n    setTimeout(() => {\n      this._waitingForMessage[1].resolve([arguments[0], arguments[1]]);\n    }, this._waitingForMessage[0]);\n  }\n};\nClientRoom.prototype.waitForNextMessage = async function(this: Room, additionalDelay: number = 0) {\n  this._waitingForMessage = [additionalDelay, new Deferred()];\n  return this._waitingForMessage[1];\n}\n\n/**\n * Wait for the next state update to be applied on the client.\n *\n * @param additionalDelay - milliseconds to wait after the update is applied.\n */\nClientRoom.prototype.waitForNextPatch = async function(this: ClientRoom, additionalDelay: number = 0) {\n  // no patch() to hook: decoding goes through serializer.patch()\n  return new Promise<void>((resolve) =>\n    this.onStateChange.once(() => setTimeout(resolve, additionalDelay)));\n}\n\n/**\n * Wait for the room's initial state to be applied on the client.\n *\n * Joining settles on the JOIN_ROOM handshake, and the server only sends the\n * full state once it sees the client's ack - so `room.state` is a round-trip\n * behind when `join()` resolves. Rooms without state resolve right away.\n */\nClientRoom.prototype.waitForInitialState = async function(this: ClientRoom) {\n  // mirrors the server's own `if (this.state)` gate: no state, no ROOM_STATE\n  if (this.serializerId === \"none\") { return; }\n\n  return new Promise<void>((resolve) => {\n    this.onStateChange.once(() => resolve());\n    this.onLeave.once(() => resolve()); // rejected after the handshake: don't hang\n  });\n}"],
  "mappings": ";AAKA,SAAS,UAAU,YAAyB;AAC5C,SAAS,QAAQ,kBAAkB;AAyBnC,IAAM,qBAAqB,KAAK,UAAU,YAAY;AACtD,KAAK,UAAU,YAAY,IAAI,WAAqB;AAClD,qBAAmB,MAAM,MAAM,SAAgB;AAC/C,MAAI,KAAK,oBAAoB;AAC3B,eAAW,MAAM,KAAK,mBAAmB,CAAC,EAAE,QAAQ,GAAG,KAAK,mBAAmB,CAAC,CAAC;AAAA,EACnF;AACF;AACA,KAAK,UAAU,qBAAqB,eAA2B,kBAA0B,GAAG;AAC1F,OAAK,qBAAqB,CAAC,iBAAiB,IAAI,SAAS,CAAC;AAC1D,SAAO,KAAK,mBAAmB,CAAC;AAClC;AAEA,KAAK,UAAU,iBAAiB,eAA2B,MAAc,gBAAwB,KAAM;AACrG,QAAM,mBAAmB,KAAK,iBAAiB,EAAE,OAAO,IAAI,KAAK,CAAC;AAClE,QAAM,OAAO;AAEb,SAAO,IAAI,QAAuB,CAAC,SAAS,WAAW;AACrD,UAAM,mBAAmB,WAAW,MAAM,OAAO,IAAI,MAAM,YAAY,IAAI,gCAAgC,aAAa,KAAK,CAAC,GAAG,aAAa;AAG9I,SAAK,iBAAiB,EAAE,OAAO,IAAI,IAAI;AAAA,MACrC,eAAgB,QAAgB,SAAc;AAE5C,qBAAa,gBAAgB;AAG7B,mBAAW,WAAW,kBAAkB;AACtC,gBAAM,QAAQ,KAAK,MAAM,QAAQ,OAAO;AAAA,QAC1C;AAGA,aAAK,iBAAiB,EAAE,OAAO,IAAI,IAAI;AAGvC,gBAAQ,CAAC,QAAQ,OAAO,CAAC;AAAA,MAC3B;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAQA,KAAK,UAAU,sBAAsB,iBAA2B;AAC9D,MAAI,CAAC,KAAK,qBAAqB,GAAG;AAChC,YAAQ,KAAK,gGAAsF;AACnG;AAAA,EACF;AACA,SAAO,IAAI,QAAc,CAAC,aAAa,KAAK,wBAAwB,CAAC,GAAG,KAAK,OAAO,CAAC;AACvF;AASA,SAAS,uBAAuB,MAAY;AAC1C,QAAM,UAAU,KAAK;AACrB,MAAI,YAAY,UAAa,QAAQ,WAAW,GAAG;AAAE;AAAA,EAAQ;AAC7D,OAAK,sBAAsB,CAAC;AAC5B,aAAW,WAAW,SAAS;AAAE,YAAQ;AAAA,EAAG;AAC9C;AAEA,IAAM,uBAAuB,KAAK,UAAU;AAC5C,KAAK,UAAU,cAAc,SAAqB,gBAAsB,OAAgB;AACtF,MAAI,mBAAmB,QAAW;AAAE,WAAO,qBAAqB,KAAK,MAAM,gBAAgB,KAAK;AAAA,EAAG;AACnG,SAAO,qBAAqB,KAAK,MAAM,CAAC,cAAsB;AAC5D,QAAI;AAAE,aAAO,eAAe,SAAS;AAAA,IAAG,UACxC;AAAU,6BAAuB,IAAI;AAAA,IAAG;AAAA,EAC1C,GAAG,KAAK;AACV;AAEA,IAAM,4BAA4B,KAAK,UAAU;AACjD,KAAK,UAAU,mBAAmB,SAAqB,MAAW,UAAmB,MAAY;AAC/F,SAAO,0BAA0B,KAAK,MAAM,CAAC,QAAa;AACxD,QAAI;AAAE,aAAO,KAAK,GAAG;AAAA,IAAG,UACxB;AAAU,6BAAuB,IAAI;AAAA,IAAG;AAAA,EAC1C,GAAG,UAAU,IAAI;AACnB;AAOA,KAAK,UAAU,4BAA4B,WAAqB;AAC9D,SAAO,KAAK,oBAAoB;AAClC;AAKA,IAAM,0BAA0B,KAAK,UAAU,gBAAgB;AAC/D,KAAK,UAAU,gBAAgB,IAAI,WAAqB;AACtD,QAAM,SAAS,wBAAwB,KAAK,IAAI;AAChD,MAAI,KAAK,kBAAkB;AACzB,eAAW,MAAM,KAAK,iBAAiB,CAAC,EAAE,QAAQ,GAAG,KAAK,iBAAiB,CAAC,CAAC;AAAA,EAC/E;AACA,SAAO;AACT;AACA,KAAK,UAAU,mBAAmB,eAA4B,kBAA0B,GAAG;AACzF,OAAK,mBAAmB,CAAC,iBAAiB,IAAI,SAAS,CAAC;AACxD,SAAO,KAAK,iBAAiB,CAAC;AAChC;AAgBA,WAAW,UAAU,iBAAiB,eAA2B,MAAc,gBAAwB,KAAM;AAC3G,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,WAAW,CAAC,YAAY;AAC5B,aAAO;AACP,cAAQ,OAAO;AACf,mBAAa,gBAAgB;AAAA,IAC/B;AACA,UAAM,SAAS,KAAK,mBAAmB,EAAE,GAAG,MAAM,CAAC,YAAY,SAAS,OAAO,CAAC;AAEhF,UAAM,mBAAmB,WAAW,MAAM;AACxC,aAAO;AACP,aAAO,IAAI,MAAM,YAAY,IAAI,gCAAgC,aAAa,KAAK,CAAC;AAAA,IACtF,GAAG,aAAa;AAAA,EAClB,CAAC;AACH;AAEA,IAAM,2BAA2B,WAAW,UAAU,iBAAiB;AACvE,WAAW,UAAU,iBAAiB,IAAI,WAA2B;AACnE,2BAAyB,MAAM,MAAM,SAAgB;AACrD,MAAI,KAAK,oBAAoB;AAC3B,eAAW,MAAM;AACf,WAAK,mBAAmB,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;AAAA,IACjE,GAAG,KAAK,mBAAmB,CAAC,CAAC;AAAA,EAC/B;AACF;AACA,WAAW,UAAU,qBAAqB,eAA2B,kBAA0B,GAAG;AAChG,OAAK,qBAAqB,CAAC,iBAAiB,IAAI,SAAS,CAAC;AAC1D,SAAO,KAAK,mBAAmB,CAAC;AAClC;AAOA,WAAW,UAAU,mBAAmB,eAAiC,kBAA0B,GAAG;AAEpG,SAAO,IAAI,QAAc,CAAC,YACxB,KAAK,cAAc,KAAK,MAAM,WAAW,SAAS,eAAe,CAAC,CAAC;AACvE;AASA,WAAW,UAAU,sBAAsB,iBAAiC;AAE1E,MAAI,KAAK,iBAAiB,QAAQ;AAAE;AAAA,EAAQ;AAE5C,SAAO,IAAI,QAAc,CAAC,YAAY;AACpC,SAAK,cAAc,KAAK,MAAM,QAAQ,CAAC;AACvC,SAAK,QAAQ,KAAK,MAAM,QAAQ,CAAC;AAAA,EACnC,CAAC;AACH;",
  "names": []
}
