@colyseus/core 0.18.3 → 0.18.5

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 (136) hide show
  1. package/build/Debug.cjs +1 -0
  2. package/build/Debug.cjs.map +1 -1
  3. package/build/IPC.cjs +1 -0
  4. package/build/IPC.cjs.map +1 -1
  5. package/build/Logger.cjs +1 -0
  6. package/build/Logger.cjs.map +1 -1
  7. package/build/MatchMaker.cjs +13 -5
  8. package/build/MatchMaker.cjs.map +2 -2
  9. package/build/MatchMaker.d.ts +10 -4
  10. package/build/MatchMaker.mjs +12 -5
  11. package/build/MatchMaker.mjs.map +2 -2
  12. package/build/Protocol.cjs +1 -0
  13. package/build/Protocol.cjs.map +1 -1
  14. package/build/Rewind.cjs +1 -0
  15. package/build/Rewind.cjs.map +1 -1
  16. package/build/Room.cjs +113 -3
  17. package/build/Room.cjs.map +2 -2
  18. package/build/Room.d.ts +58 -1
  19. package/build/Room.mjs +112 -3
  20. package/build/Room.mjs.map +2 -2
  21. package/build/RoomMessages.cjs +3 -1
  22. package/build/RoomMessages.cjs.map +2 -2
  23. package/build/RoomMessages.d.ts +3 -1
  24. package/build/RoomMessages.mjs +2 -1
  25. package/build/RoomMessages.mjs.map +2 -2
  26. package/build/RoomPlugin.cjs +1 -0
  27. package/build/RoomPlugin.cjs.map +1 -1
  28. package/build/Server.cjs +1 -0
  29. package/build/Server.cjs.map +1 -1
  30. package/build/Stats.cjs +1 -0
  31. package/build/Stats.cjs.map +1 -1
  32. package/build/Transport.cjs +39 -0
  33. package/build/Transport.cjs.map +2 -2
  34. package/build/Transport.d.ts +66 -1
  35. package/build/Transport.mjs +37 -1
  36. package/build/Transport.mjs.map +2 -2
  37. package/build/errors/RoomExceptions.cjs +1 -0
  38. package/build/errors/RoomExceptions.cjs.map +1 -1
  39. package/build/errors/SeatReservationError.cjs +1 -0
  40. package/build/errors/SeatReservationError.cjs.map +1 -1
  41. package/build/errors/ServerError.cjs +1 -0
  42. package/build/errors/ServerError.cjs.map +1 -1
  43. package/build/index.cjs +5 -0
  44. package/build/index.cjs.map +2 -2
  45. package/build/index.d.ts +1 -1
  46. package/build/index.mjs +3 -1
  47. package/build/index.mjs.map +2 -2
  48. package/build/input/InputBuffer.cjs +1 -0
  49. package/build/input/InputBuffer.cjs.map +1 -1
  50. package/build/input/RoomInput.cjs +64 -3
  51. package/build/input/RoomInput.cjs.map +2 -2
  52. package/build/input/RoomInput.d.ts +16 -2
  53. package/build/input/RoomInput.mjs +63 -3
  54. package/build/input/RoomInput.mjs.map +2 -2
  55. package/build/input/types.cjs +1 -0
  56. package/build/input/types.cjs.map +1 -1
  57. package/build/internal.cjs +1 -0
  58. package/build/internal.cjs.map +1 -1
  59. package/build/matchmaker/Lobby.cjs +1 -0
  60. package/build/matchmaker/Lobby.cjs.map +1 -1
  61. package/build/matchmaker/LocalDriver/LocalDriver.cjs +1 -0
  62. package/build/matchmaker/LocalDriver/LocalDriver.cjs.map +1 -1
  63. package/build/matchmaker/LocalDriver/Query.cjs +1 -0
  64. package/build/matchmaker/LocalDriver/Query.cjs.map +1 -1
  65. package/build/matchmaker/RegisteredHandler.cjs +1 -0
  66. package/build/matchmaker/RegisteredHandler.cjs.map +1 -1
  67. package/build/matchmaker/controller.cjs +1 -0
  68. package/build/matchmaker/controller.cjs.map +1 -1
  69. package/build/matchmaker/driver.cjs +1 -0
  70. package/build/matchmaker/driver.cjs.map +2 -2
  71. package/build/matchmaker/driver.d.ts +4 -2
  72. package/build/matchmaker/driver.mjs.map +1 -1
  73. package/build/presence/LocalPresence.cjs +1 -0
  74. package/build/presence/LocalPresence.cjs.map +1 -1
  75. package/build/presence/Presence.cjs +1 -0
  76. package/build/presence/Presence.cjs.map +1 -1
  77. package/build/rooms/LobbyRoom.cjs +1 -0
  78. package/build/rooms/LobbyRoom.cjs.map +1 -1
  79. package/build/rooms/QueueRoom.cjs +1 -0
  80. package/build/rooms/QueueRoom.cjs.map +1 -1
  81. package/build/rooms/RelayRoom.cjs +1 -0
  82. package/build/rooms/RelayRoom.cjs.map +1 -1
  83. package/build/router/default_routes.cjs +4 -8
  84. package/build/router/default_routes.cjs.map +2 -2
  85. package/build/router/default_routes.mjs +4 -9
  86. package/build/router/default_routes.mjs.map +2 -2
  87. package/build/router/index.cjs +7 -1
  88. package/build/router/index.cjs.map +2 -2
  89. package/build/router/index.mjs +6 -1
  90. package/build/router/index.mjs.map +2 -2
  91. package/build/router/node.cjs +23 -2
  92. package/build/router/node.cjs.map +2 -2
  93. package/build/router/node.mjs +22 -2
  94. package/build/router/node.mjs.map +2 -2
  95. package/build/serializer/NoneSerializer.cjs +1 -0
  96. package/build/serializer/NoneSerializer.cjs.map +1 -1
  97. package/build/serializer/SchemaSerializer.cjs +98 -0
  98. package/build/serializer/SchemaSerializer.cjs.map +2 -2
  99. package/build/serializer/SchemaSerializer.d.ts +25 -0
  100. package/build/serializer/SchemaSerializer.mjs +98 -1
  101. package/build/serializer/SchemaSerializer.mjs.map +2 -2
  102. package/build/serializer/Serializer.cjs +1 -0
  103. package/build/serializer/Serializer.cjs.map +2 -2
  104. package/build/serializer/Serializer.d.ts +15 -0
  105. package/build/utils/DevMode.cjs +1 -0
  106. package/build/utils/DevMode.cjs.map +1 -1
  107. package/build/utils/Env.cjs +1 -0
  108. package/build/utils/Env.cjs.map +1 -1
  109. package/build/utils/StandardSchema.cjs +1 -0
  110. package/build/utils/StandardSchema.cjs.map +1 -1
  111. package/build/utils/UserSessionIndex.cjs +1 -0
  112. package/build/utils/UserSessionIndex.cjs.map +1 -1
  113. package/build/utils/Utils.cjs +1 -0
  114. package/build/utils/Utils.cjs.map +2 -2
  115. package/build/utils/Utils.d.ts +12 -0
  116. package/build/utils/Utils.mjs.map +2 -2
  117. package/build/utils/nanoevents.cjs +5 -1
  118. package/build/utils/nanoevents.cjs.map +2 -2
  119. package/build/utils/nanoevents.d.ts +3 -1
  120. package/build/utils/nanoevents.mjs +4 -1
  121. package/build/utils/nanoevents.mjs.map +2 -2
  122. package/package.json +8 -7
  123. package/src/MatchMaker.ts +53 -15
  124. package/src/Room.ts +145 -4
  125. package/src/RoomMessages.ts +2 -1
  126. package/src/Transport.ts +132 -4
  127. package/src/index.ts +1 -1
  128. package/src/input/RoomInput.ts +76 -3
  129. package/src/matchmaker/driver.ts +4 -2
  130. package/src/router/default_routes.ts +4 -9
  131. package/src/router/index.ts +7 -0
  132. package/src/router/node.ts +26 -2
  133. package/src/serializer/SchemaSerializer.ts +146 -1
  134. package/src/serializer/Serializer.ts +17 -0
  135. package/src/utils/Utils.ts +18 -0
  136. package/src/utils/nanoevents.ts +4 -1
