@woosh/meep-engine 3.60.9 → 3.61.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.
- package/CHANGELOG.md +90 -0
- package/package.json +1 -1
- package/src/engine/ecs/EntityManager.d.ts +3 -3
- package/src/engine/ecs/EntityManager.js +3 -3
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +4 -0
- package/src/engine/graphics/ecs/decal/v2/Decal.d.ts +46 -2
- package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
- package/src/engine/graphics/ecs/decal/v2/Decal.js +74 -5
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.js +13 -1
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.d.ts +9 -0
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.d.ts.map +1 -0
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.js +37 -0
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem.js +462 -447
- package/src/engine/graphics3/decal/DECAL_GPU_RECORD.d.ts +14 -0
- package/src/engine/graphics3/decal/DECAL_GPU_RECORD.d.ts.map +1 -1
- package/src/engine/graphics3/decal/DECAL_GPU_RECORD.js +53 -13
- package/src/engine/graphics3/decal/chunk_decal_record.d.ts +6 -1
- package/src/engine/graphics3/decal/chunk_decal_record.d.ts.map +1 -1
- package/src/engine/graphics3/decal/chunk_decal_record.js +28 -9
- package/src/engine/graphics3/decal/decal_gpu_records.d.ts +2 -1
- package/src/engine/graphics3/decal/decal_gpu_records.d.ts.map +1 -1
- package/src/engine/graphics3/decal/decal_gpu_records.js +26 -5
- package/src/engine/graphics3/decal/decal_material_samplers.d.ts +6 -0
- package/src/engine/graphics3/decal/decal_material_samplers.d.ts.map +1 -1
- package/src/engine/graphics3/decal/decal_material_samplers.js +13 -0
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +1 -1
- package/src/engine/graphics3/decal/shader_cull_decals_frustum.js +1 -1
- package/src/engine/graphics3/decal/shader_decal_composite.d.ts +5 -0
- package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_decal_composite.js +69 -28
- package/src/engine/network/NetworkSession.d.ts +3 -0
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +68 -10
- package/src/engine/network/README.md +6 -3
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +51 -5
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +308 -34
- package/src/engine/network/replication/Replicator.d.ts +8 -2
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +13 -4
- package/src/engine/network/sim/ActionLog.d.ts +16 -2
- package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
- package/src/engine/network/sim/ActionLog.js +33 -2
- package/src/engine/network/sim/RewindEngine.d.ts +9 -0
- package/src/engine/network/sim/RewindEngine.d.ts.map +1 -1
- package/src/engine/network/sim/RewindEngine.js +15 -1
- package/src/engine/network/state/FrameBufferRing.d.ts +12 -5
- package/src/engine/network/state/FrameBufferRing.d.ts.map +1 -1
- package/src/engine/network/state/FrameBufferRing.js +32 -6
- package/src/engine/network/time/TimeDilation.d.ts +30 -14
- package/src/engine/network/time/TimeDilation.d.ts.map +1 -1
- package/src/engine/network/time/TimeDilation.js +47 -17
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/generation/foliage/skeleton/ShootWoodHash.d.ts +3 -2
- package/src/generation/foliage/skeleton/ShootWoodHash.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/ShootWoodHash.js +25 -2
- package/src/shade/renderer/buffer/graph_read_buffer.d.ts +3 -1
- package/src/shade/renderer/buffer/graph_read_buffer.d.ts.map +1 -1
- package/src/shade/renderer/buffer/graph_read_buffer.js +9 -6
- package/src/shade/renderer/buffer/util/shader_buffer_copy_storage_to_storage.d.ts +5 -0
- package/src/shade/renderer/buffer/util/shader_buffer_copy_storage_to_storage.d.ts.map +1 -1
- package/src/shade/renderer/buffer/util/shader_buffer_copy_storage_to_storage.js +48 -43
- package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
- package/src/shade/renderer/material/GPUMaterialManager.js +117 -35
- package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts +2 -2
- package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
- package/src/shade/renderer/material/standard/fragment_gbuffer.js +10 -3
- package/src/shade/renderer/material/standard/material_gbuffer_vertex.d.ts +15 -3
- package/src/shade/renderer/material/standard/material_gbuffer_vertex.d.ts.map +1 -1
- package/src/shade/renderer/material/standard/material_gbuffer_vertex.js +25 -4
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +23 -5
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +294 -20
- package/src/shade/renderer/particles/resize/shader_particle_shrink_alive_list.d.ts +21 -0
- package/src/shade/renderer/particles/resize/shader_particle_shrink_alive_list.d.ts.map +1 -0
- package/src/shade/renderer/particles/resize/shader_particle_shrink_alive_list.js +83 -0
- package/src/shade/renderer/particles/resize/shader_particle_shrink_free_list.d.ts +21 -0
- package/src/shade/renderer/particles/resize/shader_particle_shrink_free_list.d.ts.map +1 -0
- package/src/shade/renderer/particles/resize/shader_particle_shrink_free_list.js +64 -0
- package/src/shade/renderer/restir/di/chunk_restir_resolve.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/chunk_restir_resolve.js +91 -94
- package/src/shade/renderer/restir/reservoir/chunk_rtxdi_stream_sample.js +1 -1
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.d.ts +14 -0
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.js +36 -21
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.js +64 -0
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.js +13 -18
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.js +28 -30
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_u32_to_vec2.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_u32_to_vec2.js +15 -16
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.d.ts +0 -1
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.js +15 -18
- package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_bitset_or.d.ts +32 -0
- package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_bitset_or.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_bitset_or.js +73 -0
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +8 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +7 -3
- package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.d.ts +0 -2
- package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.d.ts.map +0 -1
- package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.js +0 -6
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assert } from "../../../core/assert.js";
|
|
2
2
|
import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
|
|
3
|
+
import { PairUint32Map } from "../../../core/collection/PairUint32Map.js";
|
|
3
4
|
import { Uint32Map } from "../../../core/collection/Uint32Map.js";
|
|
4
5
|
import Signal from "../../../core/events/signal/Signal.js";
|
|
5
6
|
import { AlwaysRelevantScope } from "../replication/ScopeFilter.js";
|
|
@@ -74,6 +75,27 @@ const HARVEST_STRIDE = 4;
|
|
|
74
75
|
* third. Here the authored half is `onReplay`'s job and the arrived half is
|
|
75
76
|
* this one's.
|
|
76
77
|
*
|
|
78
|
+
* - Records that arrive from a peer for a frame this client has already
|
|
79
|
+
* predicted past belong in that frame, under the prediction since, and
|
|
80
|
+
* before the frame's corrections, which already hold what they did. The
|
|
81
|
+
* frames after it were predicted without them and hold the prior state they
|
|
82
|
+
* captured then, so a rewind across those frames would put back what the
|
|
83
|
+
* records changed — a rewind about any other entity included. Where the
|
|
84
|
+
* records write something a frame after theirs, or a correction of their
|
|
85
|
+
* own frame, holds prior state of, the client takes them back off the
|
|
86
|
+
* world, rewinds to the end of their frame and back past its corrections,
|
|
87
|
+
* applies them there, the corrections after them, and replays what came
|
|
88
|
+
* after, as a reconciliation replays. Records about nothing written since
|
|
89
|
+
* stay where they landed: for everything they write, the present still holds
|
|
90
|
+
* what the end of their frame held. The test is on what records write, not
|
|
91
|
+
* what they read: one that only reads state written since — copying a
|
|
92
|
+
* predicted value into an entity nothing else writes — keeps what it read at
|
|
93
|
+
* the present until a replay crosses its frame. The replay is a
|
|
94
|
+
* reconciliation's, so a local record {@link onReplay} does not produce is
|
|
95
|
+
* lost from the frames it rebuilds. Records for a frame the action log has
|
|
96
|
+
* moved past have no frame to go in: they are applied where they land, and
|
|
97
|
+
* not logged.
|
|
98
|
+
*
|
|
77
99
|
* - A no-op short-circuit is built in: before doing the rewind+replay, the
|
|
78
100
|
* orchestrator gives the user a chance to compute what the replay WOULD
|
|
79
101
|
* produce via {@link onComputeExpected}; if that matches the current
|
|
@@ -138,11 +160,25 @@ export class ServerAuthoritativeClient {
|
|
|
138
160
|
*/
|
|
139
161
|
#correction_payload = new BinaryBuffer();
|
|
140
162
|
|
|
163
|
+
/**
|
|
164
|
+
* The `(entity, component type)` pairs that state written after an arrived frame's records holds
|
|
165
|
+
* prior state of — what those records are checked against. Filled by
|
|
166
|
+
* {@link #overwrites_later_state}.
|
|
167
|
+
* @type {PairUint32Map}
|
|
168
|
+
*/
|
|
169
|
+
#written_later = new PairUint32Map();
|
|
170
|
+
|
|
171
|
+
/** @type {ActionRecordCursor} */
|
|
172
|
+
#arrival_cursor = new ActionRecordCursor();
|
|
173
|
+
|
|
141
174
|
// Counters
|
|
142
175
|
/** @type {number} */
|
|
143
176
|
reconcile_count = 0;
|
|
144
177
|
|
|
145
|
-
/**
|
|
178
|
+
/**
|
|
179
|
+
* Frames replayed, by reconciliations and by records put back in their frame.
|
|
180
|
+
* @type {number}
|
|
181
|
+
*/
|
|
146
182
|
replay_frame_count = 0;
|
|
147
183
|
|
|
148
184
|
/**
|
|
@@ -161,6 +197,14 @@ export class ServerAuthoritativeClient {
|
|
|
161
197
|
*/
|
|
162
198
|
reconcile_abandoned_count = 0;
|
|
163
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Frames of records from a peer that arrived after this client had predicted past them, wrote
|
|
202
|
+
* something written later — in a frame after theirs, or by a correction of their own — and so
|
|
203
|
+
* were put back in their frame by a rewind and a replay. See {@link #land_arrived}.
|
|
204
|
+
* @type {number}
|
|
205
|
+
*/
|
|
206
|
+
rebase_count = 0;
|
|
207
|
+
|
|
164
208
|
/**
|
|
165
209
|
* @param {{
|
|
166
210
|
* world: EntityComponentDataset,
|
|
@@ -176,6 +220,7 @@ export class ServerAuthoritativeClient {
|
|
|
176
220
|
* time_dilation?: TimeDilation,
|
|
177
221
|
* max_packets_per_tick?: number,
|
|
178
222
|
* auto_reconcile?: boolean,
|
|
223
|
+
* rebase_on_arrival?: boolean,
|
|
179
224
|
* clock: function(): number,
|
|
180
225
|
* tick_period_ms: number,
|
|
181
226
|
* send_rate_bytes_per_second?: number,
|
|
@@ -189,8 +234,8 @@ export class ServerAuthoritativeClient {
|
|
|
189
234
|
* `time_dilation`: optional pre-configured {@link TimeDilation}.
|
|
190
235
|
* On TIME_DILATION feedback the client recomputes
|
|
191
236
|
* {@link dilation_factor} for the caller to scale its tick cadence.
|
|
192
|
-
* Defaults to
|
|
193
|
-
* first feedback arrives.
|
|
237
|
+
* Defaults to one built for round trips up to `frame_capacity` frames;
|
|
238
|
+
* `dilation_factor` is 1.0 until the first feedback arrives.
|
|
194
239
|
*
|
|
195
240
|
* `max_packets_per_tick`: forwarded to {@link NetworkPeer}; how many
|
|
196
241
|
* action-stream packets a tick may send the server.
|
|
@@ -200,6 +245,13 @@ export class ServerAuthoritativeClient {
|
|
|
200
245
|
* own reconciliation — `NetworkSession` corrects by comparison instead —
|
|
201
246
|
* turns it off and listens to `peer.onAuthState` itself; {@link reconcile}
|
|
202
247
|
* remains available to it.
|
|
248
|
+
*
|
|
249
|
+
* `rebase_on_arrival` (default true): put the records a peer sends for a
|
|
250
|
+
* frame this client has already predicted past in that frame, under what it
|
|
251
|
+
* predicted since, by rewind and replay — see the class notes. It keeps the
|
|
252
|
+
* log true for the rewinds this client reconciles by. A caller that never
|
|
253
|
+
* rewinds — `NetworkSession` correcting by comparison — turns it off, and
|
|
254
|
+
* the records are applied to the world as it is when they arrive.
|
|
203
255
|
*/
|
|
204
256
|
constructor({
|
|
205
257
|
world,
|
|
@@ -212,9 +264,10 @@ export class ServerAuthoritativeClient {
|
|
|
212
264
|
input_ring_capacity = 256,
|
|
213
265
|
input_byte_size = 4,
|
|
214
266
|
reconcile_epsilon = 1e-4,
|
|
215
|
-
time_dilation = new TimeDilation(),
|
|
267
|
+
time_dilation = new TimeDilation({ max_round_trip_frames: frame_capacity }),
|
|
216
268
|
max_packets_per_tick,
|
|
217
269
|
auto_reconcile = true,
|
|
270
|
+
rebase_on_arrival = true,
|
|
218
271
|
clock,
|
|
219
272
|
tick_period_ms,
|
|
220
273
|
send_rate_bytes_per_second,
|
|
@@ -294,7 +347,10 @@ export class ServerAuthoritativeClient {
|
|
|
294
347
|
/**
|
|
295
348
|
* Tick-period multiplier from the latest TIME_DILATION feedback.
|
|
296
349
|
* `< 1.0` ⇒ caller should run faster, `> 1.0` ⇒ slower. 1.0 until
|
|
297
|
-
* the first feedback arrives.
|
|
350
|
+
* the first feedback arrives. It follows every report, and holds while
|
|
351
|
+
* none come: a caller that seeks its frames back, or loses the host,
|
|
352
|
+
* judges whether the latest report still holds before running at it, as
|
|
353
|
+
* `NetworkSession` does.
|
|
298
354
|
*
|
|
299
355
|
* scheduled_tick_period_ms = TICK_PERIOD_MS * client.dilation_factor;
|
|
300
356
|
*
|
|
@@ -401,6 +457,9 @@ export class ServerAuthoritativeClient {
|
|
|
401
457
|
* longer holds the frames its rewind needed. Args:
|
|
402
458
|
* `(server_frame, network_id)`.
|
|
403
459
|
*
|
|
460
|
+
* Nothing of it is done: the world stays at the present, and the
|
|
461
|
+
* server's state is not applied.
|
|
462
|
+
*
|
|
404
463
|
* This is a real loss of replicated state and not a hiccup: state a peer
|
|
405
464
|
* does not own reaches it on the action stream, and an owner that
|
|
406
465
|
* publishes on change never sends it again — so whatever that window
|
|
@@ -426,6 +485,12 @@ export class ServerAuthoritativeClient {
|
|
|
426
485
|
this.#handle_auth_state(server_frame, network_id, buffer);
|
|
427
486
|
});
|
|
428
487
|
}
|
|
488
|
+
|
|
489
|
+
if (rebase_on_arrival) {
|
|
490
|
+
this.peer.replicator.onFrameApplied.add((_peer_id, frame, records_start) => {
|
|
491
|
+
this.#land_arrived(frame, records_start);
|
|
492
|
+
});
|
|
493
|
+
}
|
|
429
494
|
}
|
|
430
495
|
|
|
431
496
|
/**
|
|
@@ -617,21 +682,26 @@ export class ServerAuthoritativeClient {
|
|
|
617
682
|
to the same frame undid the first one's correction again.
|
|
618
683
|
*/
|
|
619
684
|
if (this.#current_frame > server_frame) {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
685
|
+
/*
|
|
686
|
+
The rewind undoes every frame after `server_frame`. Where the action
|
|
687
|
+
log no longer holds one of them, the window this reconciliation
|
|
688
|
+
needs is gone and skipping it is the only option left — found
|
|
689
|
+
before anything is undone, so the world stays at the present this
|
|
690
|
+
client predicts on from. Counted and announced rather than
|
|
691
|
+
swallowed: what the window carried for every entity other than this
|
|
692
|
+
one is gone for good, and an application that cannot see that
|
|
693
|
+
happen cannot ask for the back-fill that would repair it.
|
|
694
|
+
*/
|
|
695
|
+
const log = this.action_log;
|
|
696
|
+
for (let f = server_frame + 1; f <= this.#current_frame; f++) {
|
|
697
|
+
if (log.has_frame(f)) continue;
|
|
698
|
+
|
|
631
699
|
this.reconcile_abandoned_count++;
|
|
632
700
|
this.onReconcileAbandoned.send2(server_frame, network_id);
|
|
633
701
|
return;
|
|
634
702
|
}
|
|
703
|
+
|
|
704
|
+
this.rewind_engine.rewind_to(this.#current_frame, server_frame);
|
|
635
705
|
}
|
|
636
706
|
|
|
637
707
|
// Apply the server's authoritative state bytes, logged as a correction
|
|
@@ -639,12 +709,34 @@ export class ServerAuthoritativeClient {
|
|
|
639
709
|
// deserialize, and what it read is the correction.
|
|
640
710
|
this.#apply_correction(server_frame, network_id, local, buffer);
|
|
641
711
|
|
|
642
|
-
|
|
712
|
+
const replay_count = this.#replay(server_frame + 1);
|
|
713
|
+
|
|
714
|
+
this.reconcile_count++;
|
|
715
|
+
this.replay_frame_count += replay_count;
|
|
716
|
+
this.onReconcileComplete.send2(server_frame, replay_count);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Replay every frame from `from` through the current frame over the world as it stands, the end
|
|
721
|
+
* of frame `from - 1`: each frame's local input through {@link onReplay}, then the records that
|
|
722
|
+
* arrived from a peer, then corrections, last in their frame.
|
|
723
|
+
*
|
|
724
|
+
* Every frame is replayed whatever one of them throws: a frame that throws keeps what it applied
|
|
725
|
+
* before the throw, and its corrections; the first error is thrown once the world is back at the
|
|
726
|
+
* current frame. Stopped there instead, the world would be left in the past and the frames after
|
|
727
|
+
* it holding their old records, and the client would predict on from there.
|
|
728
|
+
*
|
|
729
|
+
* @param {number} from
|
|
730
|
+
* @returns {number} how many frames were replayed
|
|
731
|
+
* @private
|
|
732
|
+
*/
|
|
733
|
+
#replay(from) {
|
|
643
734
|
let replay_count = 0;
|
|
644
|
-
|
|
735
|
+
let failure = null;
|
|
736
|
+
for (let f = from; f <= this.#current_frame; f++) {
|
|
645
737
|
// Harvested before `begin_frame`, which rewinds the frame's buffer
|
|
646
738
|
// over the bytes being read.
|
|
647
|
-
const harvested = this.#harvest(f);
|
|
739
|
+
const harvested = this.#harvest(f, 0);
|
|
648
740
|
|
|
649
741
|
this.action_log.begin_frame(f);
|
|
650
742
|
try {
|
|
@@ -663,20 +755,194 @@ export class ServerAuthoritativeClient {
|
|
|
663
755
|
the one that should win where both touch a component.
|
|
664
756
|
*/
|
|
665
757
|
if (harvested > 0) {
|
|
666
|
-
this.#
|
|
667
|
-
|
|
668
|
-
// Last of all: a correction is the server's word on the END of its frame.
|
|
669
|
-
this.#reapply_corrections(f);
|
|
758
|
+
this.replayed_arrived_count += this.#apply_harvested(f);
|
|
670
759
|
}
|
|
760
|
+
} catch (e) {
|
|
761
|
+
if (failure === null) failure = e;
|
|
671
762
|
} finally {
|
|
672
763
|
this.action_log.end_frame();
|
|
673
764
|
}
|
|
674
765
|
replay_count++;
|
|
675
766
|
}
|
|
676
767
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
768
|
+
if (failure !== null) throw failure;
|
|
769
|
+
|
|
770
|
+
return replay_count;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Put the records a peer's frame has just had appended, from byte `arrived_start` on, where they
|
|
775
|
+
* belong on this client's timeline.
|
|
776
|
+
*
|
|
777
|
+
* The {@link Replicator} appends a peer's records to the frame the peer sent them for, after
|
|
778
|
+
* whatever the frame holds, and applies them to the world as it is — on a client, usually some
|
|
779
|
+
* frames past that one. The records' prior state is then the present's, every frame after
|
|
780
|
+
* `frame` holds prior state captured before they arrived, and a correction already in `frame`
|
|
781
|
+
* stands before them where a replay would write it after them. Where none of that holds prior
|
|
782
|
+
* state of anything the records wrote — nothing written later wrote it — the present held what
|
|
783
|
+
* the end of `frame` held there, and they stay. Otherwise they are taken back off the world,
|
|
784
|
+
* which puts it back as the frames after `frame` left it; those frames are rewound to the end of
|
|
785
|
+
* `frame` and its corrections undone; the records are applied there, the corrections after them,
|
|
786
|
+
* and what this client predicted since is replayed over them.
|
|
787
|
+
*
|
|
788
|
+
* A record that throws where it belongs is left out of the frame, as the executor leaves out any
|
|
789
|
+
* action that throws. The frame keeps its corrections, the world is brought back to the present
|
|
790
|
+
* all the same, and the error is thrown after.
|
|
791
|
+
*
|
|
792
|
+
* Records for a frame the log has moved past, which it applied without logging, and records for
|
|
793
|
+
* a frame the log no longer holds the frames after, are left where they landed: a rewind could
|
|
794
|
+
* not cross them either.
|
|
795
|
+
*
|
|
796
|
+
* @param {number} frame
|
|
797
|
+
* @param {number} arrived_start where in the frame the records just appended begin
|
|
798
|
+
* @private
|
|
799
|
+
*/
|
|
800
|
+
#land_arrived(frame, arrived_start) {
|
|
801
|
+
const present = this.#current_frame;
|
|
802
|
+
if (frame >= present) return;
|
|
803
|
+
|
|
804
|
+
const log = this.action_log;
|
|
805
|
+
for (let f = frame; f <= present; f++) {
|
|
806
|
+
if (!log.has_frame(f)) return;
|
|
807
|
+
}
|
|
808
|
+
if (arrived_start >= log.write_end_for(frame)) return;
|
|
809
|
+
|
|
810
|
+
// Before the records just appended: this client's own records, then what a replay puts
|
|
811
|
+
// back — what arrived before them, if their frame was applied before, and the corrections.
|
|
812
|
+
const cursor = this.#arrival_cursor;
|
|
813
|
+
let tail_start = arrived_start;
|
|
814
|
+
cursor.open(log, frame);
|
|
815
|
+
while (cursor.next() && cursor.record_start < arrived_start) {
|
|
816
|
+
const sender_id = cursor.sender_id;
|
|
817
|
+
if (sender_id === SENDER_CORRECTED || this.peer.is_connected(sender_id)) {
|
|
818
|
+
tail_start = cursor.record_start;
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (!this.#overwrites_later_state(frame, tail_start, arrived_start)) return;
|
|
824
|
+
|
|
825
|
+
// Copies of the frame's tail — its corrections, then the records just appended — taken
|
|
826
|
+
// before any of it is written over.
|
|
827
|
+
this.#harvest(frame, tail_start);
|
|
828
|
+
|
|
829
|
+
// The records just appended, off the world and off the frame: the world is the present as
|
|
830
|
+
// the frames after `frame` left it, and the frame is what it was before they came.
|
|
831
|
+
this.rewind_engine.undo_frame_from(frame, arrived_start);
|
|
832
|
+
log.resume_frame_at(frame, arrived_start);
|
|
833
|
+
log.end_frame();
|
|
834
|
+
|
|
835
|
+
// To the end of the frame, and back past its corrections.
|
|
836
|
+
this.rewind_engine.rewind_to(present, frame);
|
|
837
|
+
this.rewind_engine.undo_frame_from(frame, tail_start);
|
|
838
|
+
|
|
839
|
+
// The tail again, in the order a replay writes a frame: what arrived, then the corrections.
|
|
840
|
+
// Then forward to the present whatever became of the records: a world left in the past would
|
|
841
|
+
// be predicted on from there.
|
|
842
|
+
let failure = null;
|
|
843
|
+
log.resume_frame_at(frame, tail_start);
|
|
844
|
+
try {
|
|
845
|
+
this.#apply_harvested(frame);
|
|
846
|
+
} catch (e) {
|
|
847
|
+
failure = e;
|
|
848
|
+
} finally {
|
|
849
|
+
log.end_frame();
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
this.replay_frame_count += this.#replay(frame + 1);
|
|
853
|
+
this.rebase_count++;
|
|
854
|
+
|
|
855
|
+
if (failure !== null) throw failure;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Whether the records from byte `arrived_start` on in `frame` write anything that state written
|
|
860
|
+
* after them holds prior state of: a correction in the frame from `tail_start` up to them, which
|
|
861
|
+
* a replay writes after them, and any record in a frame after `frame`.
|
|
862
|
+
*
|
|
863
|
+
* @param {number} frame
|
|
864
|
+
* @param {number} tail_start
|
|
865
|
+
* @param {number} arrived_start
|
|
866
|
+
* @returns {boolean}
|
|
867
|
+
* @private
|
|
868
|
+
*/
|
|
869
|
+
#overwrites_later_state(frame, tail_start, arrived_start) {
|
|
870
|
+
const later = this.#written_later;
|
|
871
|
+
later.clear();
|
|
872
|
+
|
|
873
|
+
const cursor = this.#arrival_cursor;
|
|
874
|
+
|
|
875
|
+
cursor.open(this.action_log, frame);
|
|
876
|
+
while (cursor.next() && cursor.record_start < arrived_start) {
|
|
877
|
+
if (cursor.record_start >= tail_start && cursor.sender_id === SENDER_CORRECTED) {
|
|
878
|
+
this.#collect_prior_entries(cursor, later);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
for (let f = frame + 1; f <= this.#current_frame; f++) {
|
|
883
|
+
cursor.open(this.action_log, f);
|
|
884
|
+
while (cursor.next()) {
|
|
885
|
+
this.#collect_prior_entries(cursor, later);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
if (later.size === 0) return false;
|
|
890
|
+
|
|
891
|
+
cursor.open(this.action_log, frame);
|
|
892
|
+
while (cursor.next()) {
|
|
893
|
+
if (cursor.record_start < arrived_start) continue;
|
|
894
|
+
|
|
895
|
+
const buffer = cursor.buffer;
|
|
896
|
+
buffer.position = cursor.prior_start;
|
|
897
|
+
for (let i = 0; i < cursor.prior_count; i++) {
|
|
898
|
+
const entity_id = buffer.readUintVar();
|
|
899
|
+
const component_type_id = buffer.readUint8();
|
|
900
|
+
buffer.position += buffer.readUint32();
|
|
901
|
+
|
|
902
|
+
if (later.has(entity_id, component_type_id)) return true;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* Add the `(entity, component type)` of every prior-state entry of the record under `cursor`
|
|
911
|
+
* that captured something to `into` — an entry that captured nothing puts nothing back.
|
|
912
|
+
*
|
|
913
|
+
* @param {ActionRecordCursor} cursor
|
|
914
|
+
* @param {PairUint32Map} into
|
|
915
|
+
* @private
|
|
916
|
+
*/
|
|
917
|
+
#collect_prior_entries(cursor, into) {
|
|
918
|
+
const buffer = cursor.buffer;
|
|
919
|
+
buffer.position = cursor.prior_start;
|
|
920
|
+
for (let i = 0; i < cursor.prior_count; i++) {
|
|
921
|
+
const entity_id = buffer.readUintVar();
|
|
922
|
+
const component_type_id = buffer.readUint8();
|
|
923
|
+
const prior_length = buffer.readUint32();
|
|
924
|
+
buffer.position += prior_length;
|
|
925
|
+
|
|
926
|
+
if (prior_length > 0) into.set(entity_id, component_type_id, 1);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* Apply what {@link #harvest} took from `frame` into it, open: the records that arrived from a
|
|
932
|
+
* peer, then the corrections, last — those whatever the records do, since the frame has been
|
|
933
|
+
* opened over them and they live nowhere else.
|
|
934
|
+
*
|
|
935
|
+
* @param {number} frame
|
|
936
|
+
* @returns {number} how many arrived records were applied
|
|
937
|
+
* @private
|
|
938
|
+
*/
|
|
939
|
+
#apply_harvested(frame) {
|
|
940
|
+
try {
|
|
941
|
+
return this.#execute_harvested();
|
|
942
|
+
} finally {
|
|
943
|
+
// Last of all: a correction is the server's word on the END of its frame.
|
|
944
|
+
this.#reapply_corrections(frame);
|
|
945
|
+
}
|
|
680
946
|
}
|
|
681
947
|
|
|
682
948
|
/**
|
|
@@ -769,12 +1035,13 @@ export class ServerAuthoritativeClient {
|
|
|
769
1035
|
}
|
|
770
1036
|
|
|
771
1037
|
/**
|
|
772
|
-
* Copy the records of `frame` that a replay puts back out
|
|
773
|
-
* log, ready for {@link #execute_harvested} and
|
|
1038
|
+
* Copy the records of `frame` from byte `from` on that a replay puts back out
|
|
1039
|
+
* of the action log, ready for {@link #execute_harvested} and
|
|
1040
|
+
* {@link #reapply_corrections}.
|
|
774
1041
|
*
|
|
775
|
-
* MUST be called before
|
|
776
|
-
* rewinds its buffer
|
|
777
|
-
*
|
|
1042
|
+
* MUST be called before the frame is opened over them. Opening a frame
|
|
1043
|
+
* rewinds its buffer without clearing it, and the re-execution writes over
|
|
1044
|
+
* exactly the bytes this reads, so the payloads are copied into
|
|
778
1045
|
* {@link #harvest_payloads} rather than read in place.
|
|
779
1046
|
*
|
|
780
1047
|
* Provenance decides what a replay does with a record, and this client keeps
|
|
@@ -797,10 +1064,11 @@ export class ServerAuthoritativeClient {
|
|
|
797
1064
|
* itself, so its own records can never match.
|
|
798
1065
|
*
|
|
799
1066
|
* @param {number} frame
|
|
1067
|
+
* @param {number} from offset of the first record looked at, a record boundary in the frame
|
|
800
1068
|
* @returns {number} how many records were harvested
|
|
801
1069
|
* @private
|
|
802
1070
|
*/
|
|
803
|
-
#harvest(frame) {
|
|
1071
|
+
#harvest(frame, from) {
|
|
804
1072
|
this.#harvest_count = 0;
|
|
805
1073
|
this.#harvest_payloads.position = 0;
|
|
806
1074
|
|
|
@@ -811,6 +1079,8 @@ export class ServerAuthoritativeClient {
|
|
|
811
1079
|
const bytes = cursor.buffer.raw_bytes;
|
|
812
1080
|
|
|
813
1081
|
while (cursor.next()) {
|
|
1082
|
+
if (cursor.record_start < from) continue;
|
|
1083
|
+
|
|
814
1084
|
const sender_id = cursor.sender_id;
|
|
815
1085
|
if (sender_id !== SENDER_CORRECTED && !this.peer.is_connected(sender_id)) continue;
|
|
816
1086
|
|
|
@@ -841,10 +1111,12 @@ export class ServerAuthoritativeClient {
|
|
|
841
1111
|
* A record whose action class is no longer registered is skipped — the same
|
|
842
1112
|
* thing `Replicator.#apply_groups` does on the way in.
|
|
843
1113
|
*
|
|
1114
|
+
* @returns {number} how many were applied
|
|
844
1115
|
* @private
|
|
845
1116
|
*/
|
|
846
1117
|
#execute_harvested() {
|
|
847
1118
|
const payloads = this.#harvest_payloads;
|
|
1119
|
+
let applied = 0;
|
|
848
1120
|
|
|
849
1121
|
for (let record = 0; record < this.#harvest_count; record++) {
|
|
850
1122
|
const i = record * HARVEST_STRIDE;
|
|
@@ -862,14 +1134,16 @@ export class ServerAuthoritativeClient {
|
|
|
862
1134
|
action.deserialize(payloads);
|
|
863
1135
|
// `execute` returns false when an authorization policy rejects
|
|
864
1136
|
// the action, in which case nothing was applied or logged — so
|
|
865
|
-
// the
|
|
1137
|
+
// the count follows the return value rather than the attempt.
|
|
866
1138
|
if (this.executor.execute(action, sender_id)) {
|
|
867
|
-
|
|
1139
|
+
applied++;
|
|
868
1140
|
}
|
|
869
1141
|
} finally {
|
|
870
1142
|
this.action_registry.release(action);
|
|
871
1143
|
}
|
|
872
1144
|
}
|
|
1145
|
+
|
|
1146
|
+
return applied;
|
|
873
1147
|
}
|
|
874
1148
|
|
|
875
1149
|
/**
|
|
@@ -90,7 +90,11 @@ export class Replicator {
|
|
|
90
90
|
};
|
|
91
91
|
/**
|
|
92
92
|
* Fired after each per-frame action group is fully applied via
|
|
93
|
-
* {@link unpack_from_peer}. Args: `(peer_id, frame_number)
|
|
93
|
+
* {@link unpack_from_peer}. Args: `(peer_id, frame_number, records_start)`:
|
|
94
|
+
* the records just applied are logged in the action log's frame from
|
|
95
|
+
* byte `records_start` to its end, after whatever it held before. A frame
|
|
96
|
+
* the action log has moved past is applied without being logged, and the
|
|
97
|
+
* log does not hold it.
|
|
94
98
|
*
|
|
95
99
|
* Subscribe to drive interpolation buffers, replay logs, diagnostics,
|
|
96
100
|
* or anything else that needs to know "frame N from peer P has just
|
|
@@ -177,7 +181,9 @@ export class Replicator {
|
|
|
177
181
|
* Parse and apply actions from `in_buffer` into the local world via the executor.
|
|
178
182
|
* Each frame in the packet opens a new entry in the local action log under the
|
|
179
183
|
* sender's frame number, ensuring the rewind/replay machinery sees consistent
|
|
180
|
-
* frame indexing across peers.
|
|
184
|
+
* frame indexing across peers. A frame the log has moved past — older than the
|
|
185
|
+
* frame its slot holds — is applied to the world as it stands and not logged:
|
|
186
|
+
* no rewind reaches it, and logging it would erase that later frame.
|
|
181
187
|
*
|
|
182
188
|
* `slice` is the sender's description of the packet, from the
|
|
183
189
|
* {@link NetworkPeer} slice header: the frame range it covers and whether
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Replicator.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/replication/Replicator.js"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH;
|
|
1
|
+
{"version":3,"file":"Replicator.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/replication/Replicator.js"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH;IAuLI;;;;;;;;OAQG;IACH,iFARW;QACV,UAAc,YAAY;QAC1B,eAAmB,oBAAoB;QACvC,QAAY,oBAAoB;QAChC,UAAc,uBAAuB;QACrC,YAAgB,EAAE;YAAE,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC;KACpF,EA6BH;IAlJD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,wBAHW,MAAM,GACJ;QAAC,iBAAiB,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAC,CAc1F;IA2BD;;;;;;;;;;;;;;;;;OAiBG;IACH,gBAFU,MAAM,CAEc;IAE9B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,mBAFU,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAExJ;IAmBrB;;OAEG;IACH,sBAA4B;IAE5B;;OAEG;IACH,mCAAsC;IAEtC;;OAEG;IACH,4BAAwB;IAExB;;OAEG;IACH,iCAA4B;IAE5B;;;;OAIG;IACH,cAFU;QAAE,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAE9C;IAGpC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,uBAVW,MAAM,eACN,MAAM,aACN,MAAM,cACN,YAAY,cACZ,MAAM,GACJ,MAAM,CA0FlB;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;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,QA2EtE;IAkSD;;;;;;;OAOG;IACH,qBAFW,MAAM,QAKhB;;CA8CJ;mBAx0BkB,uCAAuC;6BAD7B,sCAAsC"}
|
|
@@ -200,7 +200,11 @@ export class Replicator {
|
|
|
200
200
|
|
|
201
201
|
/**
|
|
202
202
|
* Fired after each per-frame action group is fully applied via
|
|
203
|
-
* {@link unpack_from_peer}. Args: `(peer_id, frame_number)
|
|
203
|
+
* {@link unpack_from_peer}. Args: `(peer_id, frame_number, records_start)`:
|
|
204
|
+
* the records just applied are logged in the action log's frame from
|
|
205
|
+
* byte `records_start` to its end, after whatever it held before. A frame
|
|
206
|
+
* the action log has moved past is applied without being logged, and the
|
|
207
|
+
* log does not hold it.
|
|
204
208
|
*
|
|
205
209
|
* Subscribe to drive interpolation buffers, replay logs, diagnostics,
|
|
206
210
|
* or anything else that needs to know "frame N from peer P has just
|
|
@@ -396,7 +400,9 @@ export class Replicator {
|
|
|
396
400
|
* Parse and apply actions from `in_buffer` into the local world via the executor.
|
|
397
401
|
* Each frame in the packet opens a new entry in the local action log under the
|
|
398
402
|
* sender's frame number, ensuring the rewind/replay machinery sees consistent
|
|
399
|
-
* frame indexing across peers.
|
|
403
|
+
* frame indexing across peers. A frame the log has moved past — older than the
|
|
404
|
+
* frame its slot holds — is applied to the world as it stands and not logged:
|
|
405
|
+
* no rewind reaches it, and logging it would erase that later frame.
|
|
400
406
|
*
|
|
401
407
|
* `slice` is the sender's description of the packet, from the
|
|
402
408
|
* {@link NetworkPeer} slice header: the frame range it covers and whether
|
|
@@ -576,7 +582,10 @@ export class Replicator {
|
|
|
576
582
|
}
|
|
577
583
|
|
|
578
584
|
// After what the frame already holds: on a client this frame is usually one it has
|
|
579
|
-
// already predicted, and its own records are what a rewind undoes.
|
|
585
|
+
// already predicted, and its own records are what a rewind undoes. A frame the log has
|
|
586
|
+
// moved past is not logged at all (ActionLog.resume_frame): the frame in its slot is
|
|
587
|
+
// one of this peer's own.
|
|
588
|
+
const records_start = this.action_log.has_frame(frame_number) ? this.action_log.write_end_for(frame_number) : 0;
|
|
580
589
|
this.action_log.resume_frame(frame_number);
|
|
581
590
|
try {
|
|
582
591
|
for (let i = 0; i < action_count; i++) {
|
|
@@ -651,7 +660,7 @@ export class Replicator {
|
|
|
651
660
|
|
|
652
661
|
// Fire AFTER end_frame so handlers see consistent state and can
|
|
653
662
|
// safely query the action log for the just-applied frame.
|
|
654
|
-
this.onFrameApplied.
|
|
663
|
+
this.onFrameApplied.send3(peer_id, frame_number, records_start);
|
|
655
664
|
}
|
|
656
665
|
|
|
657
666
|
return last_frame;
|
|
@@ -76,17 +76,31 @@ export class ActionLog {
|
|
|
76
76
|
begin_frame(frame: number): void;
|
|
77
77
|
/**
|
|
78
78
|
* Open a frame for writing after the records it already holds, rather than over them. A frame
|
|
79
|
-
* the ring does not hold is opened empty, as {@link begin_frame} opens it
|
|
79
|
+
* the ring does not hold is opened empty, as {@link begin_frame} opens it — unless the log has
|
|
80
|
+
* moved past it, its slot holding a later frame: the later frame keeps its records, and what is
|
|
81
|
+
* written for this one is dropped at {@link end_frame}.
|
|
80
82
|
*
|
|
81
83
|
* For a writer adding to a frame someone else wrote: records arriving from a peer for a frame
|
|
82
84
|
* this peer has already simulated. Opened with {@link begin_frame} instead, they would erase
|
|
83
85
|
* this peer's own records for the frame — and with them the prior state a rewind needs to undo
|
|
84
86
|
* that input, so a replay would apply it a second time, and the outbound stream, which packs
|
|
85
|
-
* from this log, would lose it before the peer it was for had confirmed it.
|
|
87
|
+
* from this log, would lose it before the peer it was for had confirmed it. A frame the log has
|
|
88
|
+
* moved past would erase the later frame's records the same way.
|
|
86
89
|
*
|
|
87
90
|
* @param {number} frame absolute frame number
|
|
88
91
|
*/
|
|
89
92
|
resume_frame(frame: number): void;
|
|
93
|
+
/**
|
|
94
|
+
* Open a frame the log holds for writing from byte `offset` of what it holds: the records from
|
|
95
|
+
* there on are dropped, and what is written takes their place.
|
|
96
|
+
*
|
|
97
|
+
* For a writer that has taken records back off the world and writes them again — the frame's
|
|
98
|
+
* earlier records stay, the later ones are written over.
|
|
99
|
+
*
|
|
100
|
+
* @param {number} frame absolute frame number
|
|
101
|
+
* @param {number} offset a record boundary in the frame, at most its end
|
|
102
|
+
*/
|
|
103
|
+
resume_frame_at(frame: number, offset: number): void;
|
|
90
104
|
/**
|
|
91
105
|
* Drop every record the log holds, keeping each frame it holds present and empty.
|
|
92
106
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionLog.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/ActionLog.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH;IAoBI;;OAEG;IACH,qDAFW;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAE,EAIlE;IAED;;;OAGG;IACH,6BAEC;IAED;;;;OAIG;IACH,mBAFW,MAAM,QAShB;IAED
|
|
1
|
+
{"version":3,"file":"ActionLog.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/ActionLog.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH;IAoBI;;OAEG;IACH,qDAFW;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAE,EAIlE;IAED;;;OAGG;IACH,6BAEC;IAED;;;;OAIG;IACH,mBAFW,MAAM,QAShB;IAED;;;;;;;;;;;;;;OAcG;IACH,oBAFW,MAAM,QAShB;IAED;;;;;;;;;OASG;IACH,uBAHW,MAAM,UACN,MAAM,QAkBhB;IAED;;;;;;;;OAQG;IACH,qBAMC;IAED;;OAEG;IACH,kBASC;IAED;;;;;;OAMG;IACH,kBAFa,OAAO,CAInB;IAED;;;;OAIG;IACH,+BAMC;IAED;;;;;OAKG;IACH,iBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;;;;;;;;;OAWG;IACH,kBAHW,MAAM,gBAKhB;IAED;;;;OAIG;IACH,qBAHW,MAAM,GACJ,MAAM,CAIlB;;CACJ"}
|