@colyseus/core 0.15.45 → 0.16.0-alpha.23

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.
Files changed (103) hide show
  1. package/README.md +5 -5
  2. package/build/IPC.js.map +1 -1
  3. package/build/IPC.mjs.map +1 -1
  4. package/build/MatchMaker.d.ts +22 -16
  5. package/build/MatchMaker.js +71 -81
  6. package/build/MatchMaker.js.map +2 -2
  7. package/build/MatchMaker.mjs +70 -78
  8. package/build/MatchMaker.mjs.map +2 -2
  9. package/build/Protocol.d.ts +3 -9
  10. package/build/Protocol.js +35 -95
  11. package/build/Protocol.js.map +2 -2
  12. package/build/Protocol.mjs +34 -92
  13. package/build/Protocol.mjs.map +2 -2
  14. package/build/Room.d.ts +22 -27
  15. package/build/Room.js +55 -67
  16. package/build/Room.js.map +3 -3
  17. package/build/Room.mjs +56 -68
  18. package/build/Room.mjs.map +2 -2
  19. package/build/Server.d.ts +0 -1
  20. package/build/Server.js +4 -4
  21. package/build/Server.js.map +2 -2
  22. package/build/Server.mjs +3 -3
  23. package/build/Server.mjs.map +2 -2
  24. package/build/Transport.d.ts +37 -17
  25. package/build/Transport.js.map +2 -2
  26. package/build/Transport.mjs.map +2 -2
  27. package/build/index.d.ts +3 -3
  28. package/build/index.js +3 -3
  29. package/build/index.js.map +2 -2
  30. package/build/index.mjs +3 -3
  31. package/build/index.mjs.map +2 -2
  32. package/build/matchmaker/Lobby.d.ts +2 -2
  33. package/build/matchmaker/Lobby.js.map +2 -2
  34. package/build/matchmaker/Lobby.mjs.map +2 -2
  35. package/build/matchmaker/RegisteredHandler.d.ts +4 -5
  36. package/build/matchmaker/RegisteredHandler.js +4 -3
  37. package/build/matchmaker/RegisteredHandler.js.map +2 -2
  38. package/build/matchmaker/RegisteredHandler.mjs +4 -3
  39. package/build/matchmaker/RegisteredHandler.mjs.map +2 -2
  40. package/build/matchmaker/controller.d.ts +1 -2
  41. package/build/matchmaker/driver/RoomData.d.ts +3 -3
  42. package/build/matchmaker/driver/RoomData.js +3 -3
  43. package/build/matchmaker/driver/RoomData.js.map +2 -2
  44. package/build/matchmaker/driver/RoomData.mjs +2 -2
  45. package/build/matchmaker/driver/RoomData.mjs.map +2 -2
  46. package/build/matchmaker/driver/api.d.ts +104 -0
  47. package/build/matchmaker/driver/api.js +29 -0
  48. package/build/matchmaker/driver/api.js.map +7 -0
  49. package/build/matchmaker/driver/api.mjs +6 -0
  50. package/build/matchmaker/driver/api.mjs.map +7 -0
  51. package/build/matchmaker/driver/index.d.ts +7 -7
  52. package/build/matchmaker/driver/index.js +1 -1
  53. package/build/matchmaker/driver/index.js.map +2 -2
  54. package/build/matchmaker/driver/index.mjs +2 -2
  55. package/build/matchmaker/driver/index.mjs.map +2 -2
  56. package/build/matchmaker/driver/interfaces.d.ts +7 -11
  57. package/build/matchmaker/driver/interfaces.js.map +1 -1
  58. package/build/matchmaker/driver/local/LocalDriver.d.ts +13 -0
  59. package/build/matchmaker/driver/local/LocalDriver.js +65 -0
  60. package/build/matchmaker/driver/local/LocalDriver.js.map +7 -0
  61. package/build/matchmaker/driver/local/LocalDriver.mjs +42 -0
  62. package/build/matchmaker/driver/local/LocalDriver.mjs.map +7 -0
  63. package/build/matchmaker/driver/local/Query.d.ts +9 -0
  64. package/build/matchmaker/driver/local/Query.js +78 -0
  65. package/build/matchmaker/driver/local/Query.js.map +7 -0
  66. package/build/matchmaker/driver/local/Query.mjs +55 -0
  67. package/build/matchmaker/driver/local/Query.mjs.map +7 -0
  68. package/build/matchmaker/driver/local/RoomData.d.ts +19 -0
  69. package/build/matchmaker/driver/local/RoomData.js +79 -0
  70. package/build/matchmaker/driver/local/RoomData.js.map +7 -0
  71. package/build/matchmaker/driver/local/RoomData.mjs +56 -0
  72. package/build/matchmaker/driver/local/RoomData.mjs.map +7 -0
  73. package/build/presence/LocalPresence.d.ts +6 -1
  74. package/build/presence/LocalPresence.js +61 -0
  75. package/build/presence/LocalPresence.js.map +3 -3
  76. package/build/presence/LocalPresence.mjs +61 -0
  77. package/build/presence/LocalPresence.mjs.map +3 -3
  78. package/build/presence/Presence.d.ts +6 -0
  79. package/build/presence/Presence.js.map +1 -1
  80. package/build/rooms/LobbyRoom.d.ts +4 -4
  81. package/build/rooms/LobbyRoom.js.map +2 -2
  82. package/build/rooms/LobbyRoom.mjs.map +2 -2
  83. package/build/rooms/RelayRoom.js +2 -3
  84. package/build/rooms/RelayRoom.js.map +2 -2
  85. package/build/rooms/RelayRoom.mjs +3 -4
  86. package/build/rooms/RelayRoom.mjs.map +2 -2
  87. package/build/serializer/SchemaSerializer.d.ts +14 -7
  88. package/build/serializer/SchemaSerializer.js +66 -38
  89. package/build/serializer/SchemaSerializer.js.map +2 -2
  90. package/build/serializer/SchemaSerializer.mjs +67 -39
  91. package/build/serializer/SchemaSerializer.mjs.map +2 -2
  92. package/build/serializer/Serializer.d.ts +2 -2
  93. package/build/serializer/Serializer.js.map +1 -1
  94. package/build/utils/DevMode.js +1 -1
  95. package/build/utils/DevMode.js.map +2 -2
  96. package/build/utils/DevMode.mjs +2 -2
  97. package/build/utils/DevMode.mjs.map +2 -2
  98. package/build/utils/Utils.d.ts +2 -9
  99. package/build/utils/Utils.js +7 -4
  100. package/build/utils/Utils.js.map +2 -2
  101. package/build/utils/Utils.mjs +5 -3
  102. package/build/utils/Utils.mjs.map +2 -2
  103. package/package.json +5 -6
@@ -1,13 +1,20 @@
1
- import { Client } from '..';
2
1
  import { Serializer } from './Serializer';
3
- import { Schema } from '@colyseus/schema';
2
+ import { Encoder, Schema, Iterator, StateView } from '@colyseus/schema';
3
+ import { Client } from '../Transport';
4
+ declare const SHARED_VIEW: {};
4
5
  export declare class SchemaSerializer<T> implements Serializer<T> {
5
6
  id: string;
6
- private state;
7
- private useFilters;
8
- private handshakeCache;
7
+ protected encoder: Encoder;
8
+ protected hasFilters: boolean;
9
+ protected handshakeCache: Buffer;
10
+ protected needFullEncode: boolean;
11
+ protected fullEncodeBuffer: Buffer;
12
+ protected fullEncodeCache: Buffer;
13
+ protected sharedOffsetCache: Iterator;
14
+ protected views: Map<StateView | typeof SHARED_VIEW, Buffer>;
9
15
  reset(newState: T & Schema): void;
10
- getFullState(client?: Client): number[];
16
+ getFullState(client?: Client): Buffer;
11
17
  applyPatches(clients: Client[]): boolean;
12
- handshake(): number[];
18
+ handshake(): Buffer;
13
19
  }
20
+ export {};
@@ -24,63 +24,91 @@ var import_schema = require("@colyseus/schema");
24
24
  var import_Debug = require("../Debug");
25
25
  var import_Protocol = require("../Protocol");
26
26
  var import_Transport = require("../Transport");
27
+ const SHARED_VIEW = {};
27
28
  class SchemaSerializer {
28
29
  constructor() {
29
30
  this.id = "schema";
30
- this.useFilters = false;
31
+ this.hasFilters = false;
32
+ this.needFullEncode = true;
33
+ this.fullEncodeBuffer = Buffer.allocUnsafe(import_schema.Encoder.BUFFER_SIZE);
34
+ this.sharedOffsetCache = { offset: 0 };
31
35
  }
32
36
  reset(newState) {
33
- this.state = newState;
34
- this.useFilters = (0, import_schema.hasFilter)(newState.constructor);
37
+ this.encoder = new import_schema.Encoder(newState);
38
+ this.hasFilters = this.encoder.context.hasFilters;
39
+ this.fullEncodeBuffer[0] = import_Protocol.Protocol.ROOM_STATE;
40
+ if (this.hasFilters) {
41
+ this.views = /* @__PURE__ */ new Map();
42
+ }
35
43
  }
36
44
  getFullState(client) {
37
- const fullEncodedState = this.state.encodeAll(this.useFilters);
38
- if (client && this.useFilters) {
39
- return this.state.applyFilters(client, true);
45
+ if (this.needFullEncode || this.encoder.root.changes.size > 0) {
46
+ this.sharedOffsetCache = { offset: 1 };
47
+ this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);
48
+ this.needFullEncode = false;
49
+ }
50
+ if (this.hasFilters && client?.view) {
51
+ return this.encoder.encodeAllView(
52
+ client.view,
53
+ this.sharedOffsetCache.offset,
54
+ { ...this.sharedOffsetCache },
55
+ this.fullEncodeBuffer
56
+ );
40
57
  } else {
41
- return fullEncodedState;
58
+ return this.fullEncodeCache;
42
59
  }
43
60
  }
44
61
  applyPatches(clients) {
45
- const hasChanges = this.state["$changes"].changes.size > 0;
46
- if (hasChanges) {
47
- let numClients = clients.length;
48
- if (import_Debug.debugPatch.enabled) {
49
- import_Debug.debugPatch.dumpChanges = (0, import_schema.dumpChanges)(this.state);
62
+ let numClients = clients.length;
63
+ this.needFullEncode = this.encoder.root.changes.size > 0;
64
+ if (numClients == 0 || !this.needFullEncode && (!this.hasFilters || this.encoder.root.filteredChanges.size === 0)) {
65
+ return false;
66
+ }
67
+ if (import_Debug.debugPatch.enabled) {
68
+ import_Debug.debugPatch.dumpChanges = (0, import_schema.dumpChanges)(this.encoder.state);
69
+ }
70
+ const it = { offset: 1 };
71
+ this.encoder.sharedBuffer[0] = import_Protocol.Protocol.ROOM_STATE_PATCH;
72
+ const encodedChanges = this.encoder.encode(it);
73
+ if (!this.hasFilters) {
74
+ while (numClients--) {
75
+ const client = clients[numClients];
76
+ if (client.state !== import_Transport.ClientState.JOINED) {
77
+ continue;
78
+ }
79
+ client.raw(encodedChanges);
50
80
  }
51
- const patches = this.state.encode(false, [], this.useFilters);
52
- if (!this.useFilters) {
53
- patches.unshift(import_Protocol.Protocol.ROOM_STATE_PATCH);
54
- while (numClients--) {
55
- const client = clients[numClients];
56
- if (client.state === import_Transport.ClientState.JOINED) {
57
- client.raw(patches);
58
- }
81
+ } else {
82
+ const sharedOffset = it.offset;
83
+ while (numClients--) {
84
+ const client = clients[numClients];
85
+ if (client.state !== import_Transport.ClientState.JOINED) {
86
+ continue;
59
87
  }
60
- } else {
61
- while (numClients--) {
62
- const client = clients[numClients];
63
- if (client.state === import_Transport.ClientState.JOINED) {
64
- const filteredPatches = this.state.applyFilters(client);
65
- client.raw([import_Protocol.Protocol.ROOM_STATE_PATCH, ...filteredPatches]);
66
- }
88
+ const view = client.view || SHARED_VIEW;
89
+ let encodedView = this.views.get(view);
90
+ if (encodedView === void 0) {
91
+ encodedView = view === SHARED_VIEW ? encodedChanges : this.encoder.encodeView(client.view, sharedOffset, it);
92
+ this.views.set(view, encodedView);
67
93
  }
68
- this.state.discardAllChanges();
69
- }
70
- if (import_Debug.debugPatch.enabled) {
71
- (0, import_Debug.debugPatch)(
72
- "%d bytes sent to %d clients, %j",
73
- patches.length,
74
- clients.length,
75
- import_Debug.debugPatch.dumpChanges
76
- );
94
+ client.raw(encodedView);
77
95
  }
96
+ this.views.clear();
97
+ }
98
+ this.encoder.discardChanges();
99
+ if (import_Debug.debugPatch.enabled) {
100
+ (0, import_Debug.debugPatch)(
101
+ "%d bytes sent to %d clients, %j",
102
+ encodedChanges.length,
103
+ clients.length,
104
+ import_Debug.debugPatch.dumpChanges
105
+ );
78
106
  }
79
- return hasChanges;
107
+ return true;
80
108
  }
81
109
  handshake() {
82
110
  if (!this.handshakeCache) {
83
- this.handshakeCache = this.state && import_schema.Reflection.encode(this.state);
111
+ this.handshakeCache = this.encoder.state && import_schema.Reflection.encode(this.encoder.state);
84
112
  }
85
113
  return this.handshakeCache;
86
114
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/serializer/SchemaSerializer.ts"],
4
- "sourcesContent": ["/* tslint:disable:no-string-literal */\n\nimport { Client } from '..';\nimport { Serializer } from './Serializer';\n\nimport { dumpChanges, hasFilter, Reflection, Schema } from '@colyseus/schema';\nimport { debugPatch } from '../Debug';\nimport { Protocol } from '../Protocol';\nimport { ClientState } from '../Transport';\n\nexport class SchemaSerializer<T> implements Serializer<T> {\n public id = 'schema';\n\n private state: T & Schema;\n private useFilters: boolean = false;\n\n private handshakeCache: number[];\n\n // private needFullEncode = true;\n // private fullEncodedState: number[];\n\n public reset(newState: T & Schema) {\n this.state = newState;\n this.useFilters = hasFilter(newState.constructor as typeof Schema);\n }\n\n public getFullState(client?: Client) {\n const fullEncodedState = this.state.encodeAll(this.useFilters);\n\n // const fullEncodedState = (this.needFullEncode)\n // ? this.state.encodeAll(this.useFilters)\n // : this.fullEncodedState;\n\n // this.fullEncodedState = fullEncodedState;\n // this.needFullEncode = false;\n\n if (client && this.useFilters) {\n return this.state.applyFilters(client, true);\n\n } else {\n return fullEncodedState;\n }\n }\n\n public applyPatches(clients: Client[]) {\n const hasChanges = this.state['$changes'].changes.size > 0;\n\n if (hasChanges) {\n // this.needFullEncode = true;\n\n let numClients = clients.length;\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.state);\n }\n\n // get patch bytes\n const patches = this.state.encode(false, [], this.useFilters);\n\n if (!this.useFilters) {\n // encode changes once, for all clients\n patches.unshift(Protocol.ROOM_STATE_PATCH);\n\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check.\n //\n if (client.state === ClientState.JOINED) {\n client.raw(patches);\n }\n }\n\n } else {\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check.\n //\n if (client.state === ClientState.JOINED) {\n const filteredPatches = this.state.applyFilters(client);\n client.raw([Protocol.ROOM_STATE_PATCH, ...filteredPatches]);\n }\n }\n\n this.state.discardAllChanges();\n }\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n patches.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n }\n\n return hasChanges;\n }\n\n public handshake() {\n /**\n * Cache handshake to avoid encoding it for each client joining\n */\n if (!this.handshakeCache) {\n this.handshakeCache = (this.state && Reflection.encode(this.state));\n }\n\n return this.handshakeCache;\n }\n\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,oBAA2D;AAC3D,mBAA2B;AAC3B,sBAAyB;AACzB,uBAA4B;AAErB,MAAM,iBAA6C;AAAA,EAAnD;AACL,SAAO,KAAK;AAGZ,SAAQ,aAAsB;AAAA;AAAA,EAOvB,MAAM,UAAsB;AACjC,SAAK,QAAQ;AACb,SAAK,iBAAa,yBAAU,SAAS,WAA4B;AAAA,EACnE;AAAA,EAEO,aAAa,QAAiB;AACnC,UAAM,mBAAmB,KAAK,MAAM,UAAU,KAAK,UAAU;AAS7D,QAAI,UAAU,KAAK,YAAY;AAC7B,aAAO,KAAK,MAAM,aAAa,QAAQ,IAAI;AAAA,IAE7C,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEO,aAAa,SAAmB;AACrC,UAAM,aAAa,KAAK,MAAM,YAAY,QAAQ,OAAO;AAEzD,QAAI,YAAY;AAGd,UAAI,aAAa,QAAQ;AAGzB,UAAI,wBAAW,SAAS;AACtB,QAAC,wBAAmB,kBAAc,2BAAY,KAAK,KAAK;AAAA,MAC1D;AAGA,YAAM,UAAU,KAAK,MAAM,OAAO,OAAO,CAAC,GAAG,KAAK,UAAU;AAE5D,UAAI,CAAC,KAAK,YAAY;AAEpB,gBAAQ,QAAQ,yBAAS,gBAAgB;AAEzC,eAAO,cAAc;AACnB,gBAAM,SAAS,QAAQ;AAKvB,cAAI,OAAO,UAAU,6BAAY,QAAQ;AACvC,mBAAO,IAAI,OAAO;AAAA,UACpB;AAAA,QACF;AAAA,MAEF,OAAO;AAGL,eAAO,cAAc;AACnB,gBAAM,SAAS,QAAQ;AAKvB,cAAI,OAAO,UAAU,6BAAY,QAAQ;AACvC,kBAAM,kBAAkB,KAAK,MAAM,aAAa,MAAM;AACtD,mBAAO,IAAI,CAAC,yBAAS,kBAAkB,GAAG,eAAe,CAAC;AAAA,UAC5D;AAAA,QACF;AAEA,aAAK,MAAM,kBAAkB;AAAA,MAC/B;AAGA,UAAI,wBAAW,SAAS;AACtB;AAAA,UACE;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,UACP,wBAAmB;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,YAAY;AAIjB,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,iBAAkB,KAAK,SAAS,yBAAW,OAAO,KAAK,KAAK;AAAA,IACnE;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
4
+ "sourcesContent": ["import { Serializer } from './Serializer';\n\nimport { Encoder, dumpChanges, Reflection, Schema, Iterator, StateView } from '@colyseus/schema';\nimport { debugPatch } from '../Debug';\nimport { Protocol } from '../Protocol';\nimport { Client, ClientState } from '../Transport';\n\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializer<T> implements Serializer<T> {\n public id = 'schema';\n\n protected encoder: Encoder;\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.size > 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 this.needFullEncode = (this.encoder.root.changes.size > 0);\n\n if (\n numClients == 0 ||\n (\n !this.needFullEncode &&\n (!this.hasFilters || this.encoder.root.filteredChanges.size === 0)\n )\n ) {\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\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 // TODO: re-use handshake buffer for all rooms\n this.handshakeCache = (this.encoder.state && Reflection.encode(this.encoder.state));\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,iBAA6C;AAAA,EAAnD;AACL,SAAO,KAAK;AAGZ,SAAU,aAAsB;AAKhC,SAAU,iBAA0B;AAGpC,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,KAAK,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,OAAO,GAAG;AAC7D,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;AACzB,SAAK,iBAAkB,KAAK,QAAQ,KAAK,QAAQ,OAAO;AAExD,QACE,cAAc,KAEZ,CAAC,KAAK,mBACL,CAAC,KAAK,cAAc,KAAK,QAAQ,KAAK,gBAAgB,SAAS,IAElE;AAKA,aAAO;AAAA,IACT;AAIA,QAAI,wBAAW,SAAS;AACtB,MAAC,wBAAmB,kBAAc,2BAAY,KAAK,QAAQ,KAAK;AAAA,IAClE;AAGA,UAAM,KAAe,EAAE,QAAQ,EAAE;AACjC,SAAK,QAAQ,aAAa,KAAK,yBAAS;AAGxC,UAAM,iBAAiB,KAAK,QAAQ,OAAO,EAAE;AAE7C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ;AAKvB,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;AAKvB,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;AAExB,WAAK,iBAAkB,KAAK,QAAQ,SAAS,yBAAW,OAAO,KAAK,QAAQ,KAAK;AAAA,IACnF;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
6
6
  "names": []
7
7
  }
@@ -1,64 +1,92 @@
1
- import { dumpChanges, hasFilter, Reflection } from "@colyseus/schema";
1
+ import { Encoder, dumpChanges, Reflection } from "@colyseus/schema";
2
2
  import { debugPatch } from "../Debug";
3
3
  import { Protocol } from "../Protocol";
4
4
  import { ClientState } from "../Transport";
5
+ const SHARED_VIEW = {};
5
6
  class SchemaSerializer {
6
7
  constructor() {
7
8
  this.id = "schema";
8
- this.useFilters = false;
9
+ this.hasFilters = false;
10
+ this.needFullEncode = true;
11
+ this.fullEncodeBuffer = Buffer.allocUnsafe(Encoder.BUFFER_SIZE);
12
+ this.sharedOffsetCache = { offset: 0 };
9
13
  }
10
14
  reset(newState) {
11
- this.state = newState;
12
- this.useFilters = hasFilter(newState.constructor);
15
+ this.encoder = new Encoder(newState);
16
+ this.hasFilters = this.encoder.context.hasFilters;
17
+ this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;
18
+ if (this.hasFilters) {
19
+ this.views = /* @__PURE__ */ new Map();
20
+ }
13
21
  }
14
22
  getFullState(client) {
15
- const fullEncodedState = this.state.encodeAll(this.useFilters);
16
- if (client && this.useFilters) {
17
- return this.state.applyFilters(client, true);
23
+ if (this.needFullEncode || this.encoder.root.changes.size > 0) {
24
+ this.sharedOffsetCache = { offset: 1 };
25
+ this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);
26
+ this.needFullEncode = false;
27
+ }
28
+ if (this.hasFilters && client?.view) {
29
+ return this.encoder.encodeAllView(
30
+ client.view,
31
+ this.sharedOffsetCache.offset,
32
+ { ...this.sharedOffsetCache },
33
+ this.fullEncodeBuffer
34
+ );
18
35
  } else {
19
- return fullEncodedState;
36
+ return this.fullEncodeCache;
20
37
  }
21
38
  }
22
39
  applyPatches(clients) {
23
- const hasChanges = this.state["$changes"].changes.size > 0;
24
- if (hasChanges) {
25
- let numClients = clients.length;
26
- if (debugPatch.enabled) {
27
- debugPatch.dumpChanges = dumpChanges(this.state);
40
+ let numClients = clients.length;
41
+ this.needFullEncode = this.encoder.root.changes.size > 0;
42
+ if (numClients == 0 || !this.needFullEncode && (!this.hasFilters || this.encoder.root.filteredChanges.size === 0)) {
43
+ return false;
44
+ }
45
+ if (debugPatch.enabled) {
46
+ debugPatch.dumpChanges = dumpChanges(this.encoder.state);
47
+ }
48
+ const it = { offset: 1 };
49
+ this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;
50
+ const encodedChanges = this.encoder.encode(it);
51
+ if (!this.hasFilters) {
52
+ while (numClients--) {
53
+ const client = clients[numClients];
54
+ if (client.state !== ClientState.JOINED) {
55
+ continue;
56
+ }
57
+ client.raw(encodedChanges);
28
58
  }
29
- const patches = this.state.encode(false, [], this.useFilters);
30
- if (!this.useFilters) {
31
- patches.unshift(Protocol.ROOM_STATE_PATCH);
32
- while (numClients--) {
33
- const client = clients[numClients];
34
- if (client.state === ClientState.JOINED) {
35
- client.raw(patches);
36
- }
59
+ } else {
60
+ const sharedOffset = it.offset;
61
+ while (numClients--) {
62
+ const client = clients[numClients];
63
+ if (client.state !== ClientState.JOINED) {
64
+ continue;
37
65
  }
38
- } else {
39
- while (numClients--) {
40
- const client = clients[numClients];
41
- if (client.state === ClientState.JOINED) {
42
- const filteredPatches = this.state.applyFilters(client);
43
- client.raw([Protocol.ROOM_STATE_PATCH, ...filteredPatches]);
44
- }
66
+ const view = client.view || SHARED_VIEW;
67
+ let encodedView = this.views.get(view);
68
+ if (encodedView === void 0) {
69
+ encodedView = view === SHARED_VIEW ? encodedChanges : this.encoder.encodeView(client.view, sharedOffset, it);
70
+ this.views.set(view, encodedView);
45
71
  }
46
- this.state.discardAllChanges();
47
- }
48
- if (debugPatch.enabled) {
49
- debugPatch(
50
- "%d bytes sent to %d clients, %j",
51
- patches.length,
52
- clients.length,
53
- debugPatch.dumpChanges
54
- );
72
+ client.raw(encodedView);
55
73
  }
74
+ this.views.clear();
75
+ }
76
+ this.encoder.discardChanges();
77
+ if (debugPatch.enabled) {
78
+ debugPatch(
79
+ "%d bytes sent to %d clients, %j",
80
+ encodedChanges.length,
81
+ clients.length,
82
+ debugPatch.dumpChanges
83
+ );
56
84
  }
57
- return hasChanges;
85
+ return true;
58
86
  }
59
87
  handshake() {
60
88
  if (!this.handshakeCache) {
61
- this.handshakeCache = this.state && Reflection.encode(this.state);
89
+ this.handshakeCache = this.encoder.state && Reflection.encode(this.encoder.state);
62
90
  }
63
91
  return this.handshakeCache;
64
92
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/serializer/SchemaSerializer.ts"],
4
- "sourcesContent": ["/* tslint:disable:no-string-literal */\n\nimport { Client } from '..';\nimport { Serializer } from './Serializer';\n\nimport { dumpChanges, hasFilter, Reflection, Schema } from '@colyseus/schema';\nimport { debugPatch } from '../Debug';\nimport { Protocol } from '../Protocol';\nimport { ClientState } from '../Transport';\n\nexport class SchemaSerializer<T> implements Serializer<T> {\n public id = 'schema';\n\n private state: T & Schema;\n private useFilters: boolean = false;\n\n private handshakeCache: number[];\n\n // private needFullEncode = true;\n // private fullEncodedState: number[];\n\n public reset(newState: T & Schema) {\n this.state = newState;\n this.useFilters = hasFilter(newState.constructor as typeof Schema);\n }\n\n public getFullState(client?: Client) {\n const fullEncodedState = this.state.encodeAll(this.useFilters);\n\n // const fullEncodedState = (this.needFullEncode)\n // ? this.state.encodeAll(this.useFilters)\n // : this.fullEncodedState;\n\n // this.fullEncodedState = fullEncodedState;\n // this.needFullEncode = false;\n\n if (client && this.useFilters) {\n return this.state.applyFilters(client, true);\n\n } else {\n return fullEncodedState;\n }\n }\n\n public applyPatches(clients: Client[]) {\n const hasChanges = this.state['$changes'].changes.size > 0;\n\n if (hasChanges) {\n // this.needFullEncode = true;\n\n let numClients = clients.length;\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.state);\n }\n\n // get patch bytes\n const patches = this.state.encode(false, [], this.useFilters);\n\n if (!this.useFilters) {\n // encode changes once, for all clients\n patches.unshift(Protocol.ROOM_STATE_PATCH);\n\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check.\n //\n if (client.state === ClientState.JOINED) {\n client.raw(patches);\n }\n }\n\n } else {\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check.\n //\n if (client.state === ClientState.JOINED) {\n const filteredPatches = this.state.applyFilters(client);\n client.raw([Protocol.ROOM_STATE_PATCH, ...filteredPatches]);\n }\n }\n\n this.state.discardAllChanges();\n }\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n patches.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n }\n\n return hasChanges;\n }\n\n public handshake() {\n /**\n * Cache handshake to avoid encoding it for each client joining\n */\n if (!this.handshakeCache) {\n this.handshakeCache = (this.state && Reflection.encode(this.state));\n }\n\n return this.handshakeCache;\n }\n\n}\n"],
5
- "mappings": "AAKA,SAAS,aAAa,WAAW,kBAA0B;AAC3D,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAErB,MAAM,iBAA6C;AAAA,EAAnD;AACL,SAAO,KAAK;AAGZ,SAAQ,aAAsB;AAAA;AAAA,EAOvB,MAAM,UAAsB;AACjC,SAAK,QAAQ;AACb,SAAK,aAAa,UAAU,SAAS,WAA4B;AAAA,EACnE;AAAA,EAEO,aAAa,QAAiB;AACnC,UAAM,mBAAmB,KAAK,MAAM,UAAU,KAAK,UAAU;AAS7D,QAAI,UAAU,KAAK,YAAY;AAC7B,aAAO,KAAK,MAAM,aAAa,QAAQ,IAAI;AAAA,IAE7C,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEO,aAAa,SAAmB;AACrC,UAAM,aAAa,KAAK,MAAM,YAAY,QAAQ,OAAO;AAEzD,QAAI,YAAY;AAGd,UAAI,aAAa,QAAQ;AAGzB,UAAI,WAAW,SAAS;AACtB,QAAC,WAAmB,cAAc,YAAY,KAAK,KAAK;AAAA,MAC1D;AAGA,YAAM,UAAU,KAAK,MAAM,OAAO,OAAO,CAAC,GAAG,KAAK,UAAU;AAE5D,UAAI,CAAC,KAAK,YAAY;AAEpB,gBAAQ,QAAQ,SAAS,gBAAgB;AAEzC,eAAO,cAAc;AACnB,gBAAM,SAAS,QAAQ;AAKvB,cAAI,OAAO,UAAU,YAAY,QAAQ;AACvC,mBAAO,IAAI,OAAO;AAAA,UACpB;AAAA,QACF;AAAA,MAEF,OAAO;AAGL,eAAO,cAAc;AACnB,gBAAM,SAAS,QAAQ;AAKvB,cAAI,OAAO,UAAU,YAAY,QAAQ;AACvC,kBAAM,kBAAkB,KAAK,MAAM,aAAa,MAAM;AACtD,mBAAO,IAAI,CAAC,SAAS,kBAAkB,GAAG,eAAe,CAAC;AAAA,UAC5D;AAAA,QACF;AAEA,aAAK,MAAM,kBAAkB;AAAA,MAC/B;AAGA,UAAI,WAAW,SAAS;AACtB;AAAA,UACE;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,UACP,WAAmB;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,YAAY;AAIjB,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,iBAAkB,KAAK,SAAS,WAAW,OAAO,KAAK,KAAK;AAAA,IACnE;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
4
+ "sourcesContent": ["import { Serializer } from './Serializer';\n\nimport { Encoder, dumpChanges, Reflection, Schema, Iterator, StateView } from '@colyseus/schema';\nimport { debugPatch } from '../Debug';\nimport { Protocol } from '../Protocol';\nimport { Client, ClientState } from '../Transport';\n\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializer<T> implements Serializer<T> {\n public id = 'schema';\n\n protected encoder: Encoder;\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.size > 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 this.needFullEncode = (this.encoder.root.changes.size > 0);\n\n if (\n numClients == 0 ||\n (\n !this.needFullEncode &&\n (!this.hasFilters || this.encoder.root.filteredChanges.size === 0)\n )\n ) {\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\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 // TODO: re-use handshake buffer for all rooms\n this.handshakeCache = (this.encoder.state && Reflection.encode(this.encoder.state));\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,MAAM,cAAc,CAAC;AAEd,MAAM,iBAA6C;AAAA,EAAnD;AACL,SAAO,KAAK;AAGZ,SAAU,aAAsB;AAKhC,SAAU,iBAA0B;AAGpC,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,KAAK,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,OAAO,GAAG;AAC7D,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;AACzB,SAAK,iBAAkB,KAAK,QAAQ,KAAK,QAAQ,OAAO;AAExD,QACE,cAAc,KAEZ,CAAC,KAAK,mBACL,CAAC,KAAK,cAAc,KAAK,QAAQ,KAAK,gBAAgB,SAAS,IAElE;AAKA,aAAO;AAAA,IACT;AAIA,QAAI,WAAW,SAAS;AACtB,MAAC,WAAmB,cAAc,YAAY,KAAK,QAAQ,KAAK;AAAA,IAClE;AAGA,UAAM,KAAe,EAAE,QAAQ,EAAE;AACjC,SAAK,QAAQ,aAAa,KAAK,SAAS;AAGxC,UAAM,iBAAiB,KAAK,QAAQ,OAAO,EAAE;AAE7C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO,cAAc;AACnB,cAAM,SAAS,QAAQ;AAKvB,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;AAKvB,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;AAExB,WAAK,iBAAkB,KAAK,QAAQ,SAAS,WAAW,OAAO,KAAK,QAAQ,KAAK;AAAA,IACnF;AAEA,WAAO,KAAK;AAAA,EACd;AAEF;",
6
6
  "names": []
7
7
  }
@@ -2,7 +2,7 @@ import { Client } from '..';
2
2
  export interface Serializer<T> {
3
3
  id: string;
4
4
  reset(data: any): void;
5
- getFullState(client?: Client): any;
5
+ getFullState(client?: Client): Buffer;
6
6
  applyPatches(clients: Client[], state: T): boolean;
7
- handshake?(): number[];
7
+ handshake?(): Buffer;
8
8
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/serializer/Serializer.ts"],
4
- "sourcesContent": ["import { Client } from '..';\n\nexport interface Serializer<T> {\n id: string;\n reset(data: any): void;\n getFullState(client?: Client): any;\n applyPatches(clients: Client[], state: T): boolean;\n handshake?(): number[];\n}\n"],
4
+ "sourcesContent": ["import { Client } from '..';\n\nexport interface Serializer<T> {\n id: string;\n reset(data: any): void;\n getFullState(client?: Client): Buffer;\n applyPatches(clients: Client[], state: T): boolean;\n handshake?(): Buffer;\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -49,7 +49,7 @@ async function reloadFromCache() {
49
49
  const roomHistory = JSON.parse(value);
50
50
  debugDevMode("restoring room %s (%s)", roomHistory.roomName, roomId);
51
51
  const recreatedRoomListing = await (0, import_MatchMaker.handleCreateRoom)(roomHistory.roomName, roomHistory.clientOptions, roomId);
52
- const recreatedRoom = (0, import_MatchMaker.getRoomById)(recreatedRoomListing.roomId);
52
+ const recreatedRoom = (0, import_MatchMaker.getLocalRoomById)(recreatedRoomListing.roomId);
53
53
  import_Logger.logger.debug(`\u{1F504} room '${roomId}' has been restored.`);
54
54
  if (roomHistory.hasOwnProperty("state")) {
55
55
  recreatedRoom.state.decode(roomHistory.state);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/DevMode.ts"],
4
- "sourcesContent": ["import debug from \"debug\";\nimport { logger } from \"../Logger\";\nimport { debugAndPrintError } from \"../Debug\";\n\nimport { getRoomById, handleCreateRoom, presence, remoteRoomCall } from \"../MatchMaker\";\nimport type { Room } from \"../Room\";\n\nexport const debugDevMode = debug('colyseus:devmode');\n\nexport let isDevMode: boolean = false;\n\nexport function setDevMode(bool: boolean) {\n isDevMode = bool;\n}\n\nexport async function reloadFromCache() {\n const roomHistoryList = Object.entries(await presence.hgetall(getRoomRestoreListKey()));\n debugDevMode(\"rooms to restore: %i\", roomHistoryList.length);\n\n for (const [roomId, value] of roomHistoryList) {\n const roomHistory = JSON.parse(value);\n debugDevMode(\"restoring room %s (%s)\", roomHistory.roomName, roomId);\n\n const recreatedRoomListing = await handleCreateRoom(roomHistory.roomName, roomHistory.clientOptions, roomId);\n const recreatedRoom = getRoomById(recreatedRoomListing.roomId);\n logger.debug(`\uD83D\uDD04 room '${roomId}' has been restored.`);\n\n // Set previous state\n if (roomHistory.hasOwnProperty(\"state\")) {\n recreatedRoom.state.decode(roomHistory.state);\n\n //\n // WORKAROUND: @colyseus/schema is not capable of encoding a decoded\n // state. thus, we need a fresh clone immediately after decoding\n //\n recreatedRoom.setState(recreatedRoom.state.clone());\n logger.debug(`\uD83D\uDCCB room '${roomId}' state =>`, recreatedRoom.state.toJSON());\n }\n\n // call `onRestoreRoom` with custom 'cache'd property.\n recreatedRoom.onRestoreRoom?.(roomHistory[\"cache\"]);\n\n // Reserve seats for clients from cached history\n if (roomHistory.clients) {\n for (const previousSessionId of roomHistory.clients) {\n // reserve seat for 20 seconds\n await remoteRoomCall(recreatedRoomListing.roomId, '_reserveSeat', [previousSessionId, {}, 20, false, true]);\n }\n }\n }\n\n if (roomHistoryList.length > 0) {\n logger.debug(\"\u2705\", roomHistoryList.length, \"room(s) have been restored.\");\n }\n}\n\nexport async function cacheRoomHistory(rooms: { [roomId: string]: Room }) {\n for (const room of Object.values(rooms)) {\n const roomHistoryResult = await presence.hget(getRoomRestoreListKey(), room.roomId);\n if (roomHistoryResult) {\n try {\n const roomHistory = JSON.parse(roomHistoryResult);\n\n // custom cache method\n roomHistory[\"cache\"] = room.onCacheRoom?.();\n\n // encode state\n debugDevMode(\"caching room %s (%s)\", room.roomName, room.roomId);\n\n if (room.state) {\n roomHistory[\"state\"] = room.state.encodeAll();\n }\n\n // cache active clients and reserved seats\n roomHistory[\"clients\"] = room.clients.map((client) => client.sessionId);\n\n for (const sessionId in room['reservedSeats']) {\n roomHistory[\"clients\"].push(sessionId);\n }\n\n await presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify(roomHistory));\n\n // Rewrite updated room history\n logger.debug(`\uD83D\uDCBE caching room '${room.roomId}' (clients: ${room.clients.length}, state size: ${(roomHistory[\"state\"] || []).length} bytes)`);\n\n } catch (e) {\n debugAndPrintError(`\u274C couldn't cache room '${room.roomId}', due to:\\n${e.stack}`);\n }\n }\n }\n}\n\nexport async function getPreviousProcessId(hostname) {\n return await presence.hget(getProcessRestoreKey(), hostname);\n}\n\nexport function getRoomRestoreListKey() {\n return 'roomhistory';\n}\n\nexport function getProcessRestoreKey() {\n return 'processhistory';\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAClB,oBAAuB;AACvB,mBAAmC;AAEnC,wBAAwE;AAGjE,MAAM,mBAAe,aAAAA,SAAM,kBAAkB;AAE7C,IAAI,YAAqB;AAEzB,SAAS,WAAW,MAAe;AACxC,cAAY;AACd;AAEA,eAAsB,kBAAkB;AACtC,QAAM,kBAAkB,OAAO,QAAQ,MAAM,2BAAS,QAAQ,sBAAsB,CAAC,CAAC;AACtF,eAAa,wBAAwB,gBAAgB,MAAM;AAE3D,aAAW,CAAC,QAAQ,KAAK,KAAK,iBAAiB;AAC7C,UAAM,cAAc,KAAK,MAAM,KAAK;AACpC,iBAAa,0BAA0B,YAAY,UAAU,MAAM;AAEnE,UAAM,uBAAuB,UAAM,oCAAiB,YAAY,UAAU,YAAY,eAAe,MAAM;AAC3G,UAAM,oBAAgB,+BAAY,qBAAqB,MAAM;AAC7D,yBAAO,MAAM,mBAAY,4BAA4B;AAGrD,QAAI,YAAY,eAAe,OAAO,GAAG;AACvC,oBAAc,MAAM,OAAO,YAAY,KAAK;AAM5C,oBAAc,SAAS,cAAc,MAAM,MAAM,CAAC;AAClD,2BAAO,MAAM,mBAAY,oBAAoB,cAAc,MAAM,OAAO,CAAC;AAAA,IAC3E;AAGA,kBAAc,gBAAgB,YAAY,QAAQ;AAGlD,QAAI,YAAY,SAAS;AACvB,iBAAW,qBAAqB,YAAY,SAAS;AAEnD,kBAAM,kCAAe,qBAAqB,QAAQ,gBAAgB,CAAC,mBAAmB,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC;AAAA,MAC5G;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB,SAAS,GAAG;AAC9B,yBAAO,MAAM,UAAK,gBAAgB,QAAQ,6BAA6B;AAAA,EACzE;AACF;AAEA,eAAsB,iBAAiB,OAAmC;AACxE,aAAW,QAAQ,OAAO,OAAO,KAAK,GAAG;AACvC,UAAM,oBAAoB,MAAM,2BAAS,KAAK,sBAAsB,GAAG,KAAK,MAAM;AAClF,QAAI,mBAAmB;AACrB,UAAI;AACF,cAAM,cAAc,KAAK,MAAM,iBAAiB;AAGhD,oBAAY,WAAW,KAAK,cAAc;AAG1C,qBAAa,wBAAwB,KAAK,UAAU,KAAK,MAAM;AAE/D,YAAI,KAAK,OAAO;AACd,sBAAY,WAAW,KAAK,MAAM,UAAU;AAAA,QAC9C;AAGA,oBAAY,aAAa,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,SAAS;AAEtE,mBAAW,aAAa,KAAK,kBAAkB;AAC7C,sBAAY,WAAW,KAAK,SAAS;AAAA,QACvC;AAEA,cAAM,2BAAS,KAAK,sBAAsB,GAAG,KAAK,QAAQ,KAAK,UAAU,WAAW,CAAC;AAGrF,6BAAO,MAAM,2BAAoB,KAAK,qBAAqB,KAAK,QAAQ,wBAAwB,YAAY,YAAY,CAAC,GAAG,eAAe;AAAA,MAE7I,SAAS,GAAP;AACA,6CAAmB,+BAA0B,KAAK;AAAA,EAAqB,EAAE,OAAO;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,qBAAqB,UAAU;AACnD,SAAO,MAAM,2BAAS,KAAK,qBAAqB,GAAG,QAAQ;AAC7D;AAEO,SAAS,wBAAwB;AACtC,SAAO;AACT;AAEO,SAAS,uBAAuB;AACrC,SAAO;AACT;",
4
+ "sourcesContent": ["import debug from \"debug\";\nimport { logger } from \"../Logger\";\nimport { debugAndPrintError } from \"../Debug\";\n\nimport { getLocalRoomById, handleCreateRoom, presence, remoteRoomCall } from \"../MatchMaker\";\nimport type { Room } from \"../Room\";\n\nexport const debugDevMode = debug('colyseus:devmode');\n\nexport let isDevMode: boolean = false;\n\nexport function setDevMode(bool: boolean) {\n isDevMode = bool;\n}\n\nexport async function reloadFromCache() {\n const roomHistoryList = Object.entries(await presence.hgetall(getRoomRestoreListKey()));\n debugDevMode(\"rooms to restore: %i\", roomHistoryList.length);\n\n for (const [roomId, value] of roomHistoryList) {\n const roomHistory = JSON.parse(value);\n debugDevMode(\"restoring room %s (%s)\", roomHistory.roomName, roomId);\n\n const recreatedRoomListing = await handleCreateRoom(roomHistory.roomName, roomHistory.clientOptions, roomId);\n const recreatedRoom = getLocalRoomById(recreatedRoomListing.roomId);\n logger.debug(`\uD83D\uDD04 room '${roomId}' has been restored.`);\n\n // Set previous state\n if (roomHistory.hasOwnProperty(\"state\")) {\n recreatedRoom.state.decode(roomHistory.state);\n\n //\n // WORKAROUND: @colyseus/schema is not capable of encoding a decoded\n // state. thus, we need a fresh clone immediately after decoding\n //\n recreatedRoom.setState(recreatedRoom.state.clone());\n logger.debug(`\uD83D\uDCCB room '${roomId}' state =>`, recreatedRoom.state.toJSON());\n }\n\n // call `onRestoreRoom` with custom 'cache'd property.\n recreatedRoom.onRestoreRoom?.(roomHistory[\"cache\"]);\n\n // Reserve seats for clients from cached history\n if (roomHistory.clients) {\n for (const previousSessionId of roomHistory.clients) {\n // reserve seat for 20 seconds\n await remoteRoomCall(recreatedRoomListing.roomId, '_reserveSeat', [previousSessionId, {}, 20, false, true]);\n }\n }\n }\n\n if (roomHistoryList.length > 0) {\n logger.debug(\"\u2705\", roomHistoryList.length, \"room(s) have been restored.\");\n }\n}\n\nexport async function cacheRoomHistory(rooms: { [roomId: string]: Room }) {\n for (const room of Object.values(rooms)) {\n const roomHistoryResult = await presence.hget(getRoomRestoreListKey(), room.roomId);\n if (roomHistoryResult) {\n try {\n const roomHistory = JSON.parse(roomHistoryResult);\n\n // custom cache method\n roomHistory[\"cache\"] = room.onCacheRoom?.();\n\n // encode state\n debugDevMode(\"caching room %s (%s)\", room.roomName, room.roomId);\n\n if (room.state) {\n roomHistory[\"state\"] = room.state.encodeAll();\n }\n\n // cache active clients and reserved seats\n roomHistory[\"clients\"] = room.clients.map((client) => client.sessionId);\n\n for (const sessionId in room['reservedSeats']) {\n roomHistory[\"clients\"].push(sessionId);\n }\n\n await presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify(roomHistory));\n\n // Rewrite updated room history\n logger.debug(`\uD83D\uDCBE caching room '${room.roomId}' (clients: ${room.clients.length}, state size: ${(roomHistory[\"state\"] || []).length} bytes)`);\n\n } catch (e) {\n debugAndPrintError(`\u274C couldn't cache room '${room.roomId}', due to:\\n${e.stack}`);\n }\n }\n }\n}\n\nexport async function getPreviousProcessId(hostname) {\n return await presence.hget(getProcessRestoreKey(), hostname);\n}\n\nexport function getRoomRestoreListKey() {\n return 'roomhistory';\n}\n\nexport function getProcessRestoreKey() {\n return 'processhistory';\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAClB,oBAAuB;AACvB,mBAAmC;AAEnC,wBAA6E;AAGtE,MAAM,mBAAe,aAAAA,SAAM,kBAAkB;AAE7C,IAAI,YAAqB;AAEzB,SAAS,WAAW,MAAe;AACxC,cAAY;AACd;AAEA,eAAsB,kBAAkB;AACtC,QAAM,kBAAkB,OAAO,QAAQ,MAAM,2BAAS,QAAQ,sBAAsB,CAAC,CAAC;AACtF,eAAa,wBAAwB,gBAAgB,MAAM;AAE3D,aAAW,CAAC,QAAQ,KAAK,KAAK,iBAAiB;AAC7C,UAAM,cAAc,KAAK,MAAM,KAAK;AACpC,iBAAa,0BAA0B,YAAY,UAAU,MAAM;AAEnE,UAAM,uBAAuB,UAAM,oCAAiB,YAAY,UAAU,YAAY,eAAe,MAAM;AAC3G,UAAM,oBAAgB,oCAAiB,qBAAqB,MAAM;AAClE,yBAAO,MAAM,mBAAY,4BAA4B;AAGrD,QAAI,YAAY,eAAe,OAAO,GAAG;AACvC,oBAAc,MAAM,OAAO,YAAY,KAAK;AAM5C,oBAAc,SAAS,cAAc,MAAM,MAAM,CAAC;AAClD,2BAAO,MAAM,mBAAY,oBAAoB,cAAc,MAAM,OAAO,CAAC;AAAA,IAC3E;AAGA,kBAAc,gBAAgB,YAAY,QAAQ;AAGlD,QAAI,YAAY,SAAS;AACvB,iBAAW,qBAAqB,YAAY,SAAS;AAEnD,kBAAM,kCAAe,qBAAqB,QAAQ,gBAAgB,CAAC,mBAAmB,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC;AAAA,MAC5G;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB,SAAS,GAAG;AAC9B,yBAAO,MAAM,UAAK,gBAAgB,QAAQ,6BAA6B;AAAA,EACzE;AACF;AAEA,eAAsB,iBAAiB,OAAmC;AACxE,aAAW,QAAQ,OAAO,OAAO,KAAK,GAAG;AACvC,UAAM,oBAAoB,MAAM,2BAAS,KAAK,sBAAsB,GAAG,KAAK,MAAM;AAClF,QAAI,mBAAmB;AACrB,UAAI;AACF,cAAM,cAAc,KAAK,MAAM,iBAAiB;AAGhD,oBAAY,WAAW,KAAK,cAAc;AAG1C,qBAAa,wBAAwB,KAAK,UAAU,KAAK,MAAM;AAE/D,YAAI,KAAK,OAAO;AACd,sBAAY,WAAW,KAAK,MAAM,UAAU;AAAA,QAC9C;AAGA,oBAAY,aAAa,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,SAAS;AAEtE,mBAAW,aAAa,KAAK,kBAAkB;AAC7C,sBAAY,WAAW,KAAK,SAAS;AAAA,QACvC;AAEA,cAAM,2BAAS,KAAK,sBAAsB,GAAG,KAAK,QAAQ,KAAK,UAAU,WAAW,CAAC;AAGrF,6BAAO,MAAM,2BAAoB,KAAK,qBAAqB,KAAK,QAAQ,wBAAwB,YAAY,YAAY,CAAC,GAAG,eAAe;AAAA,MAE7I,SAAS,GAAP;AACA,6CAAmB,+BAA0B,KAAK;AAAA,EAAqB,EAAE,OAAO;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,qBAAqB,UAAU;AACnD,SAAO,MAAM,2BAAS,KAAK,qBAAqB,GAAG,QAAQ;AAC7D;AAEO,SAAS,wBAAwB;AACtC,SAAO;AACT;AAEO,SAAS,uBAAuB;AACrC,SAAO;AACT;",
6
6
  "names": ["debug"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import debug from "debug";
2
2
  import { logger } from "../Logger";
3
3
  import { debugAndPrintError } from "../Debug";
4
- import { getRoomById, handleCreateRoom, presence, remoteRoomCall } from "../MatchMaker";
4
+ import { getLocalRoomById, handleCreateRoom, presence, remoteRoomCall } from "../MatchMaker";
5
5
  const debugDevMode = debug("colyseus:devmode");
6
6
  let isDevMode = false;
7
7
  function setDevMode(bool) {
@@ -14,7 +14,7 @@ async function reloadFromCache() {
14
14
  const roomHistory = JSON.parse(value);
15
15
  debugDevMode("restoring room %s (%s)", roomHistory.roomName, roomId);
16
16
  const recreatedRoomListing = await handleCreateRoom(roomHistory.roomName, roomHistory.clientOptions, roomId);
17
- const recreatedRoom = getRoomById(recreatedRoomListing.roomId);
17
+ const recreatedRoom = getLocalRoomById(recreatedRoomListing.roomId);
18
18
  logger.debug(`\u{1F504} room '${roomId}' has been restored.`);
19
19
  if (roomHistory.hasOwnProperty("state")) {
20
20
  recreatedRoom.state.decode(roomHistory.state);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/DevMode.ts"],
4
- "sourcesContent": ["import debug from \"debug\";\nimport { logger } from \"../Logger\";\nimport { debugAndPrintError } from \"../Debug\";\n\nimport { getRoomById, handleCreateRoom, presence, remoteRoomCall } from \"../MatchMaker\";\nimport type { Room } from \"../Room\";\n\nexport const debugDevMode = debug('colyseus:devmode');\n\nexport let isDevMode: boolean = false;\n\nexport function setDevMode(bool: boolean) {\n isDevMode = bool;\n}\n\nexport async function reloadFromCache() {\n const roomHistoryList = Object.entries(await presence.hgetall(getRoomRestoreListKey()));\n debugDevMode(\"rooms to restore: %i\", roomHistoryList.length);\n\n for (const [roomId, value] of roomHistoryList) {\n const roomHistory = JSON.parse(value);\n debugDevMode(\"restoring room %s (%s)\", roomHistory.roomName, roomId);\n\n const recreatedRoomListing = await handleCreateRoom(roomHistory.roomName, roomHistory.clientOptions, roomId);\n const recreatedRoom = getRoomById(recreatedRoomListing.roomId);\n logger.debug(`\uD83D\uDD04 room '${roomId}' has been restored.`);\n\n // Set previous state\n if (roomHistory.hasOwnProperty(\"state\")) {\n recreatedRoom.state.decode(roomHistory.state);\n\n //\n // WORKAROUND: @colyseus/schema is not capable of encoding a decoded\n // state. thus, we need a fresh clone immediately after decoding\n //\n recreatedRoom.setState(recreatedRoom.state.clone());\n logger.debug(`\uD83D\uDCCB room '${roomId}' state =>`, recreatedRoom.state.toJSON());\n }\n\n // call `onRestoreRoom` with custom 'cache'd property.\n recreatedRoom.onRestoreRoom?.(roomHistory[\"cache\"]);\n\n // Reserve seats for clients from cached history\n if (roomHistory.clients) {\n for (const previousSessionId of roomHistory.clients) {\n // reserve seat for 20 seconds\n await remoteRoomCall(recreatedRoomListing.roomId, '_reserveSeat', [previousSessionId, {}, 20, false, true]);\n }\n }\n }\n\n if (roomHistoryList.length > 0) {\n logger.debug(\"\u2705\", roomHistoryList.length, \"room(s) have been restored.\");\n }\n}\n\nexport async function cacheRoomHistory(rooms: { [roomId: string]: Room }) {\n for (const room of Object.values(rooms)) {\n const roomHistoryResult = await presence.hget(getRoomRestoreListKey(), room.roomId);\n if (roomHistoryResult) {\n try {\n const roomHistory = JSON.parse(roomHistoryResult);\n\n // custom cache method\n roomHistory[\"cache\"] = room.onCacheRoom?.();\n\n // encode state\n debugDevMode(\"caching room %s (%s)\", room.roomName, room.roomId);\n\n if (room.state) {\n roomHistory[\"state\"] = room.state.encodeAll();\n }\n\n // cache active clients and reserved seats\n roomHistory[\"clients\"] = room.clients.map((client) => client.sessionId);\n\n for (const sessionId in room['reservedSeats']) {\n roomHistory[\"clients\"].push(sessionId);\n }\n\n await presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify(roomHistory));\n\n // Rewrite updated room history\n logger.debug(`\uD83D\uDCBE caching room '${room.roomId}' (clients: ${room.clients.length}, state size: ${(roomHistory[\"state\"] || []).length} bytes)`);\n\n } catch (e) {\n debugAndPrintError(`\u274C couldn't cache room '${room.roomId}', due to:\\n${e.stack}`);\n }\n }\n }\n}\n\nexport async function getPreviousProcessId(hostname) {\n return await presence.hget(getProcessRestoreKey(), hostname);\n}\n\nexport function getRoomRestoreListKey() {\n return 'roomhistory';\n}\n\nexport function getProcessRestoreKey() {\n return 'processhistory';\n}\n"],
5
- "mappings": "AAAA,OAAO,WAAW;AAClB,SAAS,cAAc;AACvB,SAAS,0BAA0B;AAEnC,SAAS,aAAa,kBAAkB,UAAU,sBAAsB;AAGjE,MAAM,eAAe,MAAM,kBAAkB;AAE7C,IAAI,YAAqB;AAEzB,SAAS,WAAW,MAAe;AACxC,cAAY;AACd;AAEA,eAAsB,kBAAkB;AACtC,QAAM,kBAAkB,OAAO,QAAQ,MAAM,SAAS,QAAQ,sBAAsB,CAAC,CAAC;AACtF,eAAa,wBAAwB,gBAAgB,MAAM;AAE3D,aAAW,CAAC,QAAQ,KAAK,KAAK,iBAAiB;AAC7C,UAAM,cAAc,KAAK,MAAM,KAAK;AACpC,iBAAa,0BAA0B,YAAY,UAAU,MAAM;AAEnE,UAAM,uBAAuB,MAAM,iBAAiB,YAAY,UAAU,YAAY,eAAe,MAAM;AAC3G,UAAM,gBAAgB,YAAY,qBAAqB,MAAM;AAC7D,WAAO,MAAM,mBAAY,4BAA4B;AAGrD,QAAI,YAAY,eAAe,OAAO,GAAG;AACvC,oBAAc,MAAM,OAAO,YAAY,KAAK;AAM5C,oBAAc,SAAS,cAAc,MAAM,MAAM,CAAC;AAClD,aAAO,MAAM,mBAAY,oBAAoB,cAAc,MAAM,OAAO,CAAC;AAAA,IAC3E;AAGA,kBAAc,gBAAgB,YAAY,QAAQ;AAGlD,QAAI,YAAY,SAAS;AACvB,iBAAW,qBAAqB,YAAY,SAAS;AAEnD,cAAM,eAAe,qBAAqB,QAAQ,gBAAgB,CAAC,mBAAmB,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC;AAAA,MAC5G;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB,SAAS,GAAG;AAC9B,WAAO,MAAM,UAAK,gBAAgB,QAAQ,6BAA6B;AAAA,EACzE;AACF;AAEA,eAAsB,iBAAiB,OAAmC;AACxE,aAAW,QAAQ,OAAO,OAAO,KAAK,GAAG;AACvC,UAAM,oBAAoB,MAAM,SAAS,KAAK,sBAAsB,GAAG,KAAK,MAAM;AAClF,QAAI,mBAAmB;AACrB,UAAI;AACF,cAAM,cAAc,KAAK,MAAM,iBAAiB;AAGhD,oBAAY,WAAW,KAAK,cAAc;AAG1C,qBAAa,wBAAwB,KAAK,UAAU,KAAK,MAAM;AAE/D,YAAI,KAAK,OAAO;AACd,sBAAY,WAAW,KAAK,MAAM,UAAU;AAAA,QAC9C;AAGA,oBAAY,aAAa,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,SAAS;AAEtE,mBAAW,aAAa,KAAK,kBAAkB;AAC7C,sBAAY,WAAW,KAAK,SAAS;AAAA,QACvC;AAEA,cAAM,SAAS,KAAK,sBAAsB,GAAG,KAAK,QAAQ,KAAK,UAAU,WAAW,CAAC;AAGrF,eAAO,MAAM,2BAAoB,KAAK,qBAAqB,KAAK,QAAQ,wBAAwB,YAAY,YAAY,CAAC,GAAG,eAAe;AAAA,MAE7I,SAAS,GAAP;AACA,2BAAmB,+BAA0B,KAAK;AAAA,EAAqB,EAAE,OAAO;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,qBAAqB,UAAU;AACnD,SAAO,MAAM,SAAS,KAAK,qBAAqB,GAAG,QAAQ;AAC7D;AAEO,SAAS,wBAAwB;AACtC,SAAO;AACT;AAEO,SAAS,uBAAuB;AACrC,SAAO;AACT;",
4
+ "sourcesContent": ["import debug from \"debug\";\nimport { logger } from \"../Logger\";\nimport { debugAndPrintError } from \"../Debug\";\n\nimport { getLocalRoomById, handleCreateRoom, presence, remoteRoomCall } from \"../MatchMaker\";\nimport type { Room } from \"../Room\";\n\nexport const debugDevMode = debug('colyseus:devmode');\n\nexport let isDevMode: boolean = false;\n\nexport function setDevMode(bool: boolean) {\n isDevMode = bool;\n}\n\nexport async function reloadFromCache() {\n const roomHistoryList = Object.entries(await presence.hgetall(getRoomRestoreListKey()));\n debugDevMode(\"rooms to restore: %i\", roomHistoryList.length);\n\n for (const [roomId, value] of roomHistoryList) {\n const roomHistory = JSON.parse(value);\n debugDevMode(\"restoring room %s (%s)\", roomHistory.roomName, roomId);\n\n const recreatedRoomListing = await handleCreateRoom(roomHistory.roomName, roomHistory.clientOptions, roomId);\n const recreatedRoom = getLocalRoomById(recreatedRoomListing.roomId);\n logger.debug(`\uD83D\uDD04 room '${roomId}' has been restored.`);\n\n // Set previous state\n if (roomHistory.hasOwnProperty(\"state\")) {\n recreatedRoom.state.decode(roomHistory.state);\n\n //\n // WORKAROUND: @colyseus/schema is not capable of encoding a decoded\n // state. thus, we need a fresh clone immediately after decoding\n //\n recreatedRoom.setState(recreatedRoom.state.clone());\n logger.debug(`\uD83D\uDCCB room '${roomId}' state =>`, recreatedRoom.state.toJSON());\n }\n\n // call `onRestoreRoom` with custom 'cache'd property.\n recreatedRoom.onRestoreRoom?.(roomHistory[\"cache\"]);\n\n // Reserve seats for clients from cached history\n if (roomHistory.clients) {\n for (const previousSessionId of roomHistory.clients) {\n // reserve seat for 20 seconds\n await remoteRoomCall(recreatedRoomListing.roomId, '_reserveSeat', [previousSessionId, {}, 20, false, true]);\n }\n }\n }\n\n if (roomHistoryList.length > 0) {\n logger.debug(\"\u2705\", roomHistoryList.length, \"room(s) have been restored.\");\n }\n}\n\nexport async function cacheRoomHistory(rooms: { [roomId: string]: Room }) {\n for (const room of Object.values(rooms)) {\n const roomHistoryResult = await presence.hget(getRoomRestoreListKey(), room.roomId);\n if (roomHistoryResult) {\n try {\n const roomHistory = JSON.parse(roomHistoryResult);\n\n // custom cache method\n roomHistory[\"cache\"] = room.onCacheRoom?.();\n\n // encode state\n debugDevMode(\"caching room %s (%s)\", room.roomName, room.roomId);\n\n if (room.state) {\n roomHistory[\"state\"] = room.state.encodeAll();\n }\n\n // cache active clients and reserved seats\n roomHistory[\"clients\"] = room.clients.map((client) => client.sessionId);\n\n for (const sessionId in room['reservedSeats']) {\n roomHistory[\"clients\"].push(sessionId);\n }\n\n await presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify(roomHistory));\n\n // Rewrite updated room history\n logger.debug(`\uD83D\uDCBE caching room '${room.roomId}' (clients: ${room.clients.length}, state size: ${(roomHistory[\"state\"] || []).length} bytes)`);\n\n } catch (e) {\n debugAndPrintError(`\u274C couldn't cache room '${room.roomId}', due to:\\n${e.stack}`);\n }\n }\n }\n}\n\nexport async function getPreviousProcessId(hostname) {\n return await presence.hget(getProcessRestoreKey(), hostname);\n}\n\nexport function getRoomRestoreListKey() {\n return 'roomhistory';\n}\n\nexport function getProcessRestoreKey() {\n return 'processhistory';\n}\n"],
5
+ "mappings": "AAAA,OAAO,WAAW;AAClB,SAAS,cAAc;AACvB,SAAS,0BAA0B;AAEnC,SAAS,kBAAkB,kBAAkB,UAAU,sBAAsB;AAGtE,MAAM,eAAe,MAAM,kBAAkB;AAE7C,IAAI,YAAqB;AAEzB,SAAS,WAAW,MAAe;AACxC,cAAY;AACd;AAEA,eAAsB,kBAAkB;AACtC,QAAM,kBAAkB,OAAO,QAAQ,MAAM,SAAS,QAAQ,sBAAsB,CAAC,CAAC;AACtF,eAAa,wBAAwB,gBAAgB,MAAM;AAE3D,aAAW,CAAC,QAAQ,KAAK,KAAK,iBAAiB;AAC7C,UAAM,cAAc,KAAK,MAAM,KAAK;AACpC,iBAAa,0BAA0B,YAAY,UAAU,MAAM;AAEnE,UAAM,uBAAuB,MAAM,iBAAiB,YAAY,UAAU,YAAY,eAAe,MAAM;AAC3G,UAAM,gBAAgB,iBAAiB,qBAAqB,MAAM;AAClE,WAAO,MAAM,mBAAY,4BAA4B;AAGrD,QAAI,YAAY,eAAe,OAAO,GAAG;AACvC,oBAAc,MAAM,OAAO,YAAY,KAAK;AAM5C,oBAAc,SAAS,cAAc,MAAM,MAAM,CAAC;AAClD,aAAO,MAAM,mBAAY,oBAAoB,cAAc,MAAM,OAAO,CAAC;AAAA,IAC3E;AAGA,kBAAc,gBAAgB,YAAY,QAAQ;AAGlD,QAAI,YAAY,SAAS;AACvB,iBAAW,qBAAqB,YAAY,SAAS;AAEnD,cAAM,eAAe,qBAAqB,QAAQ,gBAAgB,CAAC,mBAAmB,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC;AAAA,MAC5G;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB,SAAS,GAAG;AAC9B,WAAO,MAAM,UAAK,gBAAgB,QAAQ,6BAA6B;AAAA,EACzE;AACF;AAEA,eAAsB,iBAAiB,OAAmC;AACxE,aAAW,QAAQ,OAAO,OAAO,KAAK,GAAG;AACvC,UAAM,oBAAoB,MAAM,SAAS,KAAK,sBAAsB,GAAG,KAAK,MAAM;AAClF,QAAI,mBAAmB;AACrB,UAAI;AACF,cAAM,cAAc,KAAK,MAAM,iBAAiB;AAGhD,oBAAY,WAAW,KAAK,cAAc;AAG1C,qBAAa,wBAAwB,KAAK,UAAU,KAAK,MAAM;AAE/D,YAAI,KAAK,OAAO;AACd,sBAAY,WAAW,KAAK,MAAM,UAAU;AAAA,QAC9C;AAGA,oBAAY,aAAa,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,SAAS;AAEtE,mBAAW,aAAa,KAAK,kBAAkB;AAC7C,sBAAY,WAAW,KAAK,SAAS;AAAA,QACvC;AAEA,cAAM,SAAS,KAAK,sBAAsB,GAAG,KAAK,QAAQ,KAAK,UAAU,WAAW,CAAC;AAGrF,eAAO,MAAM,2BAAoB,KAAK,qBAAqB,KAAK,QAAQ,wBAAwB,YAAY,YAAY,CAAC,GAAG,eAAe;AAAA,MAE7I,SAAS,GAAP;AACA,2BAAmB,+BAA0B,KAAK;AAAA,EAAqB,EAAE,OAAO;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,qBAAqB,UAAU;AACnD,SAAO,MAAM,SAAS,KAAK,qBAAqB,GAAG,QAAQ;AAC7D;AAEO,SAAS,wBAAwB;AACtC,SAAO;AACT;AAEO,SAAS,uBAAuB;AACrC,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,6 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
1
  import { EventEmitter } from "events";
4
- import { ServerOpts, Socket } from "net";
5
2
  export declare const REMOTE_ROOM_SHORT_TIMEOUT: number;
3
+ export declare const MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME: number;
6
4
  export declare function generateId(length?: number): any;
7
5
  export declare function getBearerToken(authHeader: string): string;
8
6
  export declare function registerGracefulShutdown(callback: (err?: Error) => void): void;
@@ -17,10 +15,5 @@ export declare class Deferred<T = any> {
17
15
  catch(func: (value: any) => any): Promise<any>;
18
16
  }
19
17
  export declare function merge(a: any, ...objs: any[]): any;
20
- export declare interface DummyServer {
21
- constructor(options?: ServerOpts, connectionListener?: (socket: Socket) => void): any;
22
- listen(port?: number, hostname?: string, backlog?: number, listeningListener?: () => void): this;
23
- close(callback?: (err?: Error) => void): this;
24
- }
25
- export declare class DummyServer extends EventEmitter {
18
+ export declare class HttpServerMock extends EventEmitter {
26
19
  }
@@ -24,7 +24,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
24
24
  var Utils_exports = {};
25
25
  __export(Utils_exports, {
26
26
  Deferred: () => Deferred,
27
- DummyServer: () => DummyServer,
27
+ HttpServerMock: () => HttpServerMock,
28
+ MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME: () => MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME,
28
29
  REMOTE_ROOM_SHORT_TIMEOUT: () => REMOTE_ROOM_SHORT_TIMEOUT,
29
30
  generateId: () => generateId,
30
31
  getBearerToken: () => getBearerToken,
@@ -35,11 +36,12 @@ __export(Utils_exports, {
35
36
  });
36
37
  module.exports = __toCommonJS(Utils_exports);
37
38
  var import_nanoid = __toESM(require("nanoid"));
38
- var import_msgpackr = require("msgpackr");
39
+ var import_msgpackr = require("@colyseus/msgpackr");
39
40
  var import_Debug = require("../Debug");
40
41
  var import_events = require("events");
41
42
  var import_schema = require("@colyseus/schema");
42
43
  const REMOTE_ROOM_SHORT_TIMEOUT = Number(process.env.COLYSEUS_PRESENCE_SHORT_TIMEOUT || 2e3);
44
+ const MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME = Number(process.env.COLYSEUS_MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME || 1);
43
45
  function generateId(length = 9) {
44
46
  return (0, import_nanoid.default)(length);
45
47
  }
@@ -103,7 +105,7 @@ function merge(a, ...objs) {
103
105
  }
104
106
  return a;
105
107
  }
106
- class DummyServer extends import_events.EventEmitter {
108
+ class HttpServerMock extends import_events.EventEmitter {
107
109
  }
108
110
  (0, import_msgpackr.addExtension)({
109
111
  Class: import_schema.Schema,
@@ -118,7 +120,8 @@ class DummyServer extends import_events.EventEmitter {
118
120
  // Annotate the CommonJS export names for ESM import in node:
119
121
  0 && (module.exports = {
120
122
  Deferred,
121
- DummyServer,
123
+ HttpServerMock,
124
+ MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME,
122
125
  REMOTE_ROOM_SHORT_TIMEOUT,
123
126
  generateId,
124
127
  getBearerToken,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/Utils.ts"],
4
- "sourcesContent": ["import nanoid from 'nanoid';\nimport { addExtension } from 'msgpackr';\n\nimport { debugAndPrintError } from '../Debug';\nimport { EventEmitter } from \"events\";\nimport { ServerOpts, Socket } from \"net\";\nimport { Schema } from \"@colyseus/schema\";\n\n// remote room call timeouts\nexport const REMOTE_ROOM_SHORT_TIMEOUT = Number(process.env.COLYSEUS_PRESENCE_SHORT_TIMEOUT || 2000);\n\nexport function generateId(length: number = 9) {\n return nanoid(length);\n}\n\nexport function getBearerToken(authHeader: string) {\n return (authHeader && authHeader.startsWith(\"Bearer \") && authHeader.substring(7, authHeader.length)) || undefined;\n}\n\n// nodemon sends SIGUSR2 before reloading\n// (https://github.com/remy/nodemon#controlling-shutdown-of-your-script)\n//\nconst signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM', 'SIGUSR2'];\n\nexport function registerGracefulShutdown(callback: (err?: Error) => void) {\n /**\n * Gracefully shutdown on uncaught errors\n */\n process.on('uncaughtException', (err) => {\n debugAndPrintError(err);\n callback(err);\n });\n\n signals.forEach((signal) =>\n process.once(signal, () => callback()));\n}\n\nexport function retry<T = any>(\n cb: Function,\n maxRetries: number = 3,\n errorWhiteList: any[] = [],\n retries: number = 0,\n) {\n return new Promise<T>((resolve, reject) => {\n cb()\n .then(resolve)\n .catch((e) => {\n if (\n errorWhiteList.indexOf(e.constructor) !== -1 &&\n retries++ < maxRetries\n ) {\n setTimeout(() => {\n retry<T>(cb, maxRetries, errorWhiteList, retries).\n then(resolve).\n catch((e2) => reject(e2));\n }, Math.floor(Math.random() * Math.pow(2, retries) * 400));\n\n } else {\n reject(e);\n }\n });\n });\n}\n\nexport function spliceOne(arr: any[], index: number): boolean {\n // manually splice availableRooms array\n // http://jsperf.com/manual-splice\n if (index === -1 || index >= arr.length) {\n return false;\n }\n\n const len = arr.length - 1;\n for (let i = index; i < len; i++) {\n arr[i] = arr[i + 1];\n }\n\n arr.length = len;\n return true;\n}\n\nexport class Deferred<T= any> {\n public promise: Promise<T>;\n\n public resolve: Function;\n public reject: Function;\n\n constructor() {\n this.promise = new Promise<T>((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n\n public then(func: (value: T) => any) {\n return this.promise.then.apply(this.promise, arguments);\n }\n\n public catch(func: (value: any) => any) {\n return this.promise.catch(func);\n }\n\n}\n\nexport function merge(a: any, ...objs: any[]): any {\n for (let i = 0, len = objs.length; i < len; i++) {\n const b = objs[i];\n for (const key in b) {\n if (b.hasOwnProperty(key)) {\n a[key] = b[key];\n }\n }\n }\n return a;\n}\n\nexport declare interface DummyServer {\n constructor(options?: ServerOpts, connectionListener?: (socket: Socket) => void);\n\n listen(port?: number, hostname?: string, backlog?: number, listeningListener?: () => void): this;\n close(callback?: (err?: Error) => void): this;\n}\n\nexport class DummyServer extends EventEmitter {}\n\n// Add msgpackr extension to avoid circular references when encoding\n// https://github.com/kriszyp/msgpackr#custom-extensions\naddExtension({\n Class: Schema,\n type: 0,\n\n read(datum: any): any {\n return datum;\n },\n\n write(instance: any): any {\n return instance.toJSON();\n }\n});\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmB;AACnB,sBAA6B;AAE7B,mBAAmC;AACnC,oBAA6B;AAE7B,oBAAuB;AAGhB,MAAM,4BAA4B,OAAO,QAAQ,IAAI,mCAAmC,GAAI;AAE5F,SAAS,WAAW,SAAiB,GAAG;AAC7C,aAAO,cAAAA,SAAO,MAAM;AACtB;AAEO,SAAS,eAAe,YAAoB;AACjD,SAAQ,cAAc,WAAW,WAAW,SAAS,KAAK,WAAW,UAAU,GAAG,WAAW,MAAM,KAAM;AAC3G;AAKA,MAAM,UAA4B,CAAC,UAAU,WAAW,SAAS;AAE1D,SAAS,yBAAyB,UAAiC;AAIxE,UAAQ,GAAG,qBAAqB,CAAC,QAAQ;AACvC,yCAAmB,GAAG;AACtB,aAAS,GAAG;AAAA,EACd,CAAC;AAED,UAAQ,QAAQ,CAAC,WACf,QAAQ,KAAK,QAAQ,MAAM,SAAS,CAAC,CAAC;AAC1C;AAEO,SAAS,MACd,IACA,aAAqB,GACrB,iBAAwB,CAAC,GACzB,UAAkB,GAClB;AACA,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,OAAG,EACA,KAAK,OAAO,EACZ,MAAM,CAAC,MAAM;AACZ,UACE,eAAe,QAAQ,EAAE,WAAW,MAAM,MAC1C,YAAY,YACZ;AACA,mBAAW,MAAM;AACf,gBAAS,IAAI,YAAY,gBAAgB,OAAO,EAC9C,KAAK,OAAO,EACZ,MAAM,CAAC,OAAO,OAAO,EAAE,CAAC;AAAA,QAC5B,GAAG,KAAK,MAAM,KAAK,OAAO,IAAI,KAAK,IAAI,GAAG,OAAO,IAAI,GAAG,CAAC;AAAA,MAE3D,OAAO;AACL,eAAO,CAAC;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACL,CAAC;AACH;AAEO,SAAS,UAAU,KAAY,OAAwB;AAG5D,MAAI,UAAU,MAAM,SAAS,IAAI,QAAQ;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,IAAI,SAAS;AACzB,WAAS,IAAI,OAAO,IAAI,KAAK,KAAK;AAChC,QAAI,KAAK,IAAI,IAAI;AAAA,EACnB;AAEA,MAAI,SAAS;AACb,SAAO;AACT;AAEO,MAAM,SAAiB;AAAA,EAM5B,cAAc;AACZ,SAAK,UAAU,IAAI,QAAW,CAAC,SAAS,WAAW;AACjD,WAAK,UAAU;AACf,WAAK,SAAS;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEO,KAAK,MAAyB;AACnC,WAAO,KAAK,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS;AAAA,EACxD;AAAA,EAEO,MAAM,MAA2B;AACtC,WAAO,KAAK,QAAQ,MAAM,IAAI;AAAA,EAChC;AAEF;AAEO,SAAS,MAAM,MAAW,MAAkB;AACjD,WAAS,IAAI,GAAG,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK;AAC/C,UAAM,IAAI,KAAK;AACf,eAAW,OAAO,GAAG;AACnB,UAAI,EAAE,eAAe,GAAG,GAAG;AACzB,UAAE,OAAO,EAAE;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AASO,MAAM,oBAAoB,2BAAa;AAAC;AAAA,IAI/C,8BAAa;AAAA,EACX,OAAO;AAAA,EACP,MAAM;AAAA,EAEN,KAAK,OAAiB;AACpB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAoB;AACxB,WAAO,SAAS,OAAO;AAAA,EACzB;AACF,CAAC;",
4
+ "sourcesContent": ["import nanoid from 'nanoid';\nimport { addExtension } from '@colyseus/msgpackr';\n\nimport { debugAndPrintError } from '../Debug';\nimport { EventEmitter } from \"events\";\nimport { Schema } from \"@colyseus/schema\";\n\n// remote room call timeouts\nexport const REMOTE_ROOM_SHORT_TIMEOUT = Number(process.env.COLYSEUS_PRESENCE_SHORT_TIMEOUT || 2000);\nexport const MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME = Number(process.env.COLYSEUS_MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME || 1);\n\nexport function generateId(length: number = 9) {\n return nanoid(length);\n}\n\nexport function getBearerToken(authHeader: string) {\n return (authHeader && authHeader.startsWith(\"Bearer \") && authHeader.substring(7, authHeader.length)) || undefined;\n}\n\n// nodemon sends SIGUSR2 before reloading\n// (https://github.com/remy/nodemon#controlling-shutdown-of-your-script)\n//\nconst signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM', 'SIGUSR2'];\n\nexport function registerGracefulShutdown(callback: (err?: Error) => void) {\n /**\n * Gracefully shutdown on uncaught errors\n */\n process.on('uncaughtException', (err) => {\n debugAndPrintError(err);\n callback(err);\n });\n\n signals.forEach((signal) =>\n process.once(signal, () => callback()));\n}\n\nexport function retry<T = any>(\n cb: Function,\n maxRetries: number = 3,\n errorWhiteList: any[] = [],\n retries: number = 0,\n) {\n return new Promise<T>((resolve, reject) => {\n cb()\n .then(resolve)\n .catch((e) => {\n if (\n errorWhiteList.indexOf(e.constructor) !== -1 &&\n retries++ < maxRetries\n ) {\n setTimeout(() => {\n retry<T>(cb, maxRetries, errorWhiteList, retries).\n then(resolve).\n catch((e2) => reject(e2));\n }, Math.floor(Math.random() * Math.pow(2, retries) * 400));\n\n } else {\n reject(e);\n }\n });\n });\n}\n\nexport function spliceOne(arr: any[], index: number): boolean {\n // manually splice availableRooms array\n // http://jsperf.com/manual-splice\n if (index === -1 || index >= arr.length) {\n return false;\n }\n\n const len = arr.length - 1;\n for (let i = index; i < len; i++) {\n arr[i] = arr[i + 1];\n }\n\n arr.length = len;\n return true;\n}\n\nexport class Deferred<T= any> {\n public promise: Promise<T>;\n\n public resolve: Function;\n public reject: Function;\n\n constructor() {\n this.promise = new Promise<T>((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n\n public then(func: (value: T) => any) {\n return this.promise.then.apply(this.promise, arguments);\n }\n\n public catch(func: (value: any) => any) {\n return this.promise.catch(func);\n }\n\n}\n\nexport function merge(a: any, ...objs: any[]): any {\n for (let i = 0, len = objs.length; i < len; i++) {\n const b = objs[i];\n for (const key in b) {\n if (b.hasOwnProperty(key)) {\n a[key] = b[key];\n }\n }\n }\n return a;\n}\n\nexport class HttpServerMock extends EventEmitter {}\n\n// Add msgpackr extension to avoid circular references when encoding\n// https://github.com/kriszyp/msgpackr#custom-extensions\naddExtension({\n Class: Schema,\n type: 0,\n\n read(datum: any): any {\n return datum;\n },\n\n write(instance: any): any {\n return instance.toJSON();\n }\n});\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmB;AACnB,sBAA6B;AAE7B,mBAAmC;AACnC,oBAA6B;AAC7B,oBAAuB;AAGhB,MAAM,4BAA4B,OAAO,QAAQ,IAAI,mCAAmC,GAAI;AAC5F,MAAM,uCAAuC,OAAO,QAAQ,IAAI,iDAAiD,CAAC;AAElH,SAAS,WAAW,SAAiB,GAAG;AAC7C,aAAO,cAAAA,SAAO,MAAM;AACtB;AAEO,SAAS,eAAe,YAAoB;AACjD,SAAQ,cAAc,WAAW,WAAW,SAAS,KAAK,WAAW,UAAU,GAAG,WAAW,MAAM,KAAM;AAC3G;AAKA,MAAM,UAA4B,CAAC,UAAU,WAAW,SAAS;AAE1D,SAAS,yBAAyB,UAAiC;AAIxE,UAAQ,GAAG,qBAAqB,CAAC,QAAQ;AACvC,yCAAmB,GAAG;AACtB,aAAS,GAAG;AAAA,EACd,CAAC;AAED,UAAQ,QAAQ,CAAC,WACf,QAAQ,KAAK,QAAQ,MAAM,SAAS,CAAC,CAAC;AAC1C;AAEO,SAAS,MACd,IACA,aAAqB,GACrB,iBAAwB,CAAC,GACzB,UAAkB,GAClB;AACA,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,OAAG,EACA,KAAK,OAAO,EACZ,MAAM,CAAC,MAAM;AACZ,UACE,eAAe,QAAQ,EAAE,WAAW,MAAM,MAC1C,YAAY,YACZ;AACA,mBAAW,MAAM;AACf,gBAAS,IAAI,YAAY,gBAAgB,OAAO,EAC9C,KAAK,OAAO,EACZ,MAAM,CAAC,OAAO,OAAO,EAAE,CAAC;AAAA,QAC5B,GAAG,KAAK,MAAM,KAAK,OAAO,IAAI,KAAK,IAAI,GAAG,OAAO,IAAI,GAAG,CAAC;AAAA,MAE3D,OAAO;AACL,eAAO,CAAC;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACL,CAAC;AACH;AAEO,SAAS,UAAU,KAAY,OAAwB;AAG5D,MAAI,UAAU,MAAM,SAAS,IAAI,QAAQ;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,IAAI,SAAS;AACzB,WAAS,IAAI,OAAO,IAAI,KAAK,KAAK;AAChC,QAAI,KAAK,IAAI,IAAI;AAAA,EACnB;AAEA,MAAI,SAAS;AACb,SAAO;AACT;AAEO,MAAM,SAAiB;AAAA,EAM5B,cAAc;AACZ,SAAK,UAAU,IAAI,QAAW,CAAC,SAAS,WAAW;AACjD,WAAK,UAAU;AACf,WAAK,SAAS;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEO,KAAK,MAAyB;AACnC,WAAO,KAAK,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS;AAAA,EACxD;AAAA,EAEO,MAAM,MAA2B;AACtC,WAAO,KAAK,QAAQ,MAAM,IAAI;AAAA,EAChC;AAEF;AAEO,SAAS,MAAM,MAAW,MAAkB;AACjD,WAAS,IAAI,GAAG,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK;AAC/C,UAAM,IAAI,KAAK;AACf,eAAW,OAAO,GAAG;AACnB,UAAI,EAAE,eAAe,GAAG,GAAG;AACzB,UAAE,OAAO,EAAE;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,MAAM,uBAAuB,2BAAa;AAAC;AAAA,IAIlD,8BAAa;AAAA,EACX,OAAO;AAAA,EACP,MAAM;AAAA,EAEN,KAAK,OAAiB;AACpB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAoB;AACxB,WAAO,SAAS,OAAO;AAAA,EACzB;AACF,CAAC;",
6
6
  "names": ["nanoid"]
7
7
  }