package/build/Room.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ const __cjsImportMetaUrl = require('node:url').pathToFileURL(__filename).href;
1
2
  "use strict";
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
@@ -64,6 +65,8 @@ var import_RoomPlugin = require("./RoomPlugin.cjs");
64
65
  var import_RoomPlugin2 = require("./RoomPlugin.cjs");
65
66
  var DEFAULT_PATCH_RATE = 1e3 / 20;
66
67
  var DEFAULT_SIMULATION_INTERVAL = 1e3 / 60;
68
+ var NOOP = () => {
69
+ };
67
70
  var noneSerializer = new import_NoneSerializer.NoneSerializer();
68
71
  var AFTER_PATCH_OPTS = Object.freeze({ afterNextPatch: true });
69
72
  var DEFAULT_SEAT_RESERVATION_TIME = Number(process.env.COLYSEUS_SEAT_RESERVATION_TIME || 15);
@@ -103,6 +106,42 @@ var Room = class _Room {
103
106
  * @default 50ms (20fps)
104
107
  */
105
108
  this.patchRate = DEFAULT_PATCH_RATE;
109
+ /**
110
+ * Frequency to flush `@unreliable` state fields, in milliseconds.
111
+ *
112
+ * Those fields never ride a state patch — they go out over the transport's
113
+ * unreliable channel (a WebTransport datagram), so a dropped frame costs one
114
+ * stale value instead of stalling the reliable stream behind a retransmit.
115
+ * Setting this decouples them from {@link patchRate}, which is the point:
116
+ * 60Hz movement over a 20Hz structural patch.
117
+ *
118
+ * KNOWN COST of a rate faster than {@link patchRate}: an entity's ADD travels
119
+ * the reliable channel, so datagrams sent between patches can reference a
120
+ * refId the client hasn't been told about yet. Those frames are skipped by the
121
+ * client's decoder — safe (the ref graph can't desync, since `@unreliable` is
122
+ * primitives-only) but each one logs `"refId" not found`, and that entity's
123
+ * first value lands one mutation later. Measured at `patchRate/this` reports
124
+ * per mid-session spawn. Leave this unset and the flush rides
125
+ * {@link broadcastPatch}, which ships the ADD first and avoids it entirely.
126
+ *
127
+ * Requires a transport with a datagram channel — today only
128
+ * `@colyseus/h3-transport` (WebTransport), which is **experimental**. Every
129
+ * WebSocket transport lacks one, and those clients are skipped entirely (the
130
+ * room warns once), so `@unreliable` fields keep their join-time value there.
131
+ *
132
+ * @default null — flush alongside every {@link broadcastPatch}, and only when
133
+ * the state actually declares an `@unreliable` field.
134
+ */
135
+ this.unreliablePatchRate = null;
136
+ this.#_unreliablePatchRate = null;
137
+ /**
138
+ * The unreliable flush, called unconditionally at the end of every
139
+ * {@link broadcastPatch}. Stays {@link NOOP} unless the state actually
140
+ * declares an `@unreliable` field, so a room that never uses the channel
141
+ * pays an empty call the engine inlines away — and there is no second
142
+ * entry point that could drift from `broadcastPatch()`.
143
+ */
144
+ this._flushUnreliable = NOOP;
106
145
  /**
107
146
  * Maximum number of messages a client can send to the server per second.
108
147
  * If a client sends more messages than this, it will be disconnected.
@@ -197,6 +236,8 @@ var Room = class _Room {
197
236
  #_autoDispose;
198
237
  #_patchRate;
199
238
  #_patchInterval;
239
+ #_unreliablePatchRate;
240
+ #_unreliablePatchInterval;
200
241
  #_state;
201
242
  #_messages;
202
243
  // Re-expose the registry for @colyseus/playground introspection and
@@ -218,6 +259,7 @@ var Room = class _Room {
218
259
  this.#_state = this.state;
219
260
  this.#_autoDispose = this.autoDispose;
220
261
  this.#_patchRate = this.patchRate;
262
+ this.#_unreliablePatchRate = this.unreliablePatchRate;
221
263
  this.#_maxClients = this.maxClients;
222
264
  Object.defineProperties(this, {
223
265
  state: {
@@ -233,6 +275,7 @@ var Room = class _Room {
233
275
  }
234
276
  this._serializer.reset(newState);
235
277
  this.#_state = newState;
278
+ this._armUnreliablePatches();
236
279
  }
237
280
  },
238
281
  maxClients: {
@@ -267,6 +310,14 @@ var Room = class _Room {
267
310
  this.#_patchInterval = setInterval(() => this.clock.tick(), DEFAULT_SIMULATION_INTERVAL);
268
311
  }
269
312
  }
313
+ },
314
+ unreliablePatchRate: {
315
+ enumerable: true,
316
+ get: () => this.#_unreliablePatchRate,
317
+ set: (milliseconds) => {
318
+ this.#_unreliablePatchRate = milliseconds;
319
+ this._armUnreliablePatches();
320
+ }
270
321
  }
271
322
  });
272
323
  this.patchRate = this.#_patchRate;
@@ -826,6 +877,7 @@ var Room = class _Room {
826
877
  this.state,
827
878
  this._inputController !== void 0 ? { sNow } : void 0
828
879
  );
880
+ this._flushUnreliable();
829
881
  this._flushPendingClientFrames();
830
882
  this._flushAfterPatchBroadcasts();
831
883
  const rw = this.#rewind;
@@ -834,6 +886,52 @@ var Room = class _Room {
834
886
  }
835
887
  return hasChanges;
836
888
  }
889
+ /**
890
+ * Encode and send the `@unreliable` state fields over each client's
891
+ * unreliable channel. Those fields never appear in a {@link broadcastPatch}
892
+ * frame, and clients on a transport without a datagram channel are skipped.
893
+ *
894
+ * Driven automatically once the state declares an `@unreliable` field — right
895
+ * after each {@link broadcastPatch}, or on its own timer when
896
+ * {@link unreliablePatchRate} is set. Public so a room driving
897
+ * `broadcastPatch()` by hand can drive this by hand too.
898
+ */
899
+ broadcastUnreliablePatch() {
900
+ if (!this.state) {
901
+ return false;
902
+ }
903
+ return this._serializer.applyUnreliablePatches?.(this.clients) ?? false;
904
+ }
905
+ /**
906
+ * Decide how the unreliable channel is driven — and, for the rooms that never
907
+ * touch it, decide to not drive it at all. Runs when the state is assigned
908
+ * (the serializer knows by then whether any `@unreliable` field exists) and
909
+ * whenever {@link unreliablePatchRate} changes.
910
+ *
911
+ * A room whose state declares no `@unreliable` field leaves
912
+ * {@link _flushUnreliable} at {@link NOOP}, so its patch tick costs exactly
913
+ * what it did before this feature existed.
914
+ */
915
+ _armUnreliablePatches() {
916
+ if (this.#_unreliablePatchInterval) {
917
+ clearInterval(this.#_unreliablePatchInterval);
918
+ this.#_unreliablePatchInterval = void 0;
919
+ }
920
+ const armed = this._serializer?.hasUnreliableFields === true;
921
+ const rate = this.#_unreliablePatchRate;
922
+ const dedicated = armed && rate !== null && rate !== 0;
923
+ const inline = armed && !dedicated;
924
+ this._flushUnreliable = inline ? () => {
925
+ this.broadcastUnreliablePatch();
926
+ } : NOOP;
927
+ if (dedicated) {
928
+ this.#_unreliablePatchInterval = setInterval(() => this.broadcastUnreliablePatch(), rate);
929
+ } else if (inline && !this.#_patchRate) {
930
+ import_Logger.logger.warn(
931
+ "@colyseus/core: state has @unreliable fields but patchRate is disabled \u2014 set `room.unreliablePatchRate` to flush them, or they will never update."
932
+ );
933
+ }
934
+ }
837
935
  onMessage(_messageType, _validationSchema, _callback) {
838
936
  return this.#_messages.on(_messageType, _validationSchema, _callback);
839
937
  }
@@ -1093,7 +1191,7 @@ var Room = class _Room {
1093
1191
  * Allow the specified client to reconnect into the room. Must be used inside `onLeave()` method.
1094
1192
  * If seconds is provided, the reconnection is going to be cancelled after the provided amount of seconds.
1095
1193
  *
1096
- * @param client - The client that is allowed to reconnect into the room.
1194
+ * @param previousClient - The client that is allowed to reconnect into the room.
1097
1195
  * @param seconds - The time in seconds that the client is allowed to reconnect into the room.
1098
1196
  *
1099
1197
  * @returns Deferred<Client> - The differed is a promise like type.
@@ -1300,6 +1398,10 @@ var Room = class _Room {
1300
1398
  clearInterval(this.#_patchInterval);
1301
1399
  this.#_patchInterval = void 0;
1302
1400
  }
1401
+ if (this.#_unreliablePatchInterval) {
1402
+ clearInterval(this.#_unreliablePatchInterval);
1403
+ this.#_unreliablePatchInterval = void 0;
1404
+ }
1303
1405
  if (this._simulationInterval) {
1304
1406
  clearInterval(this._simulationInterval);
1305
1407
  this._simulationInterval = void 0;
@@ -1360,7 +1462,12 @@ var Room = class _Room {
1360
1462
  #_forciblyCloseClient(client, closeCode, reason) {
1361
1463
  client.ref.removeAllListeners("message");
1362
1464
  client.ref.removeListener("close", client.ref["onleave"]);
1363
- this._onLeave(client, closeCode).then(() => client.leave(closeCode, reason));
1465
+ const ref = client.ref;
1466
+ this._onLeave(client, closeCode).then(() => {
1467
+ if (client.ref === ref) {
1468
+ client.leave(closeCode, reason);
1469
+ }
1470
+ });
1364
1471
  }
1365
1472
  async _onLeave(client, code) {
1366
1473
  const method = code === import_shared_types.CloseCode.CONSENTED || client.state === import_Transport.ClientState.RECONNECTING ? this.onLeave : this.onDrop || this.onLeave;
@@ -1381,11 +1488,14 @@ var Room = class _Room {
1381
1488
  this.#_onLeaveConcurrent--;
1382
1489
  }
1383
1490
  }
1491
+ if (client.state === import_Transport.ClientState.RECONNECTED) {
1492
+ return;
1493
+ }
1384
1494
  if (this._reconnections[client.reconnectionToken]) {
1385
1495
  this._reconnections[client.reconnectionToken][1].catch(async () => {
1386
1496
  await this.#_onAfterLeave(client, code, method === this.onDrop);
1387
1497
  });
1388
- } else if (client.state !== import_Transport.ClientState.RECONNECTED) {
1498
+ } else {
1389
1499
  await this.#_onAfterLeave(client, code, method === this.onDrop);
1390
1500
  }
1391
1501
  }