@woosh/meep-engine 3.14.3 → 3.14.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.
- package/package.json +1 -1
- package/src/core/geom/3d/mat4/m4_rigidity_defect.d.ts +30 -0
- package/src/core/geom/3d/mat4/m4_rigidity_defect.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_rigidity_defect.js +71 -0
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +733 -726
- package/src/engine/network/NetworkSession.d.ts +24 -4
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +28 -4
- package/src/engine/network/orchestrator/NetworkPeer.d.ts +96 -7
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +392 -68
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +6 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +6 -0
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +105 -13
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +306 -59
- package/src/engine/network/replication/Replicator.d.ts +43 -7
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +309 -111
- package/src/engine/network/sim/ActionLog.d.ts +23 -3
- package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
- package/src/engine/network/sim/ActionLog.js +26 -3
- package/src/engine/network/sim/ActionRecordCursor.d.ts +82 -0
- package/src/engine/network/sim/ActionRecordCursor.d.ts.map +1 -0
- package/src/engine/network/sim/ActionRecordCursor.js +120 -0
- package/src/engine/network/sim/RewindEngine.d.ts.map +1 -1
- package/src/engine/network/sim/RewindEngine.js +13 -29
- package/src/engine/network/sim/SimAction.d.ts +15 -0
- package/src/engine/network/sim/SimAction.d.ts.map +1 -1
- package/src/engine/network/sim/SimAction.js +15 -0
- package/src/engine/network/sim/SimActionExecutor.d.ts +51 -2
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +74 -7
- package/src/engine/network/transport/Channel.d.ts +1 -1
- package/src/engine/network/transport/Channel.js +1 -1
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/simulation/Ticker.d.ts.map +1 -1
- package/src/engine/simulation/Ticker.js +4 -1
- package/src/engine/ui/GUIEngine.d.ts.map +1 -1
- package/src/engine/ui/GUIEngine.js +6 -0
- package/src/shade/playground/particle_system/README.md +98 -0
- package/src/shade/playground/particle_system/index.html +124 -0
- package/src/shade/playground/particle_system/main.d.ts +2 -0
- package/src/shade/playground/particle_system/main.d.ts.map +1 -0
- package/src/shade/playground/particle_system/main.js +180 -0
- package/src/shade/playground/particle_system/particle_scene.d.ts +52 -0
- package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -0
- package/src/shade/playground/particle_system/particle_scene.js +553 -0
- package/src/shade/playground/skinned_mesh_soup/README.md +143 -0
- package/src/shade/playground/skinned_mesh_soup/index.html +202 -0
- package/src/shade/playground/skinned_mesh_soup/main.d.ts +7 -0
- package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -0
- package/src/shade/playground/skinned_mesh_soup/main.js +567 -0
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts +29 -0
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -0
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +428 -0
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +1958 -1796
- package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +357 -0
- package/src/shade/renderer/animation/skin_bind_transform.d.ts +25 -0
- package/src/shade/renderer/animation/skin_bind_transform.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_bind_transform.js +33 -0
- package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts +67 -0
- package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_clip_scale_conflicts.js +199 -0
- package/src/shade/renderer/animation/skin_frame_defect.d.ts +34 -0
- package/src/shade/renderer/animation/skin_frame_defect.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_frame_defect.js +132 -0
- package/src/shade/renderer/animation/skin_joint_matrix.d.ts +24 -0
- package/src/shade/renderer/animation/skin_joint_matrix.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_joint_matrix.js +46 -0
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts +70 -0
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.js +216 -0
- package/src/shade/renderer/animation/skin_test_fixtures.d.ts +86 -0
- package/src/shade/renderer/animation/skin_test_fixtures.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_test_fixtures.js +250 -0
- package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts +18 -4
- package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.js +18 -4
- package/src/shade/renderer/particles/DESIGN.md +5 -5
- package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts.map +1 -1
- package/src/shade/renderer/particles/cull/chunk_particle_cull.js +3 -1
- package/src/shade/renderer/particles/data/chunk_particle_emitter.js +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +43 -0
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +44 -0
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +33 -59
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +185 -118
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts +15 -10
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/compile_particle_graph.js +205 -170
- package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts +44 -0
- package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/particle_graph_authoring.js +108 -0
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts +89 -0
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -0
- package/src/shade/renderer/particles/isa/InstructionStream.js +162 -0
- package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts +1 -48
- package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleAssembler.js +25 -114
- package/src/shade/renderer/particles/particle_prototype.d.ts.map +1 -1
- package/src/shade/renderer/particles/particle_prototype.js +181 -180
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +4 -4
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/create_particle_effect.js +19 -19
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.js +4 -2
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +4 -4
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +7 -5
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +3 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +3 -1
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.js +5 -2
- package/src/shade/renderer/particles/shaders/shader_particle_render.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_render.js +9 -2
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +3 -1
- package/src/shade/renderer/particles/vm/chunk_particle_vm.js +1 -1
- package/src/shade/renderer/scene/SkinnedMesh.d.ts +11 -0
- package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +1 -1
- package/src/shade/renderer/scene/SkinnedMesh.js +11 -0
- package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts +33 -3
- package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.js +58 -37
- package/src/shade/renderer/particles/graph/ParticleGraph.d.ts +0 -54
- package/src/shade/renderer/particles/graph/ParticleGraph.d.ts.map +0 -1
- package/src/shade/renderer/particles/graph/ParticleGraph.js +0 -99
- package/src/shade/renderer/particles/prototypeParticleSystem.d.ts +0 -2
- package/src/shade/renderer/particles/prototypeParticleSystem.d.ts.map +0 -1
- package/src/shade/renderer/particles/prototypeParticleSystem.js +0 -448
|
@@ -8,7 +8,9 @@ import { NetworkIdentity } from "../ecs/components/NetworkIdentity.js";
|
|
|
8
8
|
import { make_owner_authorization } from "../ecs/owner_authorization.js";
|
|
9
9
|
import { Replicator } from "../replication/Replicator.js";
|
|
10
10
|
import { AlwaysRelevantScope } from "../replication/ScopeFilter.js";
|
|
11
|
+
import { ActionRecordCursor } from "../sim/ActionRecordCursor.js";
|
|
11
12
|
import { RewindEngine } from "../sim/RewindEngine.js";
|
|
13
|
+
import { SENDER_DERIVED, SENDER_LOCAL } from "../sim/SimActionExecutor.js";
|
|
12
14
|
import { NetworkPeer } from "./NetworkPeer.js";
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -19,23 +21,48 @@ import { NetworkPeer } from "./NetworkPeer.js";
|
|
|
19
21
|
*
|
|
20
22
|
* 1. Inbound action packets do NOT execute on arrival. Instead, a deferral
|
|
21
23
|
* hook on the {@link Replicator} drops them into a per-tick pending log
|
|
22
|
-
* tagged with `(client_frame, sender_id, type_id, payload_bytes)
|
|
24
|
+
* tagged with `(client_frame, sender_id, type_id, payload_bytes)` —
|
|
25
|
+
* unless the action log already holds that record. The action stream
|
|
26
|
+
* re-sends every unconfirmed frame each tick, so most arrivals at any
|
|
27
|
+
* real latency are copies of applied records; those are dropped where
|
|
28
|
+
* they arrive, and pending holds only input the log does not.
|
|
23
29
|
* 2. Once per server tick, `tick(current_frame)` consumes the pending log:
|
|
24
30
|
* - Rejects entries older than the action_log's rewindable window.
|
|
25
|
-
* - Determines the oldest pending frame
|
|
31
|
+
* - Determines `replay_start`: the oldest pending frame, which by the
|
|
32
|
+
* above is the oldest frame whose outcome can change.
|
|
26
33
|
* - Rewinds the server world back to end-of-(replay_start - 1) via the
|
|
27
34
|
* action_log's prior-state captures (see {@link RewindEngine}).
|
|
28
35
|
* - Replays forward `[replay_start, current_frame]`. For each frame `f`:
|
|
29
36
|
* - Read historical actions out of `action_log[f]` BEFORE
|
|
30
37
|
* `begin_frame(f)` recycles the buffer.
|
|
31
38
|
* - Append pending entries for `f`.
|
|
39
|
+
* - Append anything queued by {@link enqueue_action}.
|
|
32
40
|
* - Stable-sort the merged list by `sender_id` (so multi-client order
|
|
33
41
|
* is deterministic across peers — relies on per-record sender_id in
|
|
34
|
-
* the action log).
|
|
35
|
-
* -
|
|
36
|
-
* supplied local sim via {@link onLocalSim}.
|
|
42
|
+
* the action log), and `executor.execute` each in that order.
|
|
43
|
+
* - Run the user-supplied local sim via {@link onLocalSim}.
|
|
37
44
|
* - Clear pending.
|
|
38
45
|
*
|
|
46
|
+
* A frame's records have one of two provenances, and the replay treats them
|
|
47
|
+
* differently:
|
|
48
|
+
*
|
|
49
|
+
* - **Input** — actions that arrived from a peer, and actions the server
|
|
50
|
+
* authored via {@link enqueue_action}. Each happened once, at a point in
|
|
51
|
+
* time nothing can recompute, so a replay reapplies it from the log.
|
|
52
|
+
* - **Derived output** — everything {@link onLocalSim} executes. The handler
|
|
53
|
+
* runs again on every replay of the frame, against a world that now
|
|
54
|
+
* includes whatever late input forced the replay, so the replay recomputes
|
|
55
|
+
* it. Reapplying the previous pass's copy as well would apply the effect
|
|
56
|
+
* twice — and three times on the next replay, and so on, without bound.
|
|
57
|
+
* The executor stamps these {@link SENDER_DERIVED} while the handler runs
|
|
58
|
+
* and {@link __read_historical} drops them.
|
|
59
|
+
*
|
|
60
|
+
* Derived records are still written, and still replicate: the prior-state
|
|
61
|
+
* capture is what lets a rewind undo the local sim's effect on replicated
|
|
62
|
+
* components (so derived output need not be idempotent — only deterministic
|
|
63
|
+
* in the frame's post-input state), and the action stream carries them to
|
|
64
|
+
* clients like any other record.
|
|
65
|
+
*
|
|
39
66
|
* Net effect: a client action tagged at client tick K lands on the server as
|
|
40
67
|
* if applied against end-of-K-1 server state, regardless of arrival timing
|
|
41
68
|
* or order. Both peers compute identical world states for identical inputs.
|
|
@@ -67,6 +94,15 @@ export class ServerAuthoritativeServer {
|
|
|
67
94
|
#historical_scratch = /** @type {Array<{type_id:number, sender_id:number, payload:Uint8Array}>} */ ([]);
|
|
68
95
|
#sort_scratch = /** @type {Array<{sender_id:number, type_id:number, payload:Uint8Array}>} */ ([]);
|
|
69
96
|
#payload_buf;
|
|
97
|
+
// Walks a frame's records, for the history read and the arrival check.
|
|
98
|
+
#cursor = new ActionRecordCursor();
|
|
99
|
+
// Locally-authored actions waiting for the next fresh frame. Parallel
|
|
100
|
+
// arrays, serialized at enqueue time so the caller's instance is not
|
|
101
|
+
// retained (and so a bad action class is rejected at the call site rather
|
|
102
|
+
// than a tick later).
|
|
103
|
+
#local_type_ids = /** @type {number[]} */ ([]);
|
|
104
|
+
#local_payloads = /** @type {Uint8Array[]} */ ([]);
|
|
105
|
+
#local_buf;
|
|
70
106
|
/**
|
|
71
107
|
* Count of inbound pending entries dropped by the future-lead / total
|
|
72
108
|
* bounds. See {@link onPendingActionDropped}.
|
|
@@ -92,8 +128,12 @@ export class ServerAuthoritativeServer {
|
|
|
92
128
|
* frame_capacity?: number,
|
|
93
129
|
* initial_buffer_size?: number,
|
|
94
130
|
* simulation_delay_ticks?: number,
|
|
131
|
+
* max_packets_per_tick?: number,
|
|
95
132
|
* }} options
|
|
96
133
|
*
|
|
134
|
+
* `max_packets_per_tick`: forwarded to {@link NetworkPeer}; how many
|
|
135
|
+
* action-stream packets a tick may send one peer.
|
|
136
|
+
*
|
|
97
137
|
* `simulation_delay_ticks`: server-side input buffer (Overwatch-style).
|
|
98
138
|
* When > 0, {@link tick}(wall_frame) simulates
|
|
99
139
|
* `sim_frame = wall_frame - simulation_delay_ticks`. Pending actions
|
|
@@ -116,6 +156,7 @@ export class ServerAuthoritativeServer {
|
|
|
116
156
|
max_pending_total = 4096,
|
|
117
157
|
identity_class = NetworkIdentity,
|
|
118
158
|
server_peer_id = -1,
|
|
159
|
+
max_packets_per_tick,
|
|
119
160
|
}) {
|
|
120
161
|
assert.isNonNegativeInteger(simulation_delay_ticks, 'simulation_delay_ticks');
|
|
121
162
|
assert.isPositiveInteger(max_pending_future_lead, 'max_pending_future_lead');
|
|
@@ -129,6 +170,7 @@ export class ServerAuthoritativeServer {
|
|
|
129
170
|
scope_filter,
|
|
130
171
|
frame_capacity,
|
|
131
172
|
initial_buffer_size,
|
|
173
|
+
max_packets_per_tick,
|
|
132
174
|
});
|
|
133
175
|
|
|
134
176
|
/** @type {EntityComponentDataset} */
|
|
@@ -180,6 +222,16 @@ export class ServerAuthoritativeServer {
|
|
|
180
222
|
*/
|
|
181
223
|
this.simulation_delay_ticks = simulation_delay_ticks;
|
|
182
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Peer id of this authoritative server, or `-1` when the session has no
|
|
227
|
+
* privileged peer. Actions from {@link enqueue_action} are tagged with
|
|
228
|
+
* it so they pass the owner-authorization gate on any entity (see
|
|
229
|
+
* {@link make_owner_authorization}), which is the documented convention
|
|
230
|
+
* for the server's own mutations.
|
|
231
|
+
* @type {number}
|
|
232
|
+
*/
|
|
233
|
+
this.server_peer_id = server_peer_id;
|
|
234
|
+
|
|
183
235
|
/**
|
|
184
236
|
* Upper bound on how far ahead of the server's own simulation a peer
|
|
185
237
|
* may tag an inbound action. `frame_number` is an attacker-controlled
|
|
@@ -215,6 +267,9 @@ export class ServerAuthoritativeServer {
|
|
|
215
267
|
this.#payload_buf = new BinaryBuffer();
|
|
216
268
|
this.#payload_buf.setCapacity(64);
|
|
217
269
|
|
|
270
|
+
this.#local_buf = new BinaryBuffer();
|
|
271
|
+
this.#local_buf.setCapacity(64);
|
|
272
|
+
|
|
218
273
|
// Switch the Replicator to deferred-execute mode: incoming actions
|
|
219
274
|
// accumulate in pending until tick() drains them.
|
|
220
275
|
this.peer.replicator.on_pending_action = (peer_id, frame_number, type_id, buf, off, len) => {
|
|
@@ -231,13 +286,35 @@ export class ServerAuthoritativeServer {
|
|
|
231
286
|
};
|
|
232
287
|
|
|
233
288
|
/**
|
|
234
|
-
* Fires once per
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
289
|
+
* Fires once per execution of a frame, AFTER all input for that frame
|
|
290
|
+
* has been applied and BEFORE the action_log frame is closed. Use it
|
|
291
|
+
* for server-authoritative local sim: clamps, collision, AI step,
|
|
292
|
+
* damage resolution, spawning the effects a hit produces.
|
|
293
|
+
*
|
|
294
|
+
* **This is a derivation, not an event.** The handler runs again on
|
|
295
|
+
* every replay of the frame, and must produce the same result for the
|
|
296
|
+
* same post-input world state — it is a function OF that state, not a
|
|
297
|
+
* one-shot that happens to be called from it. Concretely:
|
|
298
|
+
*
|
|
299
|
+
* - Decide from world state and the frame number. Both are restored
|
|
300
|
+
* before the handler re-runs.
|
|
301
|
+
* - Do NOT latch on handler-local flags (`if (already_fired) return`)
|
|
302
|
+
* to make something happen once. The replay needs the handler to
|
|
303
|
+
* re-emit; a latch makes it emit nothing, and the action is lost
|
|
304
|
+
* the first time a rollback crosses its frame. For a genuine
|
|
305
|
+
* one-shot — a lobby spawn, an admin command, anything decided
|
|
306
|
+
* outside the simulation — use {@link enqueue_action}, which is
|
|
307
|
+
* recorded as input and replayed rather than recomputed.
|
|
308
|
+
*
|
|
309
|
+
* Actions the handler executes are recorded as derived output: they
|
|
310
|
+
* replicate to clients and their prior state is captured so a rewind
|
|
311
|
+
* undoes them, but a replay recomputes them instead of reapplying the
|
|
312
|
+
* previous pass's copy. So they need not be idempotent — a handler may
|
|
313
|
+
* subtract hit points — only deterministic in the frame's post-input
|
|
314
|
+
* state. Components the handler mutates DIRECTLY, without going through
|
|
315
|
+
* an action, have no prior-state capture and are not undone by a
|
|
316
|
+
* rewind; those must additionally be idempotent, which is why a clamp
|
|
317
|
+
* is safe to write that way and `hp -= 10` is not.
|
|
241
318
|
*
|
|
242
319
|
* Args: `(frame_number)`.
|
|
243
320
|
* @type {Signal}
|
|
@@ -334,6 +411,71 @@ export class ServerAuthoritativeServer {
|
|
|
334
411
|
this.peer.send_time_dilation_feedback(peer_id, this.buffer_depth_for_peer(peer_id));
|
|
335
412
|
}
|
|
336
413
|
|
|
414
|
+
/**
|
|
415
|
+
* Author a server-side action, to be applied on the next simulated frame.
|
|
416
|
+
*
|
|
417
|
+
* This is the supported path for a mutation the simulation cannot
|
|
418
|
+
* recompute — a spawn triggered by a lobby event, an admin command, a
|
|
419
|
+
* scripted trigger — as opposed to {@link onLocalSim}, which derives a
|
|
420
|
+
* frame's output from its state and is re-run on every replay.
|
|
421
|
+
*
|
|
422
|
+
* The action is serialized immediately (so the caller may reuse or discard
|
|
423
|
+
* the instance) and applied exactly once, on the next frame {@link tick}
|
|
424
|
+
* simulates for the first time, merged into that frame's input and ordered
|
|
425
|
+
* with it by sender. From then on it is ordinary history: replayed from the
|
|
426
|
+
* log like any other input, and never re-queued.
|
|
427
|
+
*
|
|
428
|
+
* Callable at any time EXCEPT from inside {@link onLocalSim}, which throws:
|
|
429
|
+
* that handler re-runs on every replay of its frame, so it would queue a
|
|
430
|
+
* fresh copy each time. (`executor.execute` is the opposite — it requires
|
|
431
|
+
* an open action_log frame, so it only works from inside the handler.)
|
|
432
|
+
*
|
|
433
|
+
* Recorded with {@link server_peer_id} as the sender when the session has
|
|
434
|
+
* one, so it passes the owner-authorization gate on any entity; with
|
|
435
|
+
* {@link SENDER_LOCAL} otherwise, which bypasses the gate.
|
|
436
|
+
*
|
|
437
|
+
* @param {SimAction} action
|
|
438
|
+
*/
|
|
439
|
+
enqueue_action(action) {
|
|
440
|
+
assert.ok(action && action.isSimAction, 'enqueue_action: action must be a SimAction');
|
|
441
|
+
// Authoring from inside a derivation is always wrong, and unlike a
|
|
442
|
+
// latched handler it is exactly detectable, so it fails loudly here.
|
|
443
|
+
// onLocalSim runs again on every replay of its frame; each run would
|
|
444
|
+
// queue another copy, and each copy is recorded as input, so the
|
|
445
|
+
// applications compound per replay — the very shape this provenance
|
|
446
|
+
// split exists to stop. A handler that wants an effect every time the
|
|
447
|
+
// frame runs should `executor.execute` it as derived output instead.
|
|
448
|
+
// Real runtime check: asserts strip in prod.
|
|
449
|
+
if (this.executor.deriving) {
|
|
450
|
+
throw new Error(
|
|
451
|
+
'ServerAuthoritativeServer.enqueue_action: cannot author an action from inside onLocalSim — the handler re-runs on every replay, so the action would be queued again each time. Execute it through the executor to record it as derived output, or enqueue it from outside the local sim.',
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
const type_id = action.constructor.type_id;
|
|
455
|
+
assert.ok(
|
|
456
|
+
type_id >= 0,
|
|
457
|
+
`enqueue_action: action class '${action.constructor.action_type_name ?? action.constructor.name}' has no wire type_id — register it before enqueueing it`,
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
this.#local_buf.position = 0;
|
|
461
|
+
action.serialize(this.#local_buf);
|
|
462
|
+
const len = this.#local_buf.position;
|
|
463
|
+
|
|
464
|
+
const payload = new Uint8Array(len);
|
|
465
|
+
payload.set(this.#local_buf.raw_bytes.subarray(0, len));
|
|
466
|
+
|
|
467
|
+
this.#local_type_ids.push(type_id);
|
|
468
|
+
this.#local_payloads.push(payload);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Number of locally-authored actions waiting for the next simulated frame.
|
|
473
|
+
* @returns {number}
|
|
474
|
+
*/
|
|
475
|
+
queued_local_action_count() {
|
|
476
|
+
return this.#local_type_ids.length;
|
|
477
|
+
}
|
|
478
|
+
|
|
337
479
|
/**
|
|
338
480
|
* Drive the rollback flow for one tick.
|
|
339
481
|
*
|
|
@@ -360,8 +502,13 @@ export class ServerAuthoritativeServer {
|
|
|
360
502
|
this.#pending_trim_to_window(window_oldest);
|
|
361
503
|
}
|
|
362
504
|
|
|
363
|
-
// 2. Pick the replay window
|
|
364
|
-
//
|
|
505
|
+
// 2. Pick the replay window: the OLDEST pending frame at or below
|
|
506
|
+
// `sim_frame`. Pending holds only input the log does not already
|
|
507
|
+
// hold — a retransmission of an applied record is dropped on
|
|
508
|
+
// arrival, see __pending_add — so the oldest pending frame is the
|
|
509
|
+
// oldest frame whose outcome can change, and a rewind to it is
|
|
510
|
+
// never wasted. `__pending_referenced_frames` is sorted
|
|
511
|
+
// ascending; entries `> sim_frame` stay buffered.
|
|
365
512
|
let replay_start = sim_frame;
|
|
366
513
|
const refs = this.#pending_referenced_frames;
|
|
367
514
|
if (refs.length > 0 && refs[0] <= sim_frame) {
|
|
@@ -375,9 +522,11 @@ export class ServerAuthoritativeServer {
|
|
|
375
522
|
this.onRewind.send3(committed_top, replay_start - 1, committed_top - (replay_start - 1));
|
|
376
523
|
}
|
|
377
524
|
|
|
378
|
-
// 4. Replay [replay_start, sim_frame].
|
|
525
|
+
// 4. Replay [replay_start, sim_frame]. Only `sim_frame` is being
|
|
526
|
+
// simulated for the first time; the rest are re-executions of
|
|
527
|
+
// frames the log already holds.
|
|
379
528
|
for (let f = replay_start; f <= sim_frame; f++) {
|
|
380
|
-
this.#replay_frame(f);
|
|
529
|
+
this.#replay_frame(f, f === sim_frame);
|
|
381
530
|
}
|
|
382
531
|
|
|
383
532
|
// 5. Keep only `frame > sim_frame` pending (future buffer).
|
|
@@ -406,8 +555,57 @@ export class ServerAuthoritativeServer {
|
|
|
406
555
|
return max - this.current_sim_frame;
|
|
407
556
|
}
|
|
408
557
|
|
|
409
|
-
/**
|
|
410
|
-
|
|
558
|
+
/**
|
|
559
|
+
* Walk `action_log[frame_number]` looking for a record identical to
|
|
560
|
+
* `(sender_id, type_id, payload)`. Compares the payload in place against
|
|
561
|
+
* the log's own bytes — no copy, unlike {@link __read_historical}, because
|
|
562
|
+
* this runs once per arriving action.
|
|
563
|
+
*
|
|
564
|
+
* The key can only recognise records the log actually holds. An action
|
|
565
|
+
* the executor REJECTED (owner authorization) writes nothing, so each of
|
|
566
|
+
* its retransmissions still reads as new input and still costs a rewind —
|
|
567
|
+
* self-limiting, because the sender stops re-sending the frame once it is
|
|
568
|
+
* acked.
|
|
569
|
+
*
|
|
570
|
+
* Caller must have checked `action_log.has_frame(frame_number)`, and that
|
|
571
|
+
* the frame is closed.
|
|
572
|
+
*
|
|
573
|
+
* @param {number} frame_number
|
|
574
|
+
* @param {number} sender_id
|
|
575
|
+
* @param {number} type_id
|
|
576
|
+
* @param {Uint8Array} payload
|
|
577
|
+
* @returns {boolean}
|
|
578
|
+
* @private
|
|
579
|
+
*/
|
|
580
|
+
#log_holds_record(frame_number, sender_id, type_id, payload) {
|
|
581
|
+
const cursor = this.#cursor;
|
|
582
|
+
cursor.open(this.action_log, frame_number);
|
|
583
|
+
const bytes = cursor.buffer.raw_bytes;
|
|
584
|
+
while (cursor.next()) {
|
|
585
|
+
if (cursor.action_type_id !== type_id) continue;
|
|
586
|
+
if (cursor.sender_id !== sender_id) continue;
|
|
587
|
+
if (cursor.payload_len !== payload.length) continue;
|
|
588
|
+
|
|
589
|
+
const payload_start = cursor.payload_start;
|
|
590
|
+
let same = true;
|
|
591
|
+
for (let i = 0; i < payload.length; i++) {
|
|
592
|
+
if (bytes[payload_start + i] !== payload[i]) { same = false; break; }
|
|
593
|
+
}
|
|
594
|
+
if (same) return true;
|
|
595
|
+
}
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Execute frame `f`: its history, its pending input and — when `fresh`,
|
|
601
|
+
* meaning this is the first time the frame is simulated — the
|
|
602
|
+
* locally-authored queue, merged and sorted, then the local sim.
|
|
603
|
+
*
|
|
604
|
+
* @param {number} f
|
|
605
|
+
* @param {boolean} fresh
|
|
606
|
+
* @private
|
|
607
|
+
*/
|
|
608
|
+
#replay_frame(f, fresh) {
|
|
411
609
|
this.#sort_scratch.length = 0;
|
|
412
610
|
|
|
413
611
|
// Read historical actions out of action_log[f] BEFORE begin_frame(f)
|
|
@@ -420,15 +618,13 @@ export class ServerAuthoritativeServer {
|
|
|
420
618
|
this.#sort_scratch.push({ sender_id: h.sender_id, type_id: h.type_id, payload: h.payload });
|
|
421
619
|
}
|
|
422
620
|
|
|
423
|
-
// Append
|
|
424
|
-
//
|
|
425
|
-
//
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
//
|
|
429
|
-
//
|
|
430
|
-
// record left over from the previous apply and executes the action
|
|
431
|
-
// twice (and three times, four times… until the ack arrives).
|
|
621
|
+
// Append the pending actions for this frame. Retransmissions of
|
|
622
|
+
// records the log already holds are dropped on arrival (see
|
|
623
|
+
// __pending_add), so in the supported call pattern nothing here
|
|
624
|
+
// duplicates history. The check stays as a safety net: a duplicate
|
|
625
|
+
// that reached this point would merge with the historical record and
|
|
626
|
+
// execute the action twice, diverging the world, and the cost of the
|
|
627
|
+
// check is a scan of a small frame's copied history.
|
|
432
628
|
//
|
|
433
629
|
// Dedup key: (sender_id, type_id, payload bytes). Two actions are
|
|
434
630
|
// "the same arrival" if all three match. (Same sender_id and
|
|
@@ -450,6 +646,26 @@ export class ServerAuthoritativeServer {
|
|
|
450
646
|
this.#sort_scratch.push({ sender_id: p_sender, type_id: p_type, payload: p_payload });
|
|
451
647
|
}
|
|
452
648
|
|
|
649
|
+
// Locally-authored actions join the merge as input, and only on the
|
|
650
|
+
// frame being simulated for the first time — a replayed frame already
|
|
651
|
+
// holds, in the history read above, the ones it was given when it was
|
|
652
|
+
// fresh. They go in BEFORE the sort so a frame's input order does not
|
|
653
|
+
// depend on whether it is being simulated fresh or replayed: on replay
|
|
654
|
+
// these come back through __read_historical and are sorted with
|
|
655
|
+
// everything else, so the fresh pass has to sort them the same way.
|
|
656
|
+
if (fresh && this.#local_type_ids.length > 0) {
|
|
657
|
+
const sender = this.server_peer_id >= 0 ? this.server_peer_id : SENDER_LOCAL;
|
|
658
|
+
for (let i = 0; i < this.#local_type_ids.length; i++) {
|
|
659
|
+
this.#sort_scratch.push({
|
|
660
|
+
sender_id: sender,
|
|
661
|
+
type_id: this.#local_type_ids[i],
|
|
662
|
+
payload: this.#local_payloads[i],
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
this.#local_type_ids.length = 0;
|
|
666
|
+
this.#local_payloads.length = 0;
|
|
667
|
+
}
|
|
668
|
+
|
|
453
669
|
// Stable sort by sender. Array.prototype.sort is stable since ES2019;
|
|
454
670
|
// equal sender_ids preserve insertion order, with historical entries
|
|
455
671
|
// appearing before newly-arrived pending entries for the same sender.
|
|
@@ -461,10 +677,24 @@ export class ServerAuthoritativeServer {
|
|
|
461
677
|
const s = this.#sort_scratch[i];
|
|
462
678
|
this.#apply_payload(s.type_id, s.sender_id, s.payload);
|
|
463
679
|
}
|
|
464
|
-
|
|
465
|
-
//
|
|
466
|
-
//
|
|
467
|
-
|
|
680
|
+
|
|
681
|
+
// Notify user code so server-side local sim runs at the right point in
|
|
682
|
+
// the frame: after all input for the frame is applied, before the frame
|
|
683
|
+
// is closed.
|
|
684
|
+
//
|
|
685
|
+
// Everything the handler executes is DERIVED output — the handler runs
|
|
686
|
+
// again on every replay of this frame, so the replay recomputes it
|
|
687
|
+
// rather than reapplying it. `deriving` makes the executor stamp those
|
|
688
|
+
// records SENDER_DERIVED, which is how __read_historical tells them
|
|
689
|
+
// from the input records above. Cleared in a finally: a handler that
|
|
690
|
+
// throws must not leave the executor stamping every later record as
|
|
691
|
+
// derived, which would silently drop that input from every replay.
|
|
692
|
+
this.executor.deriving = true;
|
|
693
|
+
try {
|
|
694
|
+
this.onLocalSim.send1(f);
|
|
695
|
+
} finally {
|
|
696
|
+
this.executor.deriving = false;
|
|
697
|
+
}
|
|
468
698
|
this.action_log.end_frame();
|
|
469
699
|
}
|
|
470
700
|
|
|
@@ -491,23 +721,20 @@ export class ServerAuthoritativeServer {
|
|
|
491
721
|
#read_historical(frame_number, out_array) {
|
|
492
722
|
out_array.length = 0;
|
|
493
723
|
if (!this.action_log.has_frame(frame_number)) return;
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
payload.set(buf.raw_bytes.subarray(buf.position, buf.position + payload_len));
|
|
509
|
-
buf.position += payload_len;
|
|
510
|
-
out_array.push({ type_id, sender_id, payload });
|
|
724
|
+
const cursor = this.#cursor;
|
|
725
|
+
cursor.open(this.action_log, frame_number);
|
|
726
|
+
const bytes = cursor.buffer.raw_bytes;
|
|
727
|
+
while (cursor.next()) {
|
|
728
|
+
// Derived records are the previous pass's local-sim output. The
|
|
729
|
+
// caller re-runs onLocalSim for this frame, which recomputes them
|
|
730
|
+
// against a world that now includes the late input that forced the
|
|
731
|
+
// replay; carrying the stale copy forward as well would apply the
|
|
732
|
+
// effect twice, and the copies would accumulate one per replay.
|
|
733
|
+
if (cursor.sender_id === SENDER_DERIVED) continue;
|
|
734
|
+
|
|
735
|
+
const payload = new Uint8Array(cursor.payload_len);
|
|
736
|
+
payload.set(bytes.subarray(cursor.payload_start, cursor.payload_start + cursor.payload_len));
|
|
737
|
+
out_array.push({ type_id: cursor.action_type_id, sender_id: cursor.sender_id, payload });
|
|
511
738
|
}
|
|
512
739
|
}
|
|
513
740
|
|
|
@@ -542,17 +769,17 @@ export class ServerAuthoritativeServer {
|
|
|
542
769
|
return;
|
|
543
770
|
}
|
|
544
771
|
|
|
545
|
-
//
|
|
546
|
-
//
|
|
547
|
-
//
|
|
548
|
-
//
|
|
549
|
-
//
|
|
550
|
-
//
|
|
551
|
-
//
|
|
552
|
-
//
|
|
553
|
-
//
|
|
554
|
-
//
|
|
555
|
-
//
|
|
772
|
+
// Retransmissions are routine on the wire: `Replicator.pack_for_peer`
|
|
773
|
+
// packs every frame in [last_acked + 1, current_frame] each tick, so
|
|
774
|
+
// an action arrives once per tick until its ack round-trips, and
|
|
775
|
+
// several copies can land in the same server tick when the round trip
|
|
776
|
+
// exceeds the tick period. A copy is recognised by its whole identity,
|
|
777
|
+
// (sender_id, type_id, payload bytes) — distinct payloads from the
|
|
778
|
+
// same sender at the same frame are legitimately different actions
|
|
779
|
+
// (move + fire) and both flow through.
|
|
780
|
+
//
|
|
781
|
+
// First against everything already pending for the frame, which
|
|
782
|
+
// catches the copies that arrive before the frame is simulated.
|
|
556
783
|
for (let i = 0; i < this.#pending_frames.length; i++) {
|
|
557
784
|
if (this.#pending_frames[i] !== frame_number) continue;
|
|
558
785
|
if (this.#pending_senders[i] !== sender_id) continue;
|
|
@@ -560,6 +787,26 @@ export class ServerAuthoritativeServer {
|
|
|
560
787
|
if (fastArrayEquals(this.#pending_payloads[i], payload)) return; // duplicate already in pending; drop
|
|
561
788
|
}
|
|
562
789
|
|
|
790
|
+
// Then against the action log, which catches the copies that arrive
|
|
791
|
+
// after it. A record the log already holds is not input — applying it
|
|
792
|
+
// again would apply the action twice, and rewinding for it would
|
|
793
|
+
// replay the world into the state it is already in — so it is dropped
|
|
794
|
+
// here, and pending holds only input the log does not. That is what
|
|
795
|
+
// lets `tick` take the oldest pending frame as its replay window
|
|
796
|
+
// without a second look.
|
|
797
|
+
//
|
|
798
|
+
// Frames are only open inside `tick`, and packets arrive between
|
|
799
|
+
// ticks, so an open frame here means a call pattern this orchestrator
|
|
800
|
+
// does not support (a packet delivered from inside a local-sim
|
|
801
|
+
// handler). The check is skipped rather than reading an open frame's
|
|
802
|
+
// stale length; the copy then costs one spurious rewind, and
|
|
803
|
+
// `__replay_frame`'s own dedup keeps it from applying twice.
|
|
804
|
+
if (this.action_log.has_frame(frame_number)
|
|
805
|
+
&& !this.action_log.has_open_frame()
|
|
806
|
+
&& this.#log_holds_record(frame_number, sender_id, type_id, payload)) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
|
|
563
810
|
this.#pending_frames.push(frame_number);
|
|
564
811
|
this.#pending_senders.push(sender_id);
|
|
565
812
|
this.#pending_type_ids.push(type_id);
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
* uint32: action_payload_len
|
|
26
26
|
* bytes: action_payload
|
|
27
27
|
* ```
|
|
28
|
+
* {@link NetworkPeer} prefixes each packet of this with a slice header — the
|
|
29
|
+
* frame range the packet covers and whether it is the first of the sender's
|
|
30
|
+
* tick — which it parses itself and hands to {@link unpack_from_peer} as
|
|
31
|
+
* `slice`, so the receiver can apply the sender's packets in frame order.
|
|
28
32
|
*
|
|
29
33
|
* @author Alex Goldring
|
|
30
34
|
* @copyright Company Named Limited (c) 2026
|
|
@@ -56,8 +60,9 @@ export class Replicator {
|
|
|
56
60
|
* or anything else that needs to know "frame N from peer P has just
|
|
57
61
|
* been applied to the local world."
|
|
58
62
|
*
|
|
59
|
-
* Fires in frame
|
|
60
|
-
*
|
|
63
|
+
* Fires in frame order — within a packet, which encodes its frames
|
|
64
|
+
* ascending, and across packets, because a later slice of a sender's tick
|
|
65
|
+
* is held until the slices before it have landed.
|
|
61
66
|
*
|
|
62
67
|
* @type {Signal}
|
|
63
68
|
*/
|
|
@@ -111,27 +116,57 @@ export class Replicator {
|
|
|
111
116
|
*
|
|
112
117
|
* Writes nothing if no in-scope actions are found.
|
|
113
118
|
*
|
|
119
|
+
* `max_bytes` caps how many bytes this call may add. Frame groups are
|
|
120
|
+
* written whole or not at all: when the next group would cross the cap, the
|
|
121
|
+
* pack stops before it and the return value reports how far it got, so the
|
|
122
|
+
* caller can credit exactly what it sent and pick the rest up on a later
|
|
123
|
+
* pass. The one exception is a first group that does not fit by itself —
|
|
124
|
+
* that one is written anyway, because no smaller pack could ever carry the
|
|
125
|
+
* frame and dropping it would strand those actions forever.
|
|
126
|
+
*
|
|
114
127
|
* @param {number} peer_id
|
|
115
128
|
* @param {number} start_frame inclusive; if no frame in range is in the log, that frame is skipped
|
|
116
129
|
* @param {number} end_frame inclusive
|
|
117
130
|
* @param {BinaryBuffer} out_buffer
|
|
131
|
+
* @param {number} [max_bytes] byte budget for this call; unbounded by default
|
|
132
|
+
* @returns {number} the last frame this pack covers, or `start_frame - 1` if
|
|
133
|
+
* it covers nothing. A frame that was skipped — absent from the log, or
|
|
134
|
+
* holding nothing in scope — counts as covered: the receiver has nothing
|
|
135
|
+
* to apply for it, so the caller may credit it.
|
|
118
136
|
*/
|
|
119
|
-
pack_for_peer(peer_id: number, start_frame: number, end_frame: number, out_buffer: BinaryBuffer):
|
|
137
|
+
pack_for_peer(peer_id: number, start_frame: number, end_frame: number, out_buffer: BinaryBuffer, max_bytes?: number): number;
|
|
120
138
|
/**
|
|
121
139
|
* Parse and apply actions from `in_buffer` into the local world via the executor.
|
|
122
140
|
* Each frame in the packet opens a new entry in the local action log under the
|
|
123
141
|
* sender's frame number, ensuring the rewind/replay machinery sees consistent
|
|
124
142
|
* frame indexing across peers.
|
|
125
143
|
*
|
|
144
|
+
* `slice` is the sender's description of the packet, from the
|
|
145
|
+
* {@link NetworkPeer} slice header: the frame range it covers and whether
|
|
146
|
+
* it is the first packet of the sender's tick. Frames are applied in frame
|
|
147
|
+
* order. A slice that starts past the frames applied so far and is not a
|
|
148
|
+
* head is a later slice of a burst whose earlier slice has not landed; it
|
|
149
|
+
* is held and applied once the gap before it fills. A head is applied as
|
|
150
|
+
* soon as it arrives, because nothing the sender can still send lies
|
|
151
|
+
* before it — that is also how the receiver moves past frames lost for
|
|
152
|
+
* good. Without `slice` (callers that pack and unpack directly) the packet
|
|
153
|
+
* is taken as a head covering the frames it carries.
|
|
154
|
+
*
|
|
126
155
|
* @param {number} peer_id
|
|
127
156
|
* @param {BinaryBuffer} in_buffer
|
|
128
157
|
* @param {number} in_buffer_end byte position to stop reading at
|
|
158
|
+
* @param {{frame_start: number, frame_end: number, head: boolean}|null} [slice]
|
|
129
159
|
*/
|
|
130
|
-
unpack_from_peer(peer_id: number, in_buffer: BinaryBuffer, in_buffer_end: number
|
|
160
|
+
unpack_from_peer(peer_id: number, in_buffer: BinaryBuffer, in_buffer_end: number, slice?: {
|
|
161
|
+
frame_start: number;
|
|
162
|
+
frame_end: number;
|
|
163
|
+
head: boolean;
|
|
164
|
+
} | null): void;
|
|
131
165
|
/**
|
|
132
|
-
* Forget
|
|
133
|
-
*
|
|
134
|
-
*
|
|
166
|
+
* Forget a peer's inbound state — its apply watermark and any slices held
|
|
167
|
+
* for it. Call when a peer disconnects so a later peer reusing the same id
|
|
168
|
+
* (or the same peer resuming a session whose frame numbering restarts) is
|
|
169
|
+
* not wrongly deduped against stale state.
|
|
135
170
|
*
|
|
136
171
|
* @param {number} peer_id
|
|
137
172
|
*/
|
|
@@ -139,4 +174,5 @@ export class Replicator {
|
|
|
139
174
|
#private;
|
|
140
175
|
}
|
|
141
176
|
import Signal from "../../../core/events/signal/Signal.js";
|
|
177
|
+
import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
|
|
142
178
|
//# sourceMappingURL=Replicator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Replicator.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/replication/Replicator.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Replicator.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/replication/Replicator.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH;IAkFI;;;;;;;;OAQG;IACH;;;;;;wCAHiD,MAAM,cAAc,MAAM,GAAG,OAAO;;OA8BpF;IA/ED;;;;;;;;;;;;;OAaG;IACH,gBAFU,MAAM,CAEc;IAE9B;;;;;;;;;;;;;;;;;OAiBG;IACH,6BAFqB,MAAM,gBAAgB,MAAM,kBAAkB,MAAM,aAAa,YAAY,kBAAkB,MAAM,eAAe,MAAM,KAAK,IAAI,CAE/H;IAmBrB;;OAEG;IACH,sBAA4B;IAE5B;;OAEG;IACH,mCAAsC;IAEtC;;OAEG;IACH,4BAAwB;IAExB;;OAEG;IACH,iCAA4B;IAE5B;;;;OAIG;IACH;oCAFwC,MAAM,cAAc,MAAM,GAAG,OAAO;MAE5C;IAGpC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,uBAVW,MAAM,eACN,MAAM,aACN,MAAM,cACN,YAAY,cACZ,MAAM,GACJ,MAAM,CA4ElB;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,0BALW,MAAM,aACN,YAAY,iBACZ,MAAM,UACN;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAC,GAAC,IAAI,QAmEtE;IAyLD;;;;;;;OAOG;IACH,qBAFW,MAAM,QAKhB;;CA8CJ;mBAxlBkB,uCAAuC;6BAD7B,sCAAsC"}
|