@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
|
@@ -14,7 +14,7 @@ import { FrameBufferRing } from "../state/FrameBufferRing.js";
|
|
|
14
14
|
* uint32: prior_payload_len
|
|
15
15
|
* bytes: prior_payload (adapter.serialize of the component's prior state)
|
|
16
16
|
* uint8: action_type_id
|
|
17
|
-
* uint8: sender_id (
|
|
17
|
+
* uint8: sender_id (provenance of the record; local-only,
|
|
18
18
|
* STRIPPED by Replicator before send)
|
|
19
19
|
* uint32: action_payload_len
|
|
20
20
|
* bytes: action_payload (the action's own serialize output)
|
|
@@ -23,9 +23,21 @@ import { FrameBufferRing } from "../state/FrameBufferRing.js";
|
|
|
23
23
|
* Self-describing: records can be skipped without consulting the action registry,
|
|
24
24
|
* which means rewind code can walk records forward to find boundaries, then
|
|
25
25
|
* iterate backward to apply prior states — no need to instantiate any actions.
|
|
26
|
+
* {@link ActionRecordCursor} is that walk; readers use it rather than parsing
|
|
27
|
+
* the layout themselves.
|
|
26
28
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
+
* `sender_id` says where the record came from, which is what a rollback replay
|
|
30
|
+
* needs in order to decide what to do with it:
|
|
31
|
+
*
|
|
32
|
+
* - a peer id `[0, 253]` — arrived from that peer;
|
|
33
|
+
* - `SENDER_LOCAL` (255) — authored on this peer;
|
|
34
|
+
* - `SENDER_DERIVED` (254) — computed by this peer's simulation from the
|
|
35
|
+
* frame's own state. A replay of the frame recomputes these rather than
|
|
36
|
+
* reapplying them (see `ServerAuthoritativeServer.__read_historical`), so
|
|
37
|
+
* the sim's output does not accumulate a copy per replay.
|
|
38
|
+
*
|
|
39
|
+
* It also gives the replay a stable sort key, so multi-client action order is
|
|
40
|
+
* deterministic across peers. It never crosses the wire —
|
|
29
41
|
* {@link Replicator#pack_for_peer} strips it and the receiver derives sender
|
|
30
42
|
* from the inbound packet's peer_id, so a hostile peer cannot impersonate.
|
|
31
43
|
*
|
|
@@ -102,6 +114,17 @@ export class ActionLog {
|
|
|
102
114
|
this.#current_buffer = null;
|
|
103
115
|
}
|
|
104
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Is a frame open for writing? {@link current_buffer} — and therefore
|
|
119
|
+
* `SimActionExecutor.execute` — throws when it is not, so a caller that can
|
|
120
|
+
* run either inside or outside a frame checks this to pick its path.
|
|
121
|
+
*
|
|
122
|
+
* @returns {boolean}
|
|
123
|
+
*/
|
|
124
|
+
has_open_frame() {
|
|
125
|
+
return this.#current_frame !== -1;
|
|
126
|
+
}
|
|
127
|
+
|
|
105
128
|
/**
|
|
106
129
|
* Get the buffer for the currently-open frame for direct writing.
|
|
107
130
|
*
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forward cursor over the records of one closed {@link ActionLog} frame.
|
|
3
|
+
*
|
|
4
|
+
* The record layout is self-describing (see {@link ActionLog}), so any reader
|
|
5
|
+
* can walk it — and five did, each with its own copy of the header parse: the
|
|
6
|
+
* replicator's scope scan and action copy, the rewind engine's boundary pass,
|
|
7
|
+
* and the rollback server's history read and retransmission check. This is
|
|
8
|
+
* that parse in one place. {@link next} reads one record's header and exposes
|
|
9
|
+
* the layout as positions into the frame's buffer; what a reader does with the
|
|
10
|
+
* prior-state entries or the action payload is its own business.
|
|
11
|
+
*
|
|
12
|
+
* Allocation-free after construction: a reader owns one cursor and re-opens
|
|
13
|
+
* it per frame. After `next` returns true the buffer's `position` is at the
|
|
14
|
+
* END of the record, so a reader that wants the prior-state entries sets
|
|
15
|
+
* `position = prior_start` and reads `prior_count` of them; `next` seeks from
|
|
16
|
+
* `record_end` regardless of where the reader left the position.
|
|
17
|
+
*
|
|
18
|
+
* ```
|
|
19
|
+
* cursor.open(action_log, frame);
|
|
20
|
+
* while (cursor.next()) {
|
|
21
|
+
* // cursor.action_type_id, cursor.sender_id,
|
|
22
|
+
* // cursor.buffer.raw_bytes[cursor.payload_start .. + cursor.payload_len]
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @author Alex Goldring
|
|
27
|
+
* @copyright Company Named Limited (c) 2026
|
|
28
|
+
*/
|
|
29
|
+
export class ActionRecordCursor {
|
|
30
|
+
/**
|
|
31
|
+
* The open frame's buffer, positioned at {@link record_end} after each
|
|
32
|
+
* successful {@link next}.
|
|
33
|
+
* @type {BinaryBuffer|null}
|
|
34
|
+
*/
|
|
35
|
+
buffer: BinaryBuffer | null;
|
|
36
|
+
/** @type {number} first byte of the current record */
|
|
37
|
+
record_start: number;
|
|
38
|
+
/** @type {number} prior-state entries in the current record */
|
|
39
|
+
prior_count: number;
|
|
40
|
+
/**
|
|
41
|
+
* First byte of the first prior-state entry. Each entry is
|
|
42
|
+
* `varint entity_id, uint8 component_type_id, uint32 len, bytes[len]`.
|
|
43
|
+
* @type {number}
|
|
44
|
+
*/
|
|
45
|
+
prior_start: number;
|
|
46
|
+
/** @type {number} */
|
|
47
|
+
action_type_id: number;
|
|
48
|
+
/**
|
|
49
|
+
* The record's provenance byte: a peer id, `SENDER_LOCAL` or
|
|
50
|
+
* `SENDER_DERIVED` (see {@link SimActionExecutor}).
|
|
51
|
+
* @type {number}
|
|
52
|
+
*/
|
|
53
|
+
sender_id: number;
|
|
54
|
+
/** @type {number} first byte of the action payload */
|
|
55
|
+
payload_start: number;
|
|
56
|
+
/** @type {number} */
|
|
57
|
+
payload_len: number;
|
|
58
|
+
/**
|
|
59
|
+
* One past the last byte of the current record — and so the first byte of
|
|
60
|
+
* the next, which is where {@link next} resumes. `0` before the first
|
|
61
|
+
* record.
|
|
62
|
+
* @type {number}
|
|
63
|
+
*/
|
|
64
|
+
record_end: number;
|
|
65
|
+
/**
|
|
66
|
+
* Position the cursor before the first record of `frame`, which must be
|
|
67
|
+
* closed and present in the log (see {@link ActionLog#buffer_for}).
|
|
68
|
+
*
|
|
69
|
+
* @param {ActionLog} action_log
|
|
70
|
+
* @param {number} frame
|
|
71
|
+
*/
|
|
72
|
+
open(action_log: ActionLog, frame: number): void;
|
|
73
|
+
/**
|
|
74
|
+
* Advance to the next record. Returns false once the frame is exhausted,
|
|
75
|
+
* leaving the fields as they were.
|
|
76
|
+
*
|
|
77
|
+
* @returns {boolean}
|
|
78
|
+
*/
|
|
79
|
+
next(): boolean;
|
|
80
|
+
#private;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=ActionRecordCursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActionRecordCursor.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/ActionRecordCursor.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH;IACI;;;;OAIG;IACH,QAFU,eAAa,IAAI,CAEb;IAEd,sDAAsD;IACtD,cADW,MAAM,CACA;IAEjB,+DAA+D;IAC/D,aADW,MAAM,CACD;IAEhB;;;;OAIG;IACH,aAFU,MAAM,CAEA;IAEhB,qBAAqB;IACrB,gBADW,MAAM,CACE;IAEnB;;;;OAIG;IACH,WAFU,MAAM,CAEF;IAEd,sDAAsD;IACtD,eADW,MAAM,CACC;IAElB,qBAAqB;IACrB,aADW,MAAM,CACD;IAEhB;;;;;OAKG;IACH,YAFU,MAAM,CAED;IAKf;;;;;;OAMG;IACH,mCAFW,MAAM,QAMhB;IAED;;;;;OAKG;IACH,QAFa,OAAO,CAyBnB;;CACJ"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forward cursor over the records of one closed {@link ActionLog} frame.
|
|
3
|
+
*
|
|
4
|
+
* The record layout is self-describing (see {@link ActionLog}), so any reader
|
|
5
|
+
* can walk it — and five did, each with its own copy of the header parse: the
|
|
6
|
+
* replicator's scope scan and action copy, the rewind engine's boundary pass,
|
|
7
|
+
* and the rollback server's history read and retransmission check. This is
|
|
8
|
+
* that parse in one place. {@link next} reads one record's header and exposes
|
|
9
|
+
* the layout as positions into the frame's buffer; what a reader does with the
|
|
10
|
+
* prior-state entries or the action payload is its own business.
|
|
11
|
+
*
|
|
12
|
+
* Allocation-free after construction: a reader owns one cursor and re-opens
|
|
13
|
+
* it per frame. After `next` returns true the buffer's `position` is at the
|
|
14
|
+
* END of the record, so a reader that wants the prior-state entries sets
|
|
15
|
+
* `position = prior_start` and reads `prior_count` of them; `next` seeks from
|
|
16
|
+
* `record_end` regardless of where the reader left the position.
|
|
17
|
+
*
|
|
18
|
+
* ```
|
|
19
|
+
* cursor.open(action_log, frame);
|
|
20
|
+
* while (cursor.next()) {
|
|
21
|
+
* // cursor.action_type_id, cursor.sender_id,
|
|
22
|
+
* // cursor.buffer.raw_bytes[cursor.payload_start .. + cursor.payload_len]
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @author Alex Goldring
|
|
27
|
+
* @copyright Company Named Limited (c) 2026
|
|
28
|
+
*/
|
|
29
|
+
export class ActionRecordCursor {
|
|
30
|
+
/**
|
|
31
|
+
* The open frame's buffer, positioned at {@link record_end} after each
|
|
32
|
+
* successful {@link next}.
|
|
33
|
+
* @type {BinaryBuffer|null}
|
|
34
|
+
*/
|
|
35
|
+
buffer = null;
|
|
36
|
+
|
|
37
|
+
/** @type {number} first byte of the current record */
|
|
38
|
+
record_start = 0;
|
|
39
|
+
|
|
40
|
+
/** @type {number} prior-state entries in the current record */
|
|
41
|
+
prior_count = 0;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* First byte of the first prior-state entry. Each entry is
|
|
45
|
+
* `varint entity_id, uint8 component_type_id, uint32 len, bytes[len]`.
|
|
46
|
+
* @type {number}
|
|
47
|
+
*/
|
|
48
|
+
prior_start = 0;
|
|
49
|
+
|
|
50
|
+
/** @type {number} */
|
|
51
|
+
action_type_id = 0;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The record's provenance byte: a peer id, `SENDER_LOCAL` or
|
|
55
|
+
* `SENDER_DERIVED` (see {@link SimActionExecutor}).
|
|
56
|
+
* @type {number}
|
|
57
|
+
*/
|
|
58
|
+
sender_id = 0;
|
|
59
|
+
|
|
60
|
+
/** @type {number} first byte of the action payload */
|
|
61
|
+
payload_start = 0;
|
|
62
|
+
|
|
63
|
+
/** @type {number} */
|
|
64
|
+
payload_len = 0;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* One past the last byte of the current record — and so the first byte of
|
|
68
|
+
* the next, which is where {@link next} resumes. `0` before the first
|
|
69
|
+
* record.
|
|
70
|
+
* @type {number}
|
|
71
|
+
*/
|
|
72
|
+
record_end = 0;
|
|
73
|
+
|
|
74
|
+
/** @type {number} one past the last byte of the frame */
|
|
75
|
+
#end = 0;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Position the cursor before the first record of `frame`, which must be
|
|
79
|
+
* closed and present in the log (see {@link ActionLog#buffer_for}).
|
|
80
|
+
*
|
|
81
|
+
* @param {ActionLog} action_log
|
|
82
|
+
* @param {number} frame
|
|
83
|
+
*/
|
|
84
|
+
open(action_log, frame) {
|
|
85
|
+
this.buffer = action_log.buffer_for(frame); // rewinds to 0
|
|
86
|
+
this.#end = action_log.write_end_for(frame);
|
|
87
|
+
this.record_end = 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Advance to the next record. Returns false once the frame is exhausted,
|
|
92
|
+
* leaving the fields as they were.
|
|
93
|
+
*
|
|
94
|
+
* @returns {boolean}
|
|
95
|
+
*/
|
|
96
|
+
next() {
|
|
97
|
+
if (this.record_end >= this.#end) return false;
|
|
98
|
+
|
|
99
|
+
const buffer = this.buffer;
|
|
100
|
+
buffer.position = this.record_end;
|
|
101
|
+
|
|
102
|
+
this.record_start = buffer.position;
|
|
103
|
+
this.prior_count = buffer.readUintVar();
|
|
104
|
+
this.prior_start = buffer.position;
|
|
105
|
+
for (let i = 0; i < this.prior_count; i++) {
|
|
106
|
+
buffer.readUintVar(); // entity_id
|
|
107
|
+
buffer.readUint8(); // component_type_id
|
|
108
|
+
const prior_len = buffer.readUint32();
|
|
109
|
+
buffer.position += prior_len; // prior payload
|
|
110
|
+
}
|
|
111
|
+
this.action_type_id = buffer.readUint8();
|
|
112
|
+
this.sender_id = buffer.readUint8();
|
|
113
|
+
this.payload_len = buffer.readUint32();
|
|
114
|
+
this.payload_start = buffer.position;
|
|
115
|
+
this.record_end = this.payload_start + this.payload_len;
|
|
116
|
+
buffer.position = this.record_end;
|
|
117
|
+
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RewindEngine.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/RewindEngine.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RewindEngine.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/RewindEngine.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAeI;;;;;;OAMG;IACH,uDANW;QACV,UAAc,YAAY;QAC1B,KAAS,yBAAyB;QAClC,kBAAsB,8BAA8B;KACjD,EAiBH;IAdG;;OAEG;IACH,sBAA4B;IAE5B;;OAEG;IACH,8BAAkB;IAElB;;OAEG;IACH,gDAA4C;IAGhD;;;;;OAKG;IACH,kBAFW,MAAM,QA0BhB;IAED;;;;;;;;;OASG;IACH,yBAHW,MAAM,gBACN,MAAM,QAWhB;;CAiDJ"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { assert } from "../../../core/assert.js";
|
|
2
|
+
import { ActionRecordCursor } from "./ActionRecordCursor.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Walks the {@link ActionLog} backwards to restore prior component state.
|
|
@@ -28,6 +29,13 @@ export class RewindEngine {
|
|
|
28
29
|
*/
|
|
29
30
|
#record_starts = new Int32Array(64);
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Walks a frame's records to find where each starts.
|
|
34
|
+
* @type {ActionRecordCursor}
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
#cursor = new ActionRecordCursor();
|
|
38
|
+
|
|
31
39
|
/**
|
|
32
40
|
* @param {{
|
|
33
41
|
* action_log: ActionLog,
|
|
@@ -64,20 +72,19 @@ export class RewindEngine {
|
|
|
64
72
|
throw new Error(`RewindEngine.undo_frame: frame ${frame} is not present in the action log`);
|
|
65
73
|
}
|
|
66
74
|
|
|
67
|
-
const buffer = this.action_log.buffer_for(frame);
|
|
68
|
-
const end = this.action_log.write_end_for(frame);
|
|
69
|
-
|
|
70
75
|
// 1. First pass: walk forward to find record boundaries.
|
|
76
|
+
const cursor = this.#cursor;
|
|
77
|
+
cursor.open(this.action_log, frame);
|
|
71
78
|
let record_count = 0;
|
|
72
|
-
while (
|
|
79
|
+
while (cursor.next()) {
|
|
73
80
|
if (record_count >= this.#record_starts.length) {
|
|
74
81
|
this.#grow_record_starts();
|
|
75
82
|
}
|
|
76
|
-
this.#record_starts[record_count++] =
|
|
77
|
-
this.#skip_record(buffer);
|
|
83
|
+
this.#record_starts[record_count++] = cursor.record_start;
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
// 2. Second pass: iterate records in reverse, restoring prior state.
|
|
87
|
+
const buffer = cursor.buffer;
|
|
81
88
|
for (let i = record_count - 1; i >= 0; i--) {
|
|
82
89
|
buffer.position = this.#record_starts[i];
|
|
83
90
|
this.#restore_prior_state(buffer);
|
|
@@ -106,29 +113,6 @@ export class RewindEngine {
|
|
|
106
113
|
}
|
|
107
114
|
}
|
|
108
115
|
|
|
109
|
-
/**
|
|
110
|
-
* Walk past a single record without restoring anything. Buffer position
|
|
111
|
-
* advances to the start of the next record (or to `end` if this was the last).
|
|
112
|
-
*
|
|
113
|
-
* @param {BinaryBuffer} buffer
|
|
114
|
-
* @private
|
|
115
|
-
*/
|
|
116
|
-
#skip_record(buffer) {
|
|
117
|
-
// Skip prior_state entries.
|
|
118
|
-
const prior_count = buffer.readUintVar();
|
|
119
|
-
for (let i = 0; i < prior_count; i++) {
|
|
120
|
-
buffer.readUintVar(); // entity_id
|
|
121
|
-
buffer.readUint8(); // component_type_id
|
|
122
|
-
const len = buffer.readUint32();
|
|
123
|
-
buffer.position += len; // skip prior payload
|
|
124
|
-
}
|
|
125
|
-
// Skip action.
|
|
126
|
-
buffer.readUint8(); // action_type_id
|
|
127
|
-
buffer.readUint8(); // sender_id
|
|
128
|
-
const action_len = buffer.readUint32();
|
|
129
|
-
buffer.position += action_len; // skip action payload
|
|
130
|
-
}
|
|
131
|
-
|
|
132
116
|
/**
|
|
133
117
|
* Read the prior_state entries of the record at the buffer's current position
|
|
134
118
|
* and write them back into the live components. Buffer position advances past
|
|
@@ -11,6 +11,21 @@
|
|
|
11
11
|
* deterministic consequence of the simulation, or rewind / replay /
|
|
12
12
|
* replication will desync.
|
|
13
13
|
*
|
|
14
|
+
* "Deterministic consequence" is a narrow licence, and it is worth being exact
|
|
15
|
+
* about what it buys. A rewind restores component state from the prior-bytes
|
|
16
|
+
* captured per action record, so a mutation made outside an action is never
|
|
17
|
+
* undone — it survives into the replayed frame and the sim must overwrite it
|
|
18
|
+
* with the same answer it produced before. That holds for a function of the
|
|
19
|
+
* frame's post-input state that fully determines what it writes (a clamp, a
|
|
20
|
+
* position solved from inputs) and fails for anything that reads the value it
|
|
21
|
+
* is about to change (`hp -= 10`, a counter, an accumulator). Those need a
|
|
22
|
+
* `SimAction`, whose prior-bytes capture makes them reversible.
|
|
23
|
+
*
|
|
24
|
+
* Going through an action does not, on its own, make a mutation replayable
|
|
25
|
+
* input: on a rollback orchestrator, a record's `sender_id` marks whether it
|
|
26
|
+
* arrived, was authored, or was derived, and only the first two are reapplied
|
|
27
|
+
* from the log. See `ServerAuthoritativeServer#onLocalSim`.
|
|
28
|
+
*
|
|
14
29
|
* Wire vs local: actions reference entities by `network_id` (peer-shared);
|
|
15
30
|
* `executor.slot_table.entity_for(network_id)` translates to the local id.
|
|
16
31
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SimAction.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/SimAction.js"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"SimAction.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/SimAction.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH;IAEI;;;;OAIG;IACH,gBAFU,MAAM,CAEI;IAEpB;;;;;;;;;OASG;IACH,mEAFa,IAAI,CAIhB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,qCAHoB,MAAM,qBAAa,IAAI,qCAK1C;IAED;;;;;;OAMG;IACH,iCAFa,IAAI,CAIhB;IAED;;;;;OAKG;IACH,mCAFa,IAAI,CAIhB;IAED;;;OAGG;IACH,cAEC;IAGL;;;;OAIG;IACH,sBAFU,OAAO,CAEc;CAP9B;;IAwCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsCG;IACH;;;;;;;iBAmGC"}
|
|
@@ -13,6 +13,21 @@ import { FunctionCompiler } from "../../../core/function/FunctionCompiler.js";
|
|
|
13
13
|
* deterministic consequence of the simulation, or rewind / replay /
|
|
14
14
|
* replication will desync.
|
|
15
15
|
*
|
|
16
|
+
* "Deterministic consequence" is a narrow licence, and it is worth being exact
|
|
17
|
+
* about what it buys. A rewind restores component state from the prior-bytes
|
|
18
|
+
* captured per action record, so a mutation made outside an action is never
|
|
19
|
+
* undone — it survives into the replayed frame and the sim must overwrite it
|
|
20
|
+
* with the same answer it produced before. That holds for a function of the
|
|
21
|
+
* frame's post-input state that fully determines what it writes (a clamp, a
|
|
22
|
+
* position solved from inputs) and fails for anything that reads the value it
|
|
23
|
+
* is about to change (`hp -= 10`, a counter, an accumulator). Those need a
|
|
24
|
+
* `SimAction`, whose prior-bytes capture makes them reversible.
|
|
25
|
+
*
|
|
26
|
+
* Going through an action does not, on its own, make a mutation replayable
|
|
27
|
+
* input: on a rollback orchestrator, a record's `sender_id` marks whether it
|
|
28
|
+
* arrived, was authored, or was derived, and only the first two are reapplied
|
|
29
|
+
* from the log. See `ServerAuthoritativeServer#onLocalSim`.
|
|
30
|
+
*
|
|
16
31
|
* Wire vs local: actions reference entities by `network_id` (peer-shared);
|
|
17
32
|
* `executor.slot_table.entity_for(network_id)` translates to the local id.
|
|
18
33
|
*
|
|
@@ -2,11 +2,43 @@
|
|
|
2
2
|
* Sentinel sender id for actions that originated on the local peer (not
|
|
3
3
|
* received over the wire). Used as the default `sender_id` for
|
|
4
4
|
* {@link SimActionExecutor#execute} so existing single-peer code keeps
|
|
5
|
-
* working.
|
|
5
|
+
* working.
|
|
6
6
|
*
|
|
7
7
|
* @type {number}
|
|
8
8
|
*/
|
|
9
9
|
export const SENDER_LOCAL: number;
|
|
10
|
+
/**
|
|
11
|
+
* Sentinel sender id recorded for actions the local simulation DERIVED from
|
|
12
|
+
* the frame's state, rather than received or authored. Written in place of
|
|
13
|
+
* the caller's `sender_id` while {@link SimActionExecutor#deriving} is set.
|
|
14
|
+
*
|
|
15
|
+
* The sender byte is the record's provenance, and provenance is what decides
|
|
16
|
+
* whether a rollback replay may reuse a record. Input — remote or locally
|
|
17
|
+
* authored — happened once and cannot be recomputed, so a replay reapplies it
|
|
18
|
+
* from the log. Derived output is a function of the frame's post-input state,
|
|
19
|
+
* which a replay recomputes anyway; reapplying the previous pass's copy on top
|
|
20
|
+
* of the recomputed one applies the effect twice. So the two are separated
|
|
21
|
+
* here, at the point of execution, where the distinction is actually known.
|
|
22
|
+
*
|
|
23
|
+
* Local-only, like `SENDER_LOCAL` — {@link Replicator#pack_for_peer} strips
|
|
24
|
+
* the byte before send, so this never reaches the wire.
|
|
25
|
+
*
|
|
26
|
+
* Both sentinels are reserved: valid peer ids are `[0, 253]`, enforced by
|
|
27
|
+
* {@link SimActionExecutor#execute} and at {@link NetworkPeer#connect_peer}.
|
|
28
|
+
* A peer allowed to take 254 would have its records read back as the local
|
|
29
|
+
* sim's own output and dropped from every replay — its input would apply once
|
|
30
|
+
* and then silently vanish the first time a rollback crossed its frame.
|
|
31
|
+
*
|
|
32
|
+
* @type {number}
|
|
33
|
+
*/
|
|
34
|
+
export const SENDER_DERIVED: number;
|
|
35
|
+
/**
|
|
36
|
+
* Largest id a remote peer may take. Above this are the two local provenance
|
|
37
|
+
* sentinels, {@link SENDER_DERIVED} and {@link SENDER_LOCAL}.
|
|
38
|
+
*
|
|
39
|
+
* @type {number}
|
|
40
|
+
*/
|
|
41
|
+
export const MAX_PEER_ID: number;
|
|
10
42
|
/**
|
|
11
43
|
* The single legitimate gateway for replicated state mutations.
|
|
12
44
|
*
|
|
@@ -83,6 +115,23 @@ export class SimActionExecutor {
|
|
|
83
115
|
* @type {((sender_id: number, entity_id: number, action: SimAction) => boolean) | null}
|
|
84
116
|
*/
|
|
85
117
|
authorize: (sender_id: number, entity_id: number, action: SimAction) => boolean;
|
|
118
|
+
/**
|
|
119
|
+
* When true, records written by {@link execute} are stamped
|
|
120
|
+
* {@link SENDER_DERIVED} instead of the caller's `sender_id`, marking them
|
|
121
|
+
* as output the simulation recomputes rather than input it must replay.
|
|
122
|
+
*
|
|
123
|
+
* Set by a rollback orchestrator for the span in which the frame's local
|
|
124
|
+
* sim runs (see `ServerAuthoritativeServer.__replay_frame`) and cleared
|
|
125
|
+
* immediately after. Everything outside that span — arrived input,
|
|
126
|
+
* locally-authored actions — is left with its real sender.
|
|
127
|
+
*
|
|
128
|
+
* Only the RECORDED byte changes. `sender_id` still drives the
|
|
129
|
+
* {@link authorize} gate and {@link current_sender_id}, so an action that
|
|
130
|
+
* self-validates on its sender sees the truth.
|
|
131
|
+
*
|
|
132
|
+
* @type {boolean}
|
|
133
|
+
*/
|
|
134
|
+
deriving: boolean;
|
|
86
135
|
/**
|
|
87
136
|
* @type {EntityComponentDataset}
|
|
88
137
|
*/
|
|
@@ -142,7 +191,7 @@ export class SimActionExecutor {
|
|
|
142
191
|
* @param {SimAction} action
|
|
143
192
|
* @param {number} [sender_id] peer that originated this action.
|
|
144
193
|
* Defaults to {@link SENDER_LOCAL} for locally-originated actions.
|
|
145
|
-
* Must be in `[0,
|
|
194
|
+
* Must be in `[0, MAX_PEER_ID]` for remote-originated actions.
|
|
146
195
|
* @returns {boolean} true if the action was applied; false if it was
|
|
147
196
|
* rejected by the {@link authorize} gate (and therefore not applied or
|
|
148
197
|
* logged).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SimActionExecutor.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/SimActionExecutor.js"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,2BAFU,MAAM,CAEiB;AAEjC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;
|
|
1
|
+
{"version":3,"file":"SimActionExecutor.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/SimActionExecutor.js"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,2BAFU,MAAM,CAEiB;AAEjC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,6BAFU,MAAM,CAEmB;AAEnC;;;;;GAKG;AACH,0BAFU,MAAM,CAEgB;AAEhC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;IA2DI;;;;;;;;;OASG;IACH,sGATW;QACV,KAAS,yBAAyB;QAClC,UAAc,YAAY;QAC1B,eAAmB,oBAAoB;QACvC,kBAAsB,8BAA8B;QACpD,UAAc,uBAAuB;QACrC,gBAAoB,CAAC,mBAAmB;KACrC,EAyFH;IAvJD;;;;;;;;;OASG;IACH,gBAFU,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAEP;IAEtB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,uBAFuB,MAAM,aAAa,MAAM,wBAAwB,OAAO,CAE9D;IAEjB;;;;;;;;;;;;;;;OAeG;IACH,UAFU,OAAO,CAEA;IAab;;OAEG;IACH,8BAAkB;IAElB;;OAEG;IACH,sBAA4B;IAE5B;;OAEG;IACH,mCAAsC;IAEtC;;OAEG;IACH,gDAA4C;IAE5C;;;;OAIG;IACH,iCAA4B;IAE5B;;;;;;;;;;;OAWG;IACH,kBAFU,mBAAiB,IAAI,CAES;IA4BxC;;;;;;;OAOG;IACH,mBAFU,MAAM,CAEqB;IAErC;;;;;;;OAOG;IACH,kBAFU,MAAM,CAEoB;IAGxC;;;;;;;;;;OAUG;IACH,uCAPW,MAAM,GAGJ,OAAO,CAgJnB;;CACJ;mBA3XkB,uCAAuC"}
|
|
@@ -5,12 +5,46 @@ import Signal from "../../../core/events/signal/Signal.js";
|
|
|
5
5
|
* Sentinel sender id for actions that originated on the local peer (not
|
|
6
6
|
* received over the wire). Used as the default `sender_id` for
|
|
7
7
|
* {@link SimActionExecutor#execute} so existing single-peer code keeps
|
|
8
|
-
* working.
|
|
8
|
+
* working.
|
|
9
9
|
*
|
|
10
10
|
* @type {number}
|
|
11
11
|
*/
|
|
12
12
|
export const SENDER_LOCAL = 0xFF;
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Sentinel sender id recorded for actions the local simulation DERIVED from
|
|
16
|
+
* the frame's state, rather than received or authored. Written in place of
|
|
17
|
+
* the caller's `sender_id` while {@link SimActionExecutor#deriving} is set.
|
|
18
|
+
*
|
|
19
|
+
* The sender byte is the record's provenance, and provenance is what decides
|
|
20
|
+
* whether a rollback replay may reuse a record. Input — remote or locally
|
|
21
|
+
* authored — happened once and cannot be recomputed, so a replay reapplies it
|
|
22
|
+
* from the log. Derived output is a function of the frame's post-input state,
|
|
23
|
+
* which a replay recomputes anyway; reapplying the previous pass's copy on top
|
|
24
|
+
* of the recomputed one applies the effect twice. So the two are separated
|
|
25
|
+
* here, at the point of execution, where the distinction is actually known.
|
|
26
|
+
*
|
|
27
|
+
* Local-only, like `SENDER_LOCAL` — {@link Replicator#pack_for_peer} strips
|
|
28
|
+
* the byte before send, so this never reaches the wire.
|
|
29
|
+
*
|
|
30
|
+
* Both sentinels are reserved: valid peer ids are `[0, 253]`, enforced by
|
|
31
|
+
* {@link SimActionExecutor#execute} and at {@link NetworkPeer#connect_peer}.
|
|
32
|
+
* A peer allowed to take 254 would have its records read back as the local
|
|
33
|
+
* sim's own output and dropped from every replay — its input would apply once
|
|
34
|
+
* and then silently vanish the first time a rollback crossed its frame.
|
|
35
|
+
*
|
|
36
|
+
* @type {number}
|
|
37
|
+
*/
|
|
38
|
+
export const SENDER_DERIVED = 0xFE;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Largest id a remote peer may take. Above this are the two local provenance
|
|
42
|
+
* sentinels, {@link SENDER_DERIVED} and {@link SENDER_LOCAL}.
|
|
43
|
+
*
|
|
44
|
+
* @type {number}
|
|
45
|
+
*/
|
|
46
|
+
export const MAX_PEER_ID = 0xFD;
|
|
47
|
+
|
|
14
48
|
/**
|
|
15
49
|
* The single legitimate gateway for replicated state mutations.
|
|
16
50
|
*
|
|
@@ -75,6 +109,24 @@ export class SimActionExecutor {
|
|
|
75
109
|
*/
|
|
76
110
|
authorize = null;
|
|
77
111
|
|
|
112
|
+
/**
|
|
113
|
+
* When true, records written by {@link execute} are stamped
|
|
114
|
+
* {@link SENDER_DERIVED} instead of the caller's `sender_id`, marking them
|
|
115
|
+
* as output the simulation recomputes rather than input it must replay.
|
|
116
|
+
*
|
|
117
|
+
* Set by a rollback orchestrator for the span in which the frame's local
|
|
118
|
+
* sim runs (see `ServerAuthoritativeServer.__replay_frame`) and cleared
|
|
119
|
+
* immediately after. Everything outside that span — arrived input,
|
|
120
|
+
* locally-authored actions — is left with its real sender.
|
|
121
|
+
*
|
|
122
|
+
* Only the RECORDED byte changes. `sender_id` still drives the
|
|
123
|
+
* {@link authorize} gate and {@link current_sender_id}, so an action that
|
|
124
|
+
* self-validates on its sender sees the truth.
|
|
125
|
+
*
|
|
126
|
+
* @type {boolean}
|
|
127
|
+
*/
|
|
128
|
+
deriving = false;
|
|
129
|
+
|
|
78
130
|
/**
|
|
79
131
|
* @param {{
|
|
80
132
|
* world: EntityComponentDataset,
|
|
@@ -180,7 +232,7 @@ export class SimActionExecutor {
|
|
|
180
232
|
* @param {SimAction} action
|
|
181
233
|
* @param {number} [sender_id] peer that originated this action.
|
|
182
234
|
* Defaults to {@link SENDER_LOCAL} for locally-originated actions.
|
|
183
|
-
* Must be in `[0,
|
|
235
|
+
* Must be in `[0, MAX_PEER_ID]` for remote-originated actions.
|
|
184
236
|
* @returns {boolean} true if the action was applied; false if it was
|
|
185
237
|
* rejected by the {@link authorize} gate (and therefore not applied or
|
|
186
238
|
* logged).
|
|
@@ -197,7 +249,18 @@ export class SimActionExecutor {
|
|
|
197
249
|
`execute: action class '${action.constructor.action_type_name ?? action.constructor.name}' has no wire type_id — register it (NetworkSession.defineAction, or SimActionRegistry.register) before executing it`,
|
|
198
250
|
);
|
|
199
251
|
assert.isNonNegativeInteger(sender_id, 'sender_id');
|
|
200
|
-
|
|
252
|
+
// A sender above the peer range is either the sim-derived sentinel —
|
|
253
|
+
// which a rollback replay reads back as "this record is mine to
|
|
254
|
+
// recompute", so the peer's input would apply once and then disappear
|
|
255
|
+
// on the first replay of its frame, with nothing logged — or a value
|
|
256
|
+
// that does not fit the record's one byte at all. SENDER_LOCAL itself
|
|
257
|
+
// is the caller saying "mine". Real runtime check: asserts strip in
|
|
258
|
+
// prod, and silent input loss is not something to ship behind one.
|
|
259
|
+
if (sender_id > MAX_PEER_ID && sender_id !== SENDER_LOCAL) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
`SimActionExecutor.execute: sender_id ${sender_id} is not a peer id; remote peer ids must be in [0, ${MAX_PEER_ID}] — 254 and 255 are reserved provenance markers`,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
201
264
|
|
|
202
265
|
// Expose the originating sender to apply / affected_components / the
|
|
203
266
|
// authorize policy before any of them run.
|
|
@@ -292,10 +355,14 @@ export class SimActionExecutor {
|
|
|
292
355
|
|
|
293
356
|
// 5. Append the action itself.
|
|
294
357
|
buffer.writeUint8(action.constructor.type_id);
|
|
295
|
-
// sender_id:
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
|
|
358
|
+
// sender_id: where this record came from. Local-only; not sent over the
|
|
359
|
+
// wire (Replicator strips it during pack). Used by rollback
|
|
360
|
+
// orchestrators for stable-sort tie-breaking, and to tell input (which
|
|
361
|
+
// a replay reapplies) from derived output (which a replay recomputes).
|
|
362
|
+
// While `deriving` is set the record is stamped SENDER_DERIVED — the
|
|
363
|
+
// originating sender is not meaningful for output the sim computed for
|
|
364
|
+
// itself, and nothing reads it back on that path.
|
|
365
|
+
buffer.writeUint8(this.deriving ? SENDER_DERIVED : sender_id);
|
|
299
366
|
|
|
300
367
|
// Reserve 4 bytes for action_payload_len, write payload, then back-patch.
|
|
301
368
|
const action_len_position = buffer.position;
|
|
@@ -9,7 +9,7 @@ export class Channel {
|
|
|
9
9
|
* an unacked seq falls more than half-range behind the newest sent, the
|
|
10
10
|
* signed `seq16_distance` used for loss detection wraps and the entry can
|
|
11
11
|
* neither be acked nor declared lost — a permanent leak (and a downstream
|
|
12
|
-
* `
|
|
12
|
+
* `seq_to_pending` leak in the orchestrator). Capping in-flight makes
|
|
13
13
|
* that lap impossible. Default 1024 ≫ any realistic in-flight window
|
|
14
14
|
* (RTT × send-rate) yet ≪ 32768. Only reached under a sustained one-way
|
|
15
15
|
* stall, where eviction-as-lost is the correct verdict anyway.
|
|
@@ -64,7 +64,7 @@ export class Channel {
|
|
|
64
64
|
* an unacked seq falls more than half-range behind the newest sent, the
|
|
65
65
|
* signed `seq16_distance` used for loss detection wraps and the entry can
|
|
66
66
|
* neither be acked nor declared lost — a permanent leak (and a downstream
|
|
67
|
-
* `
|
|
67
|
+
* `seq_to_pending` leak in the orchestrator). Capping in-flight makes
|
|
68
68
|
* that lap impossible. Default 1024 ≫ any realistic in-flight window
|
|
69
69
|
* (RTT × send-rate) yet ≪ 32768. Only reached under a sustained one-way
|
|
70
70
|
* stall, where eviction-as-lost is the correct verdict anyway.
|
|
@@ -64,11 +64,11 @@ export class FluidObstacleSystem extends System<any> {
|
|
|
64
64
|
/**
|
|
65
65
|
* @param {FluidComponent} fluid
|
|
66
66
|
*/
|
|
67
|
-
static "__#
|
|
67
|
+
static "__#371@#refresh_masks"(fluid: FluidComponent): void;
|
|
68
68
|
/**
|
|
69
69
|
* @param {FluidComponent} fluid
|
|
70
70
|
*/
|
|
71
|
-
static "__#
|
|
71
|
+
static "__#371@#clear_field"(fluid: FluidComponent): void;
|
|
72
72
|
/**
|
|
73
73
|
* Mark every cell of `fluid` whose centre lies within `inflation` of the
|
|
74
74
|
* posed shape as solid. Iteration is clipped to the shape's world AABB
|
|
@@ -80,7 +80,7 @@ export class FluidObstacleSystem extends System<any> {
|
|
|
80
80
|
* @param {number} inflation world-units SDF threshold
|
|
81
81
|
* @param {Float64Array} point length-3 scratch
|
|
82
82
|
*/
|
|
83
|
-
static "__#
|
|
83
|
+
static "__#371@#voxelize"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array): void;
|
|
84
84
|
/**
|
|
85
85
|
* Write the obstacle's translation velocity onto every face of every cell
|
|
86
86
|
* it voxelized — the moving-wall boundary condition. Runs AFTER the mask
|
|
@@ -100,7 +100,7 @@ export class FluidObstacleSystem extends System<any> {
|
|
|
100
100
|
* @param {number} wvy
|
|
101
101
|
* @param {number} wvz
|
|
102
102
|
*/
|
|
103
|
-
static "__#
|
|
103
|
+
static "__#371@#stamp_wall_velocity"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array, wvx: number, wvy: number, wvz: number): void;
|
|
104
104
|
constructor();
|
|
105
105
|
dependencies: (typeof FluidObstacle)[];
|
|
106
106
|
components_used: (ResourceAccessSpecification<typeof Transform> | ResourceAccessSpecification<typeof RigidBody> | ResourceAccessSpecification<typeof Collider> | ResourceAccessSpecification<typeof FluidComponent> | ResourceAccessSpecification<typeof FluidObstacle>)[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Ticker.d.ts","sourceRoot":"","sources":["../../../../src/engine/simulation/Ticker.js"],"names":[],"mappings":";AAIA;;;;;;;;;;;;;;GAcG;AACH;IACI;;;OAGG;IACH,gBAFU,KAAK,CAEK;IAEpB;;;;;;;;;;;;OAYG;IACH,uBAFU,OAAO,CAEY;IAkC7B;;;;OAIG;IACH,qBAAsB;IAUtB;;;;OAIG;IACH,yBAEC;IAED;;;;OAIG;IACH,yBAEC;IAuGD;;;OAGG;IACH,uBAFW,MAAM,
|
|
1
|
+
{"version":3,"file":"Ticker.d.ts","sourceRoot":"","sources":["../../../../src/engine/simulation/Ticker.js"],"names":[],"mappings":";AAIA;;;;;;;;;;;;;;GAcG;AACH;IACI;;;OAGG;IACH,gBAFU,KAAK,CAEK;IAEpB;;;;;;;;;;;;OAYG;IACH,uBAFU,OAAO,CAEY;IAkC7B;;;;OAIG;IACH,qBAAsB;IAUtB;;;;OAIG;IACH,yBAEC;IAED;;;;OAIG;IACH,yBAEC;IAuGD;;;OAGG;IACH,uBAFW,MAAM,QAiFhB;IAED,cAWC;IAED,eAaC;IAED,aAYC;;CACJ;kBA3UiB,aAAa"}
|