@colyseus/core 0.18.0 → 0.18.1

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 (125) hide show
  1. package/build/MatchMaker.cjs +3 -7
  2. package/build/MatchMaker.cjs.map +2 -2
  3. package/build/MatchMaker.mjs +4 -8
  4. package/build/MatchMaker.mjs.map +2 -2
  5. package/build/Protocol.cjs +3 -3
  6. package/build/Protocol.cjs.map +1 -1
  7. package/build/Protocol.d.ts +3 -3
  8. package/build/Protocol.mjs +3 -3
  9. package/build/Protocol.mjs.map +1 -1
  10. package/build/Rewind.cjs +385 -0
  11. package/build/Rewind.cjs.map +7 -0
  12. package/build/Rewind.d.ts +291 -0
  13. package/build/Rewind.mjs +359 -0
  14. package/build/Rewind.mjs.map +7 -0
  15. package/build/Room.cjs +280 -281
  16. package/build/Room.cjs.map +3 -3
  17. package/build/Room.d.ts +185 -81
  18. package/build/Room.mjs +286 -286
  19. package/build/Room.mjs.map +2 -2
  20. package/build/RoomMessages.cjs +265 -0
  21. package/build/RoomMessages.cjs.map +7 -0
  22. package/build/RoomMessages.d.ts +49 -0
  23. package/build/RoomMessages.mjs +240 -0
  24. package/build/RoomMessages.mjs.map +7 -0
  25. package/build/Server.cjs +88 -31
  26. package/build/Server.cjs.map +2 -2
  27. package/build/Server.d.ts +36 -0
  28. package/build/Server.mjs +88 -31
  29. package/build/Server.mjs.map +2 -2
  30. package/build/Transport.cjs +26 -0
  31. package/build/Transport.cjs.map +2 -2
  32. package/build/Transport.d.ts +69 -2
  33. package/build/Transport.mjs +25 -0
  34. package/build/Transport.mjs.map +2 -2
  35. package/build/errors/RoomExceptions.cjs +7 -4
  36. package/build/errors/RoomExceptions.cjs.map +2 -2
  37. package/build/errors/RoomExceptions.d.ts +15 -3
  38. package/build/errors/RoomExceptions.mjs +5 -3
  39. package/build/errors/RoomExceptions.mjs.map +2 -2
  40. package/build/index.cjs +19 -2
  41. package/build/index.cjs.map +2 -2
  42. package/build/index.d.ts +7 -4
  43. package/build/index.mjs +17 -4
  44. package/build/index.mjs.map +2 -2
  45. package/build/input/InputBuffer.cjs +439 -16
  46. package/build/input/InputBuffer.cjs.map +2 -2
  47. package/build/input/InputBuffer.d.ts +186 -96
  48. package/build/input/InputBuffer.mjs +436 -15
  49. package/build/input/InputBuffer.mjs.map +2 -2
  50. package/build/input/RoomInput.cjs +306 -0
  51. package/build/input/RoomInput.cjs.map +7 -0
  52. package/build/input/RoomInput.d.ts +91 -0
  53. package/build/input/RoomInput.mjs +287 -0
  54. package/build/input/RoomInput.mjs.map +7 -0
  55. package/build/input/types.cjs +18 -0
  56. package/build/input/types.cjs.map +7 -0
  57. package/build/input/types.d.ts +476 -0
  58. package/build/input/types.mjs +0 -0
  59. package/build/input/types.mjs.map +7 -0
  60. package/build/rooms/QueueRoom.cjs +1 -1
  61. package/build/rooms/QueueRoom.cjs.map +2 -2
  62. package/build/rooms/QueueRoom.mjs +1 -1
  63. package/build/rooms/QueueRoom.mjs.map +2 -2
  64. package/build/router/default_routes.cjs +4 -1
  65. package/build/router/default_routes.cjs.map +2 -2
  66. package/build/router/default_routes.mjs +4 -1
  67. package/build/router/default_routes.mjs.map +2 -2
  68. package/build/router/index.cjs +6 -1
  69. package/build/router/index.cjs.map +2 -2
  70. package/build/router/index.mjs +6 -1
  71. package/build/router/index.mjs.map +2 -2
  72. package/build/router/node.cjs +37 -2
  73. package/build/router/node.cjs.map +2 -2
  74. package/build/router/node.d.ts +10 -0
  75. package/build/router/node.mjs +35 -1
  76. package/build/router/node.mjs.map +2 -2
  77. package/build/serializer/NoneSerializer.cjs +2 -2
  78. package/build/serializer/NoneSerializer.cjs.map +2 -2
  79. package/build/serializer/NoneSerializer.d.ts +3 -3
  80. package/build/serializer/NoneSerializer.mjs +2 -2
  81. package/build/serializer/NoneSerializer.mjs.map +2 -2
  82. package/build/serializer/SchemaSerializer.cjs +44 -14
  83. package/build/serializer/SchemaSerializer.cjs.map +2 -2
  84. package/build/serializer/SchemaSerializer.d.ts +3 -3
  85. package/build/serializer/SchemaSerializer.mjs +46 -16
  86. package/build/serializer/SchemaSerializer.mjs.map +2 -2
  87. package/build/serializer/Serializer.cjs.map +1 -1
  88. package/build/serializer/Serializer.d.ts +12 -2
  89. package/build/utils/DevMode.cjs +14 -14
  90. package/build/utils/DevMode.cjs.map +2 -2
  91. package/build/utils/DevMode.d.ts +0 -2
  92. package/build/utils/DevMode.mjs +14 -12
  93. package/build/utils/DevMode.mjs.map +2 -2
  94. package/build/utils/Env.cjs +8 -4
  95. package/build/utils/Env.cjs.map +3 -3
  96. package/build/utils/Env.mjs +8 -4
  97. package/build/utils/Env.mjs.map +2 -2
  98. package/build/utils/Utils.cjs +3 -0
  99. package/build/utils/Utils.cjs.map +2 -2
  100. package/build/utils/Utils.d.ts +8 -0
  101. package/build/utils/Utils.mjs +2 -0
  102. package/build/utils/Utils.mjs.map +2 -2
  103. package/package.json +11 -11
  104. package/src/MatchMaker.ts +7 -9
  105. package/src/Protocol.ts +3 -3
  106. package/src/Rewind.ts +572 -0
  107. package/src/Room.ts +409 -448
  108. package/src/RoomMessages.ts +342 -0
  109. package/src/Server.ts +112 -38
  110. package/src/Transport.ts +97 -2
  111. package/src/errors/RoomExceptions.ts +18 -4
  112. package/src/index.ts +13 -2
  113. package/src/input/InputBuffer.ts +464 -107
  114. package/src/input/RoomInput.ts +337 -0
  115. package/src/input/types.ts +503 -0
  116. package/src/rooms/QueueRoom.ts +1 -1
  117. package/src/router/default_routes.ts +6 -1
  118. package/src/router/index.ts +6 -1
  119. package/src/router/node.ts +44 -0
  120. package/src/serializer/NoneSerializer.ts +3 -3
  121. package/src/serializer/SchemaSerializer.ts +110 -19
  122. package/src/serializer/Serializer.ts +13 -2
  123. package/src/utils/DevMode.ts +18 -13
  124. package/src/utils/Env.ts +12 -4
  125. package/src/utils/Utils.ts +9 -0
@@ -0,0 +1,306 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/core/src/input/RoomInput.ts
21
+ var RoomInput_exports = {};
22
+ __export(RoomInput_exports, {
23
+ RoomInput: () => RoomInput
24
+ });
25
+ module.exports = __toCommonJS(RoomInput_exports);
26
+ var import_schema = require("@colyseus/schema");
27
+ var import_input = require("@colyseus/schema/input");
28
+ var import_shared_types = require("@colyseus/shared-types");
29
+ var import_InputBuffer = require("./InputBuffer.cjs");
30
+ var import_Debug = require("../Debug.cjs");
31
+ var _inputReflectionCache = /* @__PURE__ */ new WeakMap();
32
+ var InputAPIImpl = class {
33
+ constructor(input) {
34
+ this.input = input;
35
+ }
36
+ /** Registry, not room.clients: an accessor outlives its client through the
37
+ * reconnection window, so a dropped seat still synthesizes the idle policy. */
38
+ get(sessionId) {
39
+ return this.input.accessors.get(sessionId) ?? import_InputBuffer.NO_OP_INPUT_ACCESSOR;
40
+ }
41
+ // Live reads off `options` (mutated in place by a later setTimestep/
42
+ // setFixedTimestep back-fill, so a derived tickRate is reflected); 1/hz is
43
+ // correctly-rounded IEEE-754 → bit-identical to the client's stepSeconds.
44
+ get tickRate() {
45
+ return this.input.options.tickRate;
46
+ }
47
+ get stepSeconds() {
48
+ const hz = this.input.options.tickRate;
49
+ return hz ? 1 / hz : void 0;
50
+ }
51
+ get stepMs() {
52
+ const hz = this.input.options.tickRate;
53
+ return hz ? 1e3 / hz : void 0;
54
+ }
55
+ // Sub-step trio: same derivation as the client handle ((1/hz)/n) — bit-identical dt.
56
+ get subSteps() {
57
+ return this.input.options.subSteps ?? 1;
58
+ }
59
+ get subStepSeconds() {
60
+ const hz = this.input.options.tickRate;
61
+ return hz ? 1 / hz / (this.input.options.subSteps ?? 1) : void 0;
62
+ }
63
+ get subStepMs() {
64
+ const hz = this.input.options.tickRate;
65
+ return hz ? 1e3 / hz / (this.input.options.subSteps ?? 1) : void 0;
66
+ }
67
+ };
68
+ var RoomInput = class {
69
+ constructor(room) {
70
+ /** sessionId → accessor. Decoupled from `this.clients`: an entry outlives its
71
+ * client across the reconnection window, so {@link InputAPI.get} keeps
72
+ * synthesizing the idle policy for an absent seat (its buffer was cleared on
73
+ * leave → idle). Set on join, deleted on full leave. Read by
74
+ * {@link InputAPIImpl.get} (hence not `private`). */
75
+ this.accessors = /* @__PURE__ */ new Map();
76
+ // Wire stamp mode derived from the rewind timeline, resolved once on first
77
+ // handshake/decode then frozen so advertise + decode never disagree mid-session:
78
+ // the renderTime/reckonTime prefix per input.
79
+ this.#stampRender = false;
80
+ this.#stampReckon = false;
81
+ this.#stampResolved = false;
82
+ this.room = room;
83
+ this.nowOf = () => this.room.clock.elapsedTime;
84
+ }
85
+ #stampRender;
86
+ #stampReckon;
87
+ #stampResolved;
88
+ /**
89
+ * Build the input configuration + `InputAPI` (the body of
90
+ * {@link Room.defineInput}). Returns the api; the Room hands it back to
91
+ * userland and keeps the framework-owned reference.
92
+ */
93
+ define(type, opts) {
94
+ const tickRate = opts?.stepSeconds !== void 0 ? 1 / opts.stepSeconds : opts?.stepMs !== void 0 ? 1e3 / opts.stepMs : opts?.tickRate;
95
+ if (opts?.tickRate !== void 0 && opts.stepMs === void 0 && opts.stepSeconds === void 0 && (!Number.isInteger(opts.tickRate) || opts.tickRate > 240)) {
96
+ console.warn(
97
+ `[defineInput] tickRate is a rate in Hz (got ${opts.tickRate}); a value like 1000/rate is a step interval in ms \u2014 pass { stepMs } instead.`
98
+ );
99
+ }
100
+ this.options = {
101
+ ctor: type,
102
+ // Opt-in: a default would silently drop frames for any app with a numeric `seq` field.
103
+ seqField: opts?.seqField,
104
+ bufferMaxSize: opts?.bufferMaxSize ?? 32,
105
+ idle: opts?.idle,
106
+ // Compiled once (map → dense min/max walk); applied per decoded frame.
107
+ sanitize: opts?.sanitize !== void 0 ? (0, import_InputBuffer.compileSanitizer)(opts.sanitize) : void 0,
108
+ tickRate,
109
+ subSteps: (0, import_InputBuffer.validateSubSteps)(opts?.subSteps, "defineInput")
110
+ };
111
+ if (!_inputReflectionCache.has(type)) {
112
+ _inputReflectionCache.set(type, import_schema.Reflection.encode(new import_schema.Encoder(new type())));
113
+ }
114
+ const api = new InputAPIImpl(this);
115
+ this.api = api;
116
+ return api;
117
+ }
118
+ // --- per-client lifecycle (called from Room._onJoin/_onLeave/etc.) ---
119
+ /** Allocate the per-client input instance + decoder, the ring buffer (opt-in
120
+ * via `bufferMaxSize > 0`, for rollback/lockstep), and the accessor. */
121
+ allocate(client) {
122
+ client._input = new this.options.ctor();
123
+ client._inputDecoder = new import_input.InputDecoder(client._input);
124
+ client._reckonBaseline = 0;
125
+ const maxSize = this.options.bufferMaxSize;
126
+ if (maxSize > 0) {
127
+ client._inputBuffer = new import_InputBuffer.InputBufferImpl(maxSize, this.options.seqField, this.options.ctor, client, this.options.idle);
128
+ }
129
+ client._inputAccessor = new import_InputBuffer.InputAccessorImpl(client, this.nowOf);
130
+ }
131
+ /** @internal Raw reckon stamp for {@link Room.allowRewindState}'s
132
+ * `bindReckonTime` — bypasses the accessor's resolved getter so the rewind
133
+ * midpoint fallback still engages for unstamped clients. instanceof-narrowed:
134
+ * the registry only ever holds `InputAccessorImpl` (see {@link allocate}),
135
+ * so the 0 fallback covers only a missing session. */
136
+ rawReckonTime(sessionId) {
137
+ const acc = this.accessors.get(sessionId);
138
+ return acc instanceof import_InputBuffer.InputAccessorImpl ? acc.rawReckonTime : 0;
139
+ }
140
+ /** Register a (re)joined client's accessor. On reconnect this overwrites the
141
+ * dropped session's stale entry. Called after the client is in `this.clients`
142
+ * (so a pre-push failure can't leak it) and before onJoin (so `get()` resolves
143
+ * there). */
144
+ register(sessionId, client) {
145
+ this.accessors.set(sessionId, client._inputAccessor);
146
+ }
147
+ /** Freeze a leaving seat: drop pending inputs so a held (reconnecting) session
148
+ * idles from the first tick rather than replaying last-known moves. `_input`
149
+ * (the idle ctx's `latest`) is left intact. */
150
+ freeze(client) {
151
+ client._inputBuffer?.clear();
152
+ }
153
+ /** Drop a fully-gone session's accessor (delete of a missing key is a no-op). */
154
+ release(sessionId) {
155
+ this.accessors.delete(sessionId);
156
+ }
157
+ /** Release every held accessor (room dispose). */
158
+ dispose() {
159
+ this.accessors.clear();
160
+ }
161
+ // --- encode / decode (called from Room._onMessage) ---
162
+ /**
163
+ * Sanitize the freshly-decoded `client._input`, then (when buffering is on)
164
+ * push a clone into the per-client buffer. Honors the framework seq
165
+ * (unreliable) / a user `inputOptions.seqField` (reliable) to dedupe the
166
+ * redundancy ring.
167
+ */
168
+ capture(client, renderTime = 0, reckonTime = 0, seq) {
169
+ this.options.sanitize?.(client._input);
170
+ const buf = client._inputBuffer;
171
+ if (!buf) {
172
+ return;
173
+ }
174
+ const inst = client._input;
175
+ if (seq !== void 0) {
176
+ if (!buf.accept(seq)) {
177
+ return;
178
+ }
179
+ } else {
180
+ const seqField = this.options.seqField;
181
+ if (seqField !== void 0) {
182
+ const value = inst[seqField];
183
+ if (typeof value === "number" && !buf.accept(value)) {
184
+ return;
185
+ }
186
+ }
187
+ }
188
+ buf.push(inst.clone(), renderTime, reckonTime, seq);
189
+ }
190
+ /** Decode a `ROOM_INPUT_RELIABLE` frame: an optional TIMED stamp prefix (shape
191
+ * set by this room's derived stamp mode) then the input body. `it` starts at
192
+ * offset 1, so the body begins at `it.offset`. */
193
+ decodeReliable(client, buffer, it, modifiers) {
194
+ if (!client._inputDecoder) {
195
+ return;
196
+ }
197
+ let renderTime = 0;
198
+ let reckonTime = 0;
199
+ if (modifiers & import_shared_types.ProtocolModifier.TIMED) {
200
+ this.#resolveWireModes();
201
+ const stamp = client._reckonBaseline += import_schema.decode.number(buffer, it);
202
+ if (this.#stampReckon && this.#stampRender) {
203
+ reckonTime = stamp;
204
+ const renderDelta = import_schema.decode.uint16(buffer, it);
205
+ renderTime = stamp > renderDelta ? stamp - renderDelta : 0;
206
+ } else if (this.#stampReckon) {
207
+ reckonTime = stamp;
208
+ } else {
209
+ renderTime = stamp;
210
+ }
211
+ }
212
+ try {
213
+ client._inputDecoder.decode(buffer.subarray(it.offset, buffer.byteLength));
214
+ } catch (e) {
215
+ (0, import_Debug.debugAndPrintError)(e);
216
+ return;
217
+ }
218
+ client._lastInputReceivedAt = performance.now();
219
+ client._receivedInputCount = (client._receivedInputCount ?? 0) + 1;
220
+ this.capture(client, renderTime, reckonTime);
221
+ }
222
+ /** Decode a `ROOM_INPUT_UNRELIABLE` redundancy ring — each slot carries its
223
+ * framework seq (base seq + position) for ring dedupe, no user seqField. */
224
+ decodeUnreliable(client, buffer, _modifiers) {
225
+ if (!client._inputDecoder) {
226
+ return;
227
+ }
228
+ try {
229
+ client._inputDecoder.decodeAll(buffer.subarray(1), (_inst, seq) => this.capture(client, 0, 0, seq));
230
+ } catch (e) {
231
+ (0, import_Debug.debugAndPrintError)(e);
232
+ return;
233
+ }
234
+ client._lastInputReceivedAt = performance.now();
235
+ }
236
+ // --- handshake + stamp mode ---
237
+ /** Resolve the wire stamp mode from the rewind timeline (once, then frozen). */
238
+ #resolveWireModes() {
239
+ if (this.#stampResolved) return;
240
+ this.#stampResolved = true;
241
+ const tl = this.room._timelineMode();
242
+ this.#stampRender = tl?.snapshot ?? false;
243
+ this.#stampReckon = tl?.reckon ?? false;
244
+ }
245
+ /**
246
+ * The join-handshake input sections: INPUT_REFLECTION (the SDK-deserializable
247
+ * input ctor bytes) and, when any runtime config differs from defaults,
248
+ * INPUT_OPTIONS (`[flags uint8][tickRate varint?][patchRate varint?][subSteps
249
+ * varint?]`). The client mirrors RENDER_TIME/RECKON_TIME (auto-stamp timeline),
250
+ * tickRate (predict at dt=1/tickRate), patchRate (reconcile cadence), and
251
+ * subSteps (physics sub-steps per input, omitted when 1). Returns `undefined`
252
+ * when there's nothing to add.
253
+ */
254
+ handshakeSections() {
255
+ let sections;
256
+ const inputBytes = _inputReflectionCache.get(this.options.ctor);
257
+ if (inputBytes !== void 0) {
258
+ sections = [{ tag: import_shared_types.HandshakeSection.INPUT_REFLECTION, bytes: inputBytes }];
259
+ }
260
+ this.#resolveWireModes();
261
+ const stampRender = this.#stampRender;
262
+ const stampReckon = this.#stampReckon;
263
+ const tickRate = this.options.tickRate;
264
+ const patchRate = typeof this.room.patchRate === "number" && this.room.patchRate > 0 ? Math.round(this.room.patchRate) : void 0;
265
+ const subSteps = this.options.subSteps !== void 0 && this.options.subSteps > 1 ? this.options.subSteps : void 0;
266
+ if (stampRender || stampReckon || tickRate || patchRate || subSteps) {
267
+ let flags = 0;
268
+ if (stampRender) {
269
+ flags |= import_shared_types.InputFlags.RENDER_TIME;
270
+ }
271
+ if (stampReckon) {
272
+ flags |= import_shared_types.InputFlags.RECKON_TIME;
273
+ }
274
+ if (tickRate) {
275
+ flags |= import_shared_types.InputFlags.FIXED_TIMESTEP;
276
+ }
277
+ if (patchRate) {
278
+ flags |= import_shared_types.InputFlags.PATCH_RATE;
279
+ }
280
+ if (subSteps) {
281
+ flags |= import_shared_types.InputFlags.SUB_STEPS;
282
+ }
283
+ const buf = new Uint8Array(24);
284
+ const sit = { offset: 0 };
285
+ buf[sit.offset++] = flags;
286
+ if (tickRate) {
287
+ import_schema.encode.number(buf, tickRate, sit);
288
+ }
289
+ if (patchRate) {
290
+ import_schema.encode.number(buf, patchRate, sit);
291
+ }
292
+ if (subSteps) {
293
+ import_schema.encode.number(buf, subSteps, sit);
294
+ }
295
+ (sections ??= []).push({
296
+ tag: import_shared_types.HandshakeSection.INPUT_OPTIONS,
297
+ bytes: buf.subarray(0, sit.offset)
298
+ });
299
+ }
300
+ return sections;
301
+ }
302
+ };
303
+ // Annotate the CommonJS export names for ESM import in node:
304
+ 0 && (module.exports = {
305
+ RoomInput
306
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/input/RoomInput.ts"],
4
+ "sourcesContent": ["import { decode, encode, Encoder, Reflection, type Iterator } from '@colyseus/schema';\nimport { InputDecoder } from '@colyseus/schema/input';\nimport { HandshakeSection, InputFlags, ProtocolModifier } from '@colyseus/shared-types';\n\nimport {\n InputAccessorImpl, InputBufferImpl, NO_OP_INPUT_ACCESSOR,\n compileSanitizer, validateSubSteps,\n} from './InputBuffer.ts';\nimport type {\n InputAccessor, InputAPI, NormalizedInputOptions,\n DefineInputOptions, IdleDeclared,\n} from './types.ts';\nimport type { Client, ClientPrivate } from '../Transport.ts';\nimport type { Room } from '../Room.ts';\nimport { debugAndPrintError } from '../Debug.ts';\n\n/**\n * Module-level cache of `Reflection.encode` output keyed by input\n * constructor \u2014 pays the encoding cost once per Room class regardless of\n * room instance count. WeakMap so unused classes can be GC'd.\n */\nconst _inputReflectionCache = new WeakMap<Function, Uint8Array>();\n\n/**\n * Runtime behind {@link InputAPI}. A class, not a per-`define()` object literal:\n * literal (and `defineProperty`) accessors carry their closure identity in the\n * hidden class, so every room instance would get a UNIQUE map \u2014 sending shared\n * `this.inputs.*` call sites megamorphic. Prototype getters are created once,\n * every instance shares one hidden class (reads stay monomorphic), and\n * `define()` allocates a single 1-field object instead of 7 closures + a map\n * lineage per room.\n *\n * @internal\n */\nclass InputAPIImpl {\n private input: RoomInput;\n constructor(input: RoomInput) { this.input = input; }\n /** Registry, not room.clients: an accessor outlives its client through the\n * reconnection window, so a dropped seat still synthesizes the idle policy. */\n get(sessionId: string): InputAccessor<any> {\n return this.input.accessors.get(sessionId) ?? NO_OP_INPUT_ACCESSOR;\n }\n // Live reads off `options` (mutated in place by a later setTimestep/\n // setFixedTimestep back-fill, so a derived tickRate is reflected); 1/hz is\n // correctly-rounded IEEE-754 \u2192 bit-identical to the client's stepSeconds.\n get tickRate(): number | undefined { return this.input.options.tickRate; }\n get stepSeconds(): number | undefined { const hz = this.input.options.tickRate; return hz ? 1 / hz : undefined; }\n get stepMs(): number | undefined { const hz = this.input.options.tickRate; return hz ? 1000 / hz : undefined; }\n // Sub-step trio: same derivation as the client handle ((1/hz)/n) \u2014 bit-identical dt.\n get subSteps(): number { return this.input.options.subSteps ?? 1; }\n get subStepSeconds(): number | undefined { const hz = this.input.options.tickRate; return hz ? (1 / hz) / (this.input.options.subSteps ?? 1) : undefined; }\n get subStepMs(): number | undefined { const hz = this.input.options.tickRate; return hz ? (1000 / hz) / (this.input.options.subSteps ?? 1) : undefined; }\n}\n\n/**\n * Per-room input subsystem, owned by {@link Room} and created lazily on the\n * first {@link Room.defineInput} call \u2014 rooms without inputs allocate none of\n * it. Owns the input options, the per-session accessor registry (decoupled\n * from `this.clients` so an entry outlives a dropped client across its\n * reconnection window), the wire stamp mode, and the encode/decode/handshake\n * machinery. Reads back into its Room for context it doesn't own (the patch\n * rate and the rewind timeline mode).\n *\n * @internal\n */\nexport class RoomInput {\n /** Owning room \u2014 for `patchRate` and the rewind timeline mode. */\n private room: Room<any>;\n\n /** Input configuration (ctor, seqField, bufferMaxSize, idle, sanitize,\n * tickRate, subSteps). `tickRate`/`subSteps` may be back-filled by\n * `setTimestep`/`setFixedTimestep`. Set in {@link define}. */\n options!: NormalizedInputOptions;\n\n /** The `InputAPI` returned to userland from `defineInput`, also the\n * framework-owned handle the rewind binding resolves accessors through. */\n api!: InputAPI<any>;\n\n /** sessionId \u2192 accessor. Decoupled from `this.clients`: an entry outlives its\n * client across the reconnection window, so {@link InputAPI.get} keeps\n * synthesizing the idle policy for an absent seat (its buffer was cleared on\n * leave \u2192 idle). Set on join, deleted on full leave. Read by\n * {@link InputAPIImpl.get} (hence not `private`). */\n readonly accessors: Map<string, InputAccessor<any>> = new Map();\n\n // Wire stamp mode derived from the rewind timeline, resolved once on first\n // handshake/decode then frozen so advertise + decode never disagree mid-session:\n // the renderTime/reckonTime prefix per input.\n #stampRender = false;\n #stampReckon = false;\n #stampResolved = false;\n\n /** One shared now-resolver handed to every accessor (see {@link InputAccessorImpl}). */\n private nowOf: () => number;\n\n constructor(room: Room<any>) {\n this.room = room;\n this.nowOf = () => this.room.clock.elapsedTime;\n }\n\n /**\n * Build the input configuration + `InputAPI` (the body of\n * {@link Room.defineInput}). Returns the api; the Room hands it back to\n * userland and keeps the framework-owned reference.\n */\n define<\n C extends new () => any,\n O extends DefineInputOptions<InstanceType<C>> = DefineInputOptions<InstanceType<C>>,\n >(\n type: C,\n opts?: O,\n ): InputAPI<InstanceType<C>, IdleDeclared<O, InstanceType<C>>> {\n // Normalize the step declaration to the canonical wire form (Hz). stepSeconds\n // / stepMs are the unit-safe spellings; both sides derive dt = 1/tickRate, so\n // one declared number drives the server's physics step AND the client's.\n const tickRate =\n opts?.stepSeconds !== undefined ? 1 / opts.stepSeconds :\n opts?.stepMs !== undefined ? 1000 / opts.stepMs :\n opts?.tickRate;\n if (\n opts?.tickRate !== undefined && opts.stepMs === undefined && opts.stepSeconds === undefined &&\n (!Number.isInteger(opts.tickRate) || opts.tickRate > 240)\n ) {\n console.warn(\n `[defineInput] tickRate is a rate in Hz (got ${opts.tickRate}); a value ` +\n `like 1000/rate is a step interval in ms \u2014 pass { stepMs } instead.`,\n );\n }\n this.options = {\n ctor: type,\n // Opt-in: a default would silently drop frames for any app with a numeric `seq` field.\n seqField: opts?.seqField,\n bufferMaxSize: opts?.bufferMaxSize ?? 32,\n idle: opts?.idle,\n // Compiled once (map \u2192 dense min/max walk); applied per decoded frame.\n sanitize: opts?.sanitize !== undefined ? compileSanitizer(opts.sanitize) : undefined,\n tickRate,\n subSteps: validateSubSteps(opts?.subSteps, 'defineInput'),\n };\n if (!_inputReflectionCache.has(type)) {\n // SDK-deserializable ctor bytes (Reflection.decode rebuilds the ctor client-side).\n _inputReflectionCache.set(type, Reflection.encode(new Encoder(new type())));\n }\n const api = new InputAPIImpl(this) as InputAPI<InstanceType<C>, IdleDeclared<O, InstanceType<C>>>;\n this.api = api;\n return api;\n }\n\n // --- per-client lifecycle (called from Room._onJoin/_onLeave/etc.) ---\n\n /** Allocate the per-client input instance + decoder, the ring buffer (opt-in\n * via `bufferMaxSize > 0`, for rollback/lockstep), and the accessor. */\n allocate(client: Client & ClientPrivate): void {\n client._input = new this.options.ctor();\n client._inputDecoder = new InputDecoder(client._input);\n client._reckonBaseline = 0; // mirrors the SDK's delta-coded stamp baseline (reset together on (re)connect)\n const maxSize = this.options.bufferMaxSize;\n if (maxSize > 0) {\n // ctor \u2192 idle synthesis; client ref \u2192 idle ctx; idle policy \u2192 total drain()/next().\n client._inputBuffer = new InputBufferImpl(maxSize, this.options.seqField, this.options.ctor, client, this.options.idle);\n }\n client._inputAccessor = new InputAccessorImpl(client, this.nowOf);\n }\n\n /** @internal Raw reckon stamp for {@link Room.allowRewindState}'s\n * `bindReckonTime` \u2014 bypasses the accessor's resolved getter so the rewind\n * midpoint fallback still engages for unstamped clients. instanceof-narrowed:\n * the registry only ever holds `InputAccessorImpl` (see {@link allocate}),\n * so the 0 fallback covers only a missing session. */\n rawReckonTime(sessionId: string): number {\n const acc = this.accessors.get(sessionId);\n return acc instanceof InputAccessorImpl ? acc.rawReckonTime : 0;\n }\n\n /** Register a (re)joined client's accessor. On reconnect this overwrites the\n * dropped session's stale entry. Called after the client is in `this.clients`\n * (so a pre-push failure can't leak it) and before onJoin (so `get()` resolves\n * there). */\n register(sessionId: string, client: ClientPrivate): void {\n this.accessors.set(sessionId, client._inputAccessor!);\n }\n\n /** Freeze a leaving seat: drop pending inputs so a held (reconnecting) session\n * idles from the first tick rather than replaying last-known moves. `_input`\n * (the idle ctx's `latest`) is left intact. */\n freeze(client: ClientPrivate): void {\n client._inputBuffer?.clear();\n }\n\n /** Drop a fully-gone session's accessor (delete of a missing key is a no-op). */\n release(sessionId: string): void {\n this.accessors.delete(sessionId);\n }\n\n /** Release every held accessor (room dispose). */\n dispose(): void {\n this.accessors.clear();\n }\n\n // --- encode / decode (called from Room._onMessage) ---\n\n /**\n * Sanitize the freshly-decoded `client._input`, then (when buffering is on)\n * push a clone into the per-client buffer. Honors the framework seq\n * (unreliable) / a user `inputOptions.seqField` (reliable) to dedupe the\n * redundancy ring.\n */\n capture(client: ClientPrivate, renderTime: number = 0, reckonTime: number = 0, seq?: number): void {\n // Sanitize before anything reads it (latest, the clone below, the idle ctx).\n this.options.sanitize?.(client._input);\n const buf = client._inputBuffer;\n if (!buf) { return; } // no consumer registered \u2014 skip the clone allocation\n const inst = client._input!;\n if (seq !== undefined) {\n // Unreliable: dedup the ring by the framework wire seq (user seqField is for .at() only).\n if (!buf.accept(seq)) { return; }\n } else {\n // Reliable: no framework seq (implicit count). Honor a user `seqField` if set.\n const seqField = this.options.seqField;\n if (seqField !== undefined) {\n const value = (inst as any)[seqField] as number;\n if (typeof value === 'number' && !buf.accept(value)) { return; }\n }\n }\n buf.push(inst.clone() as any, renderTime, reckonTime, seq);\n }\n\n /** Decode a `ROOM_INPUT_RELIABLE` frame: an optional TIMED stamp prefix (shape\n * set by this room's derived stamp mode) then the input body. `it` starts at\n * offset 1, so the body begins at `it.offset`. */\n decodeReliable(client: ClientPrivate, buffer: Buffer, it: Iterator, modifiers: number): void {\n if (!client._inputDecoder) { return; }\n // Optional stamp prefix (TIMED bit), DELTA-CODED, length set by this room's\n // stamp mode (the timeline value is reconstructed against the per-client\n // baseline; the wire carries only the signed change from the previous frame):\n // both: [varint \u0394reckon][uint16 renderDelta] \u2192 renderTime = reckon \u2212 renderDelta\n // reckon-only: [varint \u0394reckon]\n // render-only: [varint \u0394render]\n let renderTime = 0;\n let reckonTime = 0;\n if (modifiers & ProtocolModifier.TIMED) {\n this.#resolveWireModes();\n // Reconstruct the absolute timeline value: baseline += signed delta. Both\n // sides start at 0 (so the first delta is absolute) and re-zero together on\n // (re)connect; reliable+in-order keeps the mirror locked.\n const stamp = client._reckonBaseline! += decode.number(buffer, it);\n if (this.#stampReckon && this.#stampRender) {\n reckonTime = stamp;\n const renderDelta = decode.uint16(buffer, it);\n renderTime = stamp > renderDelta ? stamp - renderDelta : 0;\n } else if (this.#stampReckon) {\n reckonTime = stamp;\n } else {\n renderTime = stamp;\n }\n }\n try {\n client._inputDecoder.decode(buffer.subarray(it.offset, buffer.byteLength));\n } catch (e: any) {\n debugAndPrintError(e);\n return;\n }\n client._lastInputReceivedAt = performance.now();\n // Mirrors the SDK's sent count; echoed back as lastInputSeq for RTT.\n client._receivedInputCount = (client._receivedInputCount ?? 0) + 1;\n this.capture(client, renderTime, reckonTime);\n }\n\n /** Decode a `ROOM_INPUT_UNRELIABLE` redundancy ring \u2014 each slot carries its\n * framework seq (base seq + position) for ring dedupe, no user seqField. */\n decodeUnreliable(client: ClientPrivate, buffer: Buffer, _modifiers: number): void {\n if (!client._inputDecoder) { return; }\n try {\n client._inputDecoder.decodeAll(buffer.subarray(1), (_inst, seq) => this.capture(client, 0, 0, seq));\n } catch (e: any) {\n debugAndPrintError(e);\n return;\n }\n client._lastInputReceivedAt = performance.now();\n }\n\n // --- handshake + stamp mode ---\n\n /** Resolve the wire stamp mode from the rewind timeline (once, then frozen). */\n #resolveWireModes(): void {\n if (this.#stampResolved) return;\n this.#stampResolved = true;\n const tl = this.room._timelineMode();\n this.#stampRender = tl?.snapshot ?? false;\n this.#stampReckon = tl?.reckon ?? false;\n }\n\n /**\n * The join-handshake input sections: INPUT_REFLECTION (the SDK-deserializable\n * input ctor bytes) and, when any runtime config differs from defaults,\n * INPUT_OPTIONS (`[flags uint8][tickRate varint?][patchRate varint?][subSteps\n * varint?]`). The client mirrors RENDER_TIME/RECKON_TIME (auto-stamp timeline),\n * tickRate (predict at dt=1/tickRate), patchRate (reconcile cadence), and\n * subSteps (physics sub-steps per input, omitted when 1). Returns `undefined`\n * when there's nothing to add.\n */\n handshakeSections(): Array<{ tag: number; bytes: Uint8Array }> | undefined {\n let sections: Array<{ tag: number; bytes: Uint8Array }> | undefined;\n const inputBytes = _inputReflectionCache.get(this.options.ctor);\n if (inputBytes !== undefined) {\n sections = [{ tag: HandshakeSection.INPUT_REFLECTION, bytes: inputBytes }];\n }\n this.#resolveWireModes();\n const stampRender = this.#stampRender;\n const stampReckon = this.#stampReckon;\n const tickRate = this.options.tickRate;\n const patchRate = (typeof this.room.patchRate === \"number\" && this.room.patchRate > 0)\n ? Math.round(this.room.patchRate) : undefined;\n const subSteps = (this.options.subSteps !== undefined && this.options.subSteps > 1)\n ? this.options.subSteps : undefined;\n if (stampRender || stampReckon || tickRate || patchRate || subSteps) {\n let flags = 0;\n if (stampRender) { flags |= InputFlags.RENDER_TIME; }\n if (stampReckon) { flags |= InputFlags.RECKON_TIME; }\n if (tickRate) { flags |= InputFlags.FIXED_TIMESTEP; }\n if (patchRate) { flags |= InputFlags.PATCH_RATE; }\n if (subSteps) { flags |= InputFlags.SUB_STEPS; }\n // 24B: worst case = flags + float64 tickRate (9) + uint32 patchRate (5) + subSteps (2).\n const buf = new Uint8Array(24);\n const sit = { offset: 0 };\n buf[sit.offset++] = flags;\n if (tickRate) { encode.number(buf, tickRate, sit); }\n if (patchRate) { encode.number(buf, patchRate, sit); }\n if (subSteps) { encode.number(buf, subSteps, sit); }\n (sections ??= []).push({\n tag: HandshakeSection.INPUT_OPTIONS,\n bytes: buf.subarray(0, sit.offset),\n });\n }\n return sections;\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmE;AACnE,mBAA6B;AAC7B,0BAA+D;AAE/D,yBAGO;AAOP,mBAAmC;AAOnC,IAAM,wBAAwB,oBAAI,QAA8B;AAahE,IAAM,eAAN,MAAmB;AAAA,EAEjB,YAAY,OAAkB;AAAE,SAAK,QAAQ;AAAA,EAAO;AAAA;AAAA;AAAA,EAGpD,IAAI,WAAuC;AACzC,WAAO,KAAK,MAAM,UAAU,IAAI,SAAS,KAAK;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,WAA+B;AAAE,WAAO,KAAK,MAAM,QAAQ;AAAA,EAAU;AAAA,EACzE,IAAI,cAAkC;AAAE,UAAM,KAAK,KAAK,MAAM,QAAQ;AAAU,WAAO,KAAK,IAAI,KAAK;AAAA,EAAW;AAAA,EAChH,IAAI,SAA6B;AAAE,UAAM,KAAK,KAAK,MAAM,QAAQ;AAAU,WAAO,KAAK,MAAO,KAAK;AAAA,EAAW;AAAA;AAAA,EAE9G,IAAI,WAAmB;AAAE,WAAO,KAAK,MAAM,QAAQ,YAAY;AAAA,EAAG;AAAA,EAClE,IAAI,iBAAqC;AAAE,UAAM,KAAK,KAAK,MAAM,QAAQ;AAAU,WAAO,KAAM,IAAI,MAAO,KAAK,MAAM,QAAQ,YAAY,KAAK;AAAA,EAAW;AAAA,EAC1J,IAAI,YAAgC;AAAE,UAAM,KAAK,KAAK,MAAM,QAAQ;AAAU,WAAO,KAAM,MAAO,MAAO,KAAK,MAAM,QAAQ,YAAY,KAAK;AAAA,EAAW;AAC1J;AAaO,IAAM,YAAN,MAAgB;AAAA,EA8BrB,YAAY,MAAiB;AAZ7B;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,YAA6C,oBAAI,IAAI;AAK9D;AAAA;AAAA;AAAA,wBAAe;AACf,wBAAe;AACf,0BAAiB;AAMf,SAAK,OAAO;AACZ,SAAK,QAAQ,MAAM,KAAK,KAAK,MAAM;AAAA,EACrC;AAAA,EAVA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,OAIE,MACA,MAC6D;AAI7D,UAAM,WACJ,MAAM,gBAAgB,SAAY,IAAI,KAAK,cAC3C,MAAM,WAAW,SAAY,MAAO,KAAK,SACzC,MAAM;AACR,QACE,MAAM,aAAa,UAAa,KAAK,WAAW,UAAa,KAAK,gBAAgB,WACjF,CAAC,OAAO,UAAU,KAAK,QAAQ,KAAK,KAAK,WAAW,MACrD;AACA,cAAQ;AAAA,QACN,+CAA+C,KAAK,QAAQ;AAAA,MAE9D;AAAA,IACF;AACA,SAAK,UAAU;AAAA,MACb,MAAM;AAAA;AAAA,MAEN,UAAU,MAAM;AAAA,MAChB,eAAe,MAAM,iBAAiB;AAAA,MACtC,MAAM,MAAM;AAAA;AAAA,MAEZ,UAAU,MAAM,aAAa,aAAY,qCAAiB,KAAK,QAAQ,IAAI;AAAA,MAC3E;AAAA,MACA,cAAU,qCAAiB,MAAM,UAAU,aAAa;AAAA,IAC1D;AACA,QAAI,CAAC,sBAAsB,IAAI,IAAI,GAAG;AAEpC,4BAAsB,IAAI,MAAM,yBAAW,OAAO,IAAI,sBAAQ,IAAI,KAAK,CAAC,CAAC,CAAC;AAAA,IAC5E;AACA,UAAM,MAAM,IAAI,aAAa,IAAI;AACjC,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,QAAsC;AAC7C,WAAO,SAAS,IAAI,KAAK,QAAQ,KAAK;AACtC,WAAO,gBAAgB,IAAI,0BAAa,OAAO,MAAM;AACrD,WAAO,kBAAkB;AACzB,UAAM,UAAU,KAAK,QAAQ;AAC7B,QAAI,UAAU,GAAG;AAEf,aAAO,eAAe,IAAI,mCAAgB,SAAS,KAAK,QAAQ,UAAU,KAAK,QAAQ,MAAM,QAAQ,KAAK,QAAQ,IAAI;AAAA,IACxH;AACA,WAAO,iBAAiB,IAAI,qCAAkB,QAAQ,KAAK,KAAK;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAc,WAA2B;AACvC,UAAM,MAAM,KAAK,UAAU,IAAI,SAAS;AACxC,WAAO,eAAe,uCAAoB,IAAI,gBAAgB;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,WAAmB,QAA6B;AACvD,SAAK,UAAU,IAAI,WAAW,OAAO,cAAe;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,QAA6B;AAClC,WAAO,cAAc,MAAM;AAAA,EAC7B;AAAA;AAAA,EAGA,QAAQ,WAAyB;AAC/B,SAAK,UAAU,OAAO,SAAS;AAAA,EACjC;AAAA;AAAA,EAGA,UAAgB;AACd,SAAK,UAAU,MAAM;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,QAAQ,QAAuB,aAAqB,GAAG,aAAqB,GAAG,KAAoB;AAEjG,SAAK,QAAQ,WAAW,OAAO,MAAM;AACrC,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,KAAK;AAAE;AAAA,IAAQ;AACpB,UAAM,OAAO,OAAO;AACpB,QAAI,QAAQ,QAAW;AAErB,UAAI,CAAC,IAAI,OAAO,GAAG,GAAG;AAAE;AAAA,MAAQ;AAAA,IAClC,OAAO;AAEL,YAAM,WAAW,KAAK,QAAQ;AAC9B,UAAI,aAAa,QAAW;AAC1B,cAAM,QAAS,KAAa,QAAQ;AACpC,YAAI,OAAO,UAAU,YAAY,CAAC,IAAI,OAAO,KAAK,GAAG;AAAE;AAAA,QAAQ;AAAA,MACjE;AAAA,IACF;AACA,QAAI,KAAK,KAAK,MAAM,GAAU,YAAY,YAAY,GAAG;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,QAAuB,QAAgB,IAAc,WAAyB;AAC3F,QAAI,CAAC,OAAO,eAAe;AAAE;AAAA,IAAQ;AAOrC,QAAI,aAAa;AACjB,QAAI,aAAa;AACjB,QAAI,YAAY,qCAAiB,OAAO;AACtC,WAAK,kBAAkB;AAIvB,YAAM,QAAQ,OAAO,mBAAoB,qBAAO,OAAO,QAAQ,EAAE;AACjE,UAAI,KAAK,gBAAgB,KAAK,cAAc;AAC1C,qBAAa;AACb,cAAM,cAAc,qBAAO,OAAO,QAAQ,EAAE;AAC5C,qBAAa,QAAQ,cAAc,QAAQ,cAAc;AAAA,MAC3D,WAAW,KAAK,cAAc;AAC5B,qBAAa;AAAA,MACf,OAAO;AACL,qBAAa;AAAA,MACf;AAAA,IACF;AACA,QAAI;AACF,aAAO,cAAc,OAAO,OAAO,SAAS,GAAG,QAAQ,OAAO,UAAU,CAAC;AAAA,IAC3E,SAAS,GAAQ;AACf,2CAAmB,CAAC;AACpB;AAAA,IACF;AACA,WAAO,uBAAuB,YAAY,IAAI;AAE9C,WAAO,uBAAuB,OAAO,uBAAuB,KAAK;AACjE,SAAK,QAAQ,QAAQ,YAAY,UAAU;AAAA,EAC7C;AAAA;AAAA;AAAA,EAIA,iBAAiB,QAAuB,QAAgB,YAA0B;AAChF,QAAI,CAAC,OAAO,eAAe;AAAE;AAAA,IAAQ;AACrC,QAAI;AACF,aAAO,cAAc,UAAU,OAAO,SAAS,CAAC,GAAG,CAAC,OAAO,QAAQ,KAAK,QAAQ,QAAQ,GAAG,GAAG,GAAG,CAAC;AAAA,IACpG,SAAS,GAAQ;AACf,2CAAmB,CAAC;AACpB;AAAA,IACF;AACA,WAAO,uBAAuB,YAAY,IAAI;AAAA,EAChD;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB,QAAI,KAAK,eAAgB;AACzB,SAAK,iBAAiB;AACtB,UAAM,KAAK,KAAK,KAAK,cAAc;AACnC,SAAK,eAAe,IAAI,YAAY;AACpC,SAAK,eAAe,IAAI,UAAU;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,oBAA2E;AACzE,QAAI;AACJ,UAAM,aAAa,sBAAsB,IAAI,KAAK,QAAQ,IAAI;AAC9D,QAAI,eAAe,QAAW;AAC5B,iBAAW,CAAC,EAAE,KAAK,qCAAiB,kBAAkB,OAAO,WAAW,CAAC;AAAA,IAC3E;AACA,SAAK,kBAAkB;AACvB,UAAM,cAAc,KAAK;AACzB,UAAM,cAAc,KAAK;AACzB,UAAM,WAAW,KAAK,QAAQ;AAC9B,UAAM,YAAa,OAAO,KAAK,KAAK,cAAc,YAAY,KAAK,KAAK,YAAY,IAChF,KAAK,MAAM,KAAK,KAAK,SAAS,IAAI;AACtC,UAAM,WAAY,KAAK,QAAQ,aAAa,UAAa,KAAK,QAAQ,WAAW,IAC7E,KAAK,QAAQ,WAAW;AAC5B,QAAI,eAAe,eAAe,YAAY,aAAa,UAAU;AACnE,UAAI,QAAQ;AACZ,UAAI,aAAa;AAAE,iBAAS,+BAAW;AAAA,MAAa;AACpD,UAAI,aAAa;AAAE,iBAAS,+BAAW;AAAA,MAAa;AACpD,UAAI,UAAU;AAAE,iBAAS,+BAAW;AAAA,MAAgB;AACpD,UAAI,WAAW;AAAE,iBAAS,+BAAW;AAAA,MAAY;AACjD,UAAI,UAAU;AAAE,iBAAS,+BAAW;AAAA,MAAW;AAE/C,YAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,YAAM,MAAM,EAAE,QAAQ,EAAE;AACxB,UAAI,IAAI,QAAQ,IAAI;AACpB,UAAI,UAAU;AAAE,6BAAO,OAAO,KAAK,UAAU,GAAG;AAAA,MAAG;AACnD,UAAI,WAAW;AAAE,6BAAO,OAAO,KAAK,WAAW,GAAG;AAAA,MAAG;AACrD,UAAI,UAAU;AAAE,6BAAO,OAAO,KAAK,UAAU,GAAG;AAAA,MAAG;AACnD,OAAC,aAAa,CAAC,GAAG,KAAK;AAAA,QACrB,KAAK,qCAAiB;AAAA,QACtB,OAAO,IAAI,SAAS,GAAG,IAAI,MAAM;AAAA,MACnC,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,91 @@
1
+ import { type Iterator } from '@colyseus/schema';
2
+ import type { InputAccessor, InputAPI, NormalizedInputOptions, DefineInputOptions, IdleDeclared } from './types.ts';
3
+ import type { Client, ClientPrivate } from '../Transport.ts';
4
+ import type { Room } from '../Room.ts';
5
+ /**
6
+ * Per-room input subsystem, owned by {@link Room} and created lazily on the
7
+ * first {@link Room.defineInput} call — rooms without inputs allocate none of
8
+ * it. Owns the input options, the per-session accessor registry (decoupled
9
+ * from `this.clients` so an entry outlives a dropped client across its
10
+ * reconnection window), the wire stamp mode, and the encode/decode/handshake
11
+ * machinery. Reads back into its Room for context it doesn't own (the patch
12
+ * rate and the rewind timeline mode).
13
+ *
14
+ * @internal
15
+ */
16
+ export declare class RoomInput {
17
+ #private;
18
+ /** Owning room — for `patchRate` and the rewind timeline mode. */
19
+ private room;
20
+ /** Input configuration (ctor, seqField, bufferMaxSize, idle, sanitize,
21
+ * tickRate, subSteps). `tickRate`/`subSteps` may be back-filled by
22
+ * `setTimestep`/`setFixedTimestep`. Set in {@link define}. */
23
+ options: NormalizedInputOptions;
24
+ /** The `InputAPI` returned to userland from `defineInput`, also the
25
+ * framework-owned handle the rewind binding resolves accessors through. */
26
+ api: InputAPI<any>;
27
+ /** sessionId → accessor. Decoupled from `this.clients`: an entry outlives its
28
+ * client across the reconnection window, so {@link InputAPI.get} keeps
29
+ * synthesizing the idle policy for an absent seat (its buffer was cleared on
30
+ * leave → idle). Set on join, deleted on full leave. Read by
31
+ * {@link InputAPIImpl.get} (hence not `private`). */
32
+ readonly accessors: Map<string, InputAccessor<any>>;
33
+ /** One shared now-resolver handed to every accessor (see {@link InputAccessorImpl}). */
34
+ private nowOf;
35
+ constructor(room: Room<any>);
36
+ /**
37
+ * Build the input configuration + `InputAPI` (the body of
38
+ * {@link Room.defineInput}). Returns the api; the Room hands it back to
39
+ * userland and keeps the framework-owned reference.
40
+ */
41
+ define<C extends new () => any, O extends DefineInputOptions<InstanceType<C>> = DefineInputOptions<InstanceType<C>>>(type: C, opts?: O): InputAPI<InstanceType<C>, IdleDeclared<O, InstanceType<C>>>;
42
+ /** Allocate the per-client input instance + decoder, the ring buffer (opt-in
43
+ * via `bufferMaxSize > 0`, for rollback/lockstep), and the accessor. */
44
+ allocate(client: Client & ClientPrivate): void;
45
+ /** @internal Raw reckon stamp for {@link Room.allowRewindState}'s
46
+ * `bindReckonTime` — bypasses the accessor's resolved getter so the rewind
47
+ * midpoint fallback still engages for unstamped clients. instanceof-narrowed:
48
+ * the registry only ever holds `InputAccessorImpl` (see {@link allocate}),
49
+ * so the 0 fallback covers only a missing session. */
50
+ rawReckonTime(sessionId: string): number;
51
+ /** Register a (re)joined client's accessor. On reconnect this overwrites the
52
+ * dropped session's stale entry. Called after the client is in `this.clients`
53
+ * (so a pre-push failure can't leak it) and before onJoin (so `get()` resolves
54
+ * there). */
55
+ register(sessionId: string, client: ClientPrivate): void;
56
+ /** Freeze a leaving seat: drop pending inputs so a held (reconnecting) session
57
+ * idles from the first tick rather than replaying last-known moves. `_input`
58
+ * (the idle ctx's `latest`) is left intact. */
59
+ freeze(client: ClientPrivate): void;
60
+ /** Drop a fully-gone session's accessor (delete of a missing key is a no-op). */
61
+ release(sessionId: string): void;
62
+ /** Release every held accessor (room dispose). */
63
+ dispose(): void;
64
+ /**
65
+ * Sanitize the freshly-decoded `client._input`, then (when buffering is on)
66
+ * push a clone into the per-client buffer. Honors the framework seq
67
+ * (unreliable) / a user `inputOptions.seqField` (reliable) to dedupe the
68
+ * redundancy ring.
69
+ */
70
+ capture(client: ClientPrivate, renderTime?: number, reckonTime?: number, seq?: number): void;
71
+ /** Decode a `ROOM_INPUT_RELIABLE` frame: an optional TIMED stamp prefix (shape
72
+ * set by this room's derived stamp mode) then the input body. `it` starts at
73
+ * offset 1, so the body begins at `it.offset`. */
74
+ decodeReliable(client: ClientPrivate, buffer: Buffer, it: Iterator, modifiers: number): void;
75
+ /** Decode a `ROOM_INPUT_UNRELIABLE` redundancy ring — each slot carries its
76
+ * framework seq (base seq + position) for ring dedupe, no user seqField. */
77
+ decodeUnreliable(client: ClientPrivate, buffer: Buffer, _modifiers: number): void;
78
+ /**
79
+ * The join-handshake input sections: INPUT_REFLECTION (the SDK-deserializable
80
+ * input ctor bytes) and, when any runtime config differs from defaults,
81
+ * INPUT_OPTIONS (`[flags uint8][tickRate varint?][patchRate varint?][subSteps
82
+ * varint?]`). The client mirrors RENDER_TIME/RECKON_TIME (auto-stamp timeline),
83
+ * tickRate (predict at dt=1/tickRate), patchRate (reconcile cadence), and
84
+ * subSteps (physics sub-steps per input, omitted when 1). Returns `undefined`
85
+ * when there's nothing to add.
86
+ */
87
+ handshakeSections(): Array<{
88
+ tag: number;
89
+ bytes: Uint8Array;
90
+ }> | undefined;
91
+ }