dredless 0.6.3 → 0.7.0

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.
@@ -21,1000 +21,3 @@ export const LOADER_FILTER_MODE_NAMES = new Map([
21
21
  [2, "allow-filter"],
22
22
  [3, "block-all"]
23
23
  ]);
24
-
25
- const DEFAULT_LOADER_PRIORITY = 0;
26
- const DEFAULT_LOADER_FILTER_MODE = 0;
27
- const DEFAULT_LOADER_STACK = 16;
28
- const DEFAULT_LOADER_CYCLE = 1;
29
- const DEFAULT_LOADER_PICK = 3;
30
- const DEFAULT_LOADER_PLACE = 4;
31
- const LOADER_CONFIG_NUMERIC_BITS = [1, 2, 4, 8, 16];
32
- const LOADER_CONFIG_NUMERIC_FIELDS = ["q20", "q24", "q28", "q32", "q36"];
33
-
34
- export function wrapLoaderPosition(value) {
35
- return value == null ? null : ((value % 8) + 8) % 8;
36
- }
37
-
38
- export function enumName(map, value) {
39
- if (value == null) return "-";
40
- const name = map.get(value);
41
- return name == null ? String(value) : `${name}(${value})`;
42
- }
43
-
44
- export function decodeIndexedLoaderSnapshotRecord(loader, mask = 0, cumulative = null, reference = null) {
45
- const config = {
46
- pick: 3,
47
- place: 4,
48
- priority: DEFAULT_LOADER_PRIORITY,
49
- requireOutput: false,
50
- waitForStack: false,
51
- stack: DEFAULT_LOADER_STACK,
52
- cycle: DEFAULT_LOADER_CYCLE
53
- };
54
-
55
- if (mask & 32) config.requireOutput = true;
56
- if (mask & 64) config.waitForStack = true;
57
-
58
- switch (mask) {
59
- case 0:
60
- break;
61
- case 1:
62
- config.pick = wrapLoaderPosition((loader.q20 ?? 0) + 3);
63
- if (cumulative?.q40 != null) config.requireOutput = true;
64
- break;
65
- case 2:
66
- if (reference && cumulative?.q40 != null && loader.q24 != null) {
67
- if (loader.q24 <= -8) {
68
- config.pick = wrapLoaderPosition((reference.pick ?? 3) + 1);
69
- config.place = wrapLoaderPosition((reference.place ?? 4) + 3);
70
- config.requireOutput = true;
71
- } else {
72
- config.pick = wrapLoaderPosition((reference.pick ?? 3) + 2);
73
- config.place = wrapLoaderPosition((reference.place ?? 4) + 4);
74
- }
75
- } else {
76
- config.place = wrapLoaderPosition((loader.q24 ?? 0) + 4);
77
- }
78
- break;
79
- case 3:
80
- config.pick = reference && loader.q24 <= -8
81
- ? wrapLoaderPosition((reference.pick ?? 3) + (loader.q20 ?? 0) + 3)
82
- : wrapLoaderPosition((loader.q20 ?? 0) + 3);
83
- config.place = wrapLoaderPosition((loader.q24 ?? 0) + 4);
84
- // Some repeated full-snapshot rows keep flag state in the materialized
85
- // cumulative row while only sending pick/place deltas in the row mask.
86
- if (cumulative?.q44 != null && cumulative?.q36 == null && cumulative?.q40 == null) {
87
- config.requireOutput = true;
88
- config.waitForStack = true;
89
- }
90
- break;
91
- case 5:
92
- config.pick = wrapLoaderPosition((loader.q28 ?? 0) + 1);
93
- config.place = wrapLoaderPosition((loader.q28 ?? 0) + 3);
94
- break;
95
- case 6:
96
- config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 5);
97
- config.place = wrapLoaderPosition((loader.q24 ?? 0) + 3);
98
- config.requireOutput = true;
99
- break;
100
- case 7:
101
- if (reference && (cumulative?.q40 != null || loader.q24 <= -8 || loader.q28 >= 2)) {
102
- if (loader.q24 <= -8) {
103
- config.pick = wrapLoaderPosition((reference.pick ?? 3) + (loader.q20 ?? 0) + 5);
104
- config.place = wrapLoaderPosition(reference.place ?? 4);
105
- config.requireOutput = true;
106
- config.waitForStack = true;
107
- if (loader.q28 != null) config.priority = loader.q28;
108
- } else if (loader.q28 >= 2) {
109
- config.pick = wrapLoaderPosition((reference.pick ?? 3) + loader.q28);
110
- config.place = wrapLoaderPosition((reference.place ?? 4) + (loader.q20 ?? 0));
111
- config.priority = loader.q28 - 4;
112
- } else if ((loader.q20 ?? 0) >= 3) {
113
- config.pick = wrapLoaderPosition((reference.pick ?? 3) + (loader.q20 ?? 0));
114
- config.place = wrapLoaderPosition(reference.place ?? 4);
115
- config.priority = (loader.q28 ?? 0) + 1;
116
- config.requireOutput = Boolean(reference.requireOutput);
117
- config.waitForStack = Boolean(reference.waitForStack);
118
- } else {
119
- config.pick = wrapLoaderPosition((loader.q20 ?? 0) + 2);
120
- config.place = wrapLoaderPosition((reference.place ?? 4) + (loader.q24 ?? 0));
121
- config.priority = (loader.q28 ?? 0) + 1;
122
- }
123
- } else {
124
- config.pick = wrapLoaderPosition((loader.q20 ?? 0) + 3);
125
- config.place = wrapLoaderPosition((loader.q24 ?? 0) + 4);
126
- if (loader.q28 != null) config.priority = loader.q28;
127
- }
128
- break;
129
- case 8:
130
- config.pick = wrapLoaderPosition((cumulative?.q40 ?? 0) + 4);
131
- config.place = wrapLoaderPosition((cumulative?.q28 ?? 0) + 2);
132
- config.requireOutput = true;
133
- break;
134
- case 9:
135
- config.pick = wrapLoaderPosition((loader.q20 ?? 0) + 3);
136
- config.place = wrapLoaderPosition((cumulative?.q40 ?? 0) + 3);
137
- break;
138
- case 18:
139
- config.pick = wrapLoaderPosition(loader.q24 ?? 0);
140
- config.place = wrapLoaderPosition((loader.q36 ?? 0) + 2);
141
- if (loader.q36 != null) config.cycle = (loader.q36 / 20) + 1;
142
- break;
143
- case 32:
144
- break;
145
- case 65:
146
- config.pick = wrapLoaderPosition((loader.q44 ?? 0) + 3);
147
- break;
148
- case 33:
149
- config.pick = wrapLoaderPosition((loader.q40 ?? 0) + 3);
150
- config.place = wrapLoaderPosition((loader.q20 ?? 0) + 4);
151
- break;
152
- case 34:
153
- config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
154
- config.place = wrapLoaderPosition((loader.q40 ?? 0) + 4);
155
- break;
156
- case 35:
157
- config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
158
- config.place = wrapLoaderPosition((loader.q40 ?? 0) + 4);
159
- break;
160
- case 67:
161
- config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
162
- config.place = wrapLoaderPosition((loader.q44 ?? 0) + 4);
163
- break;
164
- case 95:
165
- config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
166
- config.place = wrapLoaderPosition((loader.q28 ?? 0) + 4);
167
- if (loader.q32 != null) config.priority = loader.q32;
168
- if (loader.q36 != null) config.stack = DEFAULT_LOADER_STACK + loader.q36;
169
- if (loader.q44 != null) config.cycle = (loader.q44 / 20) + 1;
170
- break;
171
- case 98:
172
- config.place = wrapLoaderPosition((loader.q40 ?? 0) + 4);
173
- break;
174
- case 99:
175
- config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
176
- config.place = wrapLoaderPosition((loader.q40 ?? 0) + 4);
177
- break;
178
- case 126:
179
- config.pick = wrapLoaderPosition(loader.q28 ?? 0);
180
- config.place = wrapLoaderPosition(loader.q24 ?? 0);
181
- if (loader.q32 != null) config.priority = loader.q32;
182
- if (loader.q36 != null) config.stack = DEFAULT_LOADER_STACK + loader.q36;
183
- if (loader.q40 != null) config.cycle = (loader.q40 / 20) + 1;
184
- break;
185
- default:
186
- return null;
187
- }
188
-
189
- return config;
190
- }
191
-
192
- export function decodeLoaderSnapshotRecord(loader, mask = loader?.lastMask ?? 0) {
193
- if (!loader) return null;
194
- const hasRequireOutput = Boolean(mask & 32);
195
- const hasWaitForStack = Boolean(mask & 64);
196
- const hasFlag = hasRequireOutput || hasWaitForStack;
197
- const slots = [];
198
-
199
- for (const [index, bit] of LOADER_CONFIG_NUMERIC_BITS.entries()) {
200
- if (!(mask & bit)) continue;
201
- const value = loader[LOADER_CONFIG_NUMERIC_FIELDS[index]];
202
- if (value == null) return null;
203
- slots.push(value);
204
- }
205
- if (hasRequireOutput) {
206
- if (loader.q40 == null) return null;
207
- slots.push(loader.q40);
208
- } else if (hasWaitForStack) {
209
- if (loader.q44 == null) return null;
210
- slots.push(loader.q44);
211
- }
212
-
213
- if (hasFlag && slots.length) slots.shift();
214
-
215
- const config = {
216
- pick: 3,
217
- place: 4,
218
- priority: DEFAULT_LOADER_PRIORITY,
219
- requireOutput: hasRequireOutput,
220
- waitForStack: hasWaitForStack,
221
- stack: DEFAULT_LOADER_STACK,
222
- cycle: DEFAULT_LOADER_CYCLE
223
- };
224
-
225
- if (mask & 1) {
226
- if (!slots.length) return null;
227
- config.pick = wrapLoaderPosition(slots.shift() + 3);
228
- }
229
- if (mask & 2) {
230
- if (!slots.length) return null;
231
- config.place = wrapLoaderPosition(slots.shift() + 4);
232
- }
233
- if (mask & 4) {
234
- if (!slots.length) return null;
235
- config.priority = slots.shift();
236
- }
237
- if (mask & 8) {
238
- if (!slots.length) return null;
239
- config.stack = DEFAULT_LOADER_STACK + slots.shift();
240
- }
241
- if (mask & 16) {
242
- if (!slots.length) return null;
243
- config.cycle = (slots.shift() / 20) + 1;
244
- }
245
-
246
- return config;
247
- }
248
-
249
- function decodeLoaderSemanticDeltaRecord(loader, mask = loader?.lastMask ?? 0) {
250
- if (!loader) return null;
251
- const hasRequireOutput = Boolean(mask & 32);
252
- const hasWaitForStack = Boolean(mask & 64);
253
- if (!hasRequireOutput && !hasWaitForStack) return null;
254
-
255
- const slots = [];
256
- for (const [index, bit] of LOADER_CONFIG_NUMERIC_BITS.entries()) {
257
- if (!(mask & bit)) continue;
258
- slots.push(loader[LOADER_CONFIG_NUMERIC_FIELDS[index]] ?? 0);
259
- }
260
- if (hasRequireOutput) slots.push(loader.q40 ?? 0);
261
- else if (hasWaitForStack) slots.push(loader.q44 ?? 0);
262
-
263
- if (slots.length) slots.shift();
264
-
265
- const config = {};
266
- if (mask & 1) config.pick = slots.shift() ?? 0;
267
- if (mask & 2) config.place = slots.shift() ?? 0;
268
- if (mask & 4) config.priority = slots.shift() ?? 0;
269
- if (mask & 8) config.stack = slots.shift() ?? 0;
270
- if (mask & 16) config.cycleTicks = slots.shift() ?? 0;
271
- config.requireOutput = hasRequireOutput;
272
- config.waitForStack = hasWaitForStack;
273
- return config;
274
- }
275
-
276
- function loaderDeltaRecord(loader, mask, previous) {
277
- const record = {lastMask: mask};
278
- for (const [field, bit] of [
279
- ["q20", 1],
280
- ["q24", 2],
281
- ["q28", 4],
282
- ["q32", 8],
283
- ["q36", 16],
284
- ["q40", 32],
285
- ["q44", 64]
286
- ]) {
287
- if (!(mask & bit)) continue;
288
- if (field === "q44" && ((mask & 32) || loader?.q44 == null)) continue;
289
- record[field] = (loader?.[field] ?? 0) - (previous?.[field] ?? 0);
290
- }
291
- return record;
292
- }
293
-
294
- function isSemanticLoaderDelta(changed, full) {
295
- return !full &&
296
- changed.previous != null &&
297
- (changed.mask & 96) === 96;
298
- }
299
-
300
- function filterSlotValue(value) {
301
- return value == null || value === 0 ? null : value;
302
- }
303
-
304
- export class LoaderConfigTracker {
305
- constructor() {
306
- this.pickBases = new Map();
307
- this.pickDeltaBases = new Map();
308
- this.placeBases = new Map();
309
- this.placeDeltaBases = new Map();
310
- this.currentPicks = new Map();
311
- this.currentPlaces = new Map();
312
- this.sparsePositionBaselines = new Set();
313
- this.priorities = new Map();
314
- this.priorityOffsets = new Map();
315
- this.filterModes = new Map();
316
- this.filterSources = new Map();
317
- this.requireOutputs = new Map();
318
- this.waitForStacks = new Map();
319
- this.stackBases = new Map();
320
- this.stackSources = new Map();
321
- this.cycles = new Map();
322
- this.cycleModes = new Map();
323
- this.cycleDeltaBases = new Map();
324
- this.directCycleValues = new Map();
325
- this.directCycleFields = new Map();
326
- }
327
-
328
- updateFromModel(update) {
329
- const world = update?.world;
330
- const model = update?.result?.model;
331
- if (!world || !model) return;
332
- const seenEntities = new Set();
333
- for (const section of model.sections || []) {
334
- if (section.table !== 78) continue;
335
- for (const changed of section.records || []) {
336
- if (changed.indexedLoaderConfig) {
337
- this.updateIndexedSnapshotRecord(world.id, changed.entity, changed.record, changed.mask, changed.cumulativeRecord, changed.configEntity);
338
- continue;
339
- }
340
- const loader = changed.record ?? world.model.record(78, changed.entity);
341
- this.updateRecord(world.id, changed.entity, loader, changed.mask, changed.previous, {
342
- repeatedInUpdate: seenEntities.has(changed.entity),
343
- repeatedInSection: changed.repeatedInSection,
344
- semanticSnapshot: Boolean(model.full),
345
- semanticDelta: isSemanticLoaderDelta(changed, model.full),
346
- deltaRecord: loaderDeltaRecord(loader, changed.mask, changed.previous)
347
- });
348
- seenEntities.add(changed.entity);
349
- }
350
- }
351
- }
352
-
353
- updateRecord(worldId, entityId, loader, mask = 0, previous = null, options = {}) {
354
- if (!loader) return;
355
- const key = this.#key(worldId, entityId);
356
- const hasTrackedConfig = this.#hasTrackedConfig(key);
357
- if (hasTrackedConfig &&
358
- (options.repeatedInSection || options.repeatedInUpdate) &&
359
- this.sparsePositionBaselines.has(key) &&
360
- this.hasPositionConfig(worldId, entityId)) {
361
- return;
362
- }
363
- if (!hasTrackedConfig && this.#isDirectPositionCycleBaseline(loader, mask)) {
364
- this.pickBases.set(key, 3);
365
- this.pickDeltaBases.set(key, 0);
366
- this.placeBases.set(key, 4);
367
- this.placeDeltaBases.set(key, 0);
368
- this.#setCurrentPosition(key, loader);
369
- if ((mask & 4) && loader.q28 >= -1 && loader.q28 <= 1) this.priorities.set(key, loader.q28);
370
- this.requireOutputs.set(key, Boolean(mask & 32));
371
- this.waitForStacks.set(key, Boolean(mask & 64));
372
- this.stackBases.set(key, 16);
373
- this.stackSources.delete(key);
374
- this.cycleModes.set(key, "direct");
375
- this.cycleDeltaBases.set(key, 0);
376
- this.directCycleValues.set(key, loader.q44 ?? loader.q36);
377
- this.directCycleFields.set(key, loader.q44 == null ? "q36" : "q44");
378
- this.cycles.set(key, ((loader.q44 ?? loader.q36) / 20) + 1);
379
- return;
380
- }
381
-
382
- if (!hasTrackedConfig && options.allowSparseBaseline && this.#isSparsePositionBaseline(loader, mask)) {
383
- this.#applySparsePositionBaseline(key, loader, mask);
384
- return;
385
- }
386
-
387
- const baseline = hasTrackedConfig ? null : this.#loaderBaseline(loader, mask, options.semanticSnapshot);
388
- if (hasTrackedConfig && options.semanticDelta && this.#applySemanticDelta(worldId, entityId, loader, mask, previous, options.deltaRecord)) {
389
- return;
390
- }
391
- const hasInitialConfigFields = baseline || ((mask & 31) && ((mask & 32) || ((mask & 64) && (mask & 4))));
392
- // Loader table 78 is an affine config vector: initial/full rows establish
393
- // origins, then later rows are deltas even when active flag bits are present.
394
- if (!hasTrackedConfig && hasInitialConfigFields && mask !== 32 && mask !== 64) {
395
- if (baseline) this.#applyLoaderBaseline(key, loader, baseline);
396
- else {
397
- const usedQ28AsPositionBase = this.#initializePositionBaseline(key, loader, mask);
398
- if ((mask & 4) && loader.q28 != null) {
399
- if (usedQ28AsPositionBase) this.#initializePriorityOffset(key, loader);
400
- else this.priorities.set(key, loader.q28);
401
- }
402
- }
403
- this.requireOutputs.set(key, Boolean(mask & 32));
404
- this.waitForStacks.set(key, Boolean(mask & 64));
405
- if (!this.stackBases.has(key)) this.#initializeStackBaseline(key, loader);
406
- if (!this.cycles.has(key)) this.#initializeCycleBaseline(key, loader);
407
- return;
408
- }
409
-
410
- const q44CycleChanged = (mask & 64) &&
411
- this.#usesQ44CycleBase(key) &&
412
- loader.q44 != null &&
413
- (
414
- this.#fieldChanged(previous, loader, "q44") ||
415
- (this.directCycleValues.has(key) && loader.q44 !== this.directCycleValues.get(key))
416
- );
417
- const q40DirectCycleChanged = (mask & 32) &&
418
- this.cycleModes.get(key) === "q40-direct" &&
419
- loader.q40 != null &&
420
- (
421
- this.#fieldChanged(previous, loader, "q40") ||
422
- (this.directCycleValues.has(key) && loader.q40 !== this.directCycleValues.get(key))
423
- );
424
- if (q44CycleChanged) {
425
- this.directCycleValues.set(key, loader.q44);
426
- this.#updateCycle(key, loader);
427
- } else if (q40DirectCycleChanged) {
428
- this.directCycleValues.set(key, loader.q40);
429
- this.#updateCycle(key, loader);
430
- } else if ((mask & 32) && mask === 32) {
431
- this.requireOutputs.set(key, !this.requireOutputs.get(key));
432
- } else if ((mask & 32) && !this.requireOutputs.has(key)) {
433
- this.requireOutputs.set(key, true);
434
- }
435
- // The same bit is also the wait-for-stack toggle. Treat a real q44 value
436
- // change as cycle config, and an unchanged standalone bit as the toggle.
437
- if (!q44CycleChanged) {
438
- if ((mask & 64) && mask === 64) this.waitForStacks.set(key, !this.waitForStacks.get(key));
439
- else if ((mask & 64) && !this.waitForStacks.has(key)) this.waitForStacks.set(key, true);
440
- }
441
- if ((mask & 4) && loader.q28 != null) this.priorities.set(key, this.#priority(key, loader.q28));
442
- if ((mask & 8) && this.filterSources.get(key) === "q32" && loader.q32 != null) this.filterModes.set(key, loader.q32);
443
- const q32FilterOnlyUpdate = this.filterSources.get(key) === "q32" && mask === 8;
444
- if ((mask & 8) && !options.semanticDelta && !q32FilterOnlyUpdate && loader.q32 != null && this.stackBases.has(key)) {
445
- const previousConfig = this.getConfig(worldId, entityId, previous);
446
- this.stackBases.set(key, previousConfig.stack - (previous?.q32 ?? 0));
447
- this.stackSources.set(key, "q32");
448
- }
449
- if (mask & 16) this.#updateCycle(key, loader);
450
- if ((mask & 3) && this.hasPositionConfig(worldId, entityId)) this.#setCurrentPosition(key, loader);
451
- }
452
-
453
- updateIndexedSnapshotRecord(worldId, entityId, loader, mask = 0, cumulative = null, configEntity = null) {
454
- if (!loader) return false;
455
- const reference = configEntity == null || Number(configEntity) === Number(entityId)
456
- ? null
457
- : this.#trackedConfig(worldId, configEntity);
458
- const config = decodeIndexedLoaderSnapshotRecord(loader, mask, cumulative, reference);
459
- if (!config) return false;
460
-
461
- const key = this.#key(worldId, entityId);
462
- this.pickBases.set(key, config.pick);
463
- this.pickDeltaBases.set(key, loader.q20 ?? 0);
464
- this.placeBases.set(key, config.place);
465
- this.placeDeltaBases.set(key, loader.q24 ?? 0);
466
- this.currentPicks.set(key, config.pick);
467
- this.currentPlaces.set(key, config.place);
468
- this.sparsePositionBaselines.delete(key);
469
- this.priorities.set(key, config.priority);
470
- if (mask === 95 && loader.q28 != null) this.priorityOffsets.set(key, config.priority - loader.q28);
471
- else this.priorityOffsets.delete(key);
472
- this.filterModes.delete(key);
473
- this.filterSources.delete(key);
474
- this.requireOutputs.set(key, config.requireOutput);
475
- this.waitForStacks.set(key, config.waitForStack);
476
- this.stackBases.set(key, config.stack - (loader.q32 ?? 0));
477
- this.stackSources.delete(key);
478
- this.cycles.set(key, config.cycle);
479
- if (mask === 95) {
480
- this.cycleModes.set(key, "q44-q36-delta");
481
- this.cycleDeltaBases.set(key, loader.q36 ?? 0);
482
- this.directCycleValues.set(key, loader.q44);
483
- this.directCycleFields.set(key, "q44");
484
- } else if (mask === 126) {
485
- this.cycleModes.set(key, "offset");
486
- this.cycleDeltaBases.set(key, loader.q36 ?? 0);
487
- this.directCycleValues.delete(key);
488
- this.directCycleFields.delete(key);
489
- } else {
490
- this.cycleModes.set(key, "direct");
491
- this.cycleDeltaBases.set(key, 0);
492
- }
493
- if (loader.q36 != null && mask === 18) {
494
- this.directCycleValues.set(key, loader.q36);
495
- this.directCycleFields.set(key, "q36");
496
- } else if (mask !== 95 && mask !== 126) {
497
- this.directCycleValues.delete(key);
498
- this.directCycleFields.delete(key);
499
- }
500
- return true;
501
- }
502
-
503
- delete(worldId, entityId) {
504
- const key = this.#key(worldId, entityId);
505
- this.pickBases.delete(key);
506
- this.pickDeltaBases.delete(key);
507
- this.placeBases.delete(key);
508
- this.placeDeltaBases.delete(key);
509
- this.currentPicks.delete(key);
510
- this.currentPlaces.delete(key);
511
- this.sparsePositionBaselines.delete(key);
512
- this.priorities.delete(key);
513
- this.priorityOffsets.delete(key);
514
- this.filterModes.delete(key);
515
- this.filterSources.delete(key);
516
- this.requireOutputs.delete(key);
517
- this.waitForStacks.delete(key);
518
- this.stackBases.delete(key);
519
- this.stackSources.delete(key);
520
- this.cycles.delete(key);
521
- this.cycleModes.delete(key);
522
- this.cycleDeltaBases.delete(key);
523
- this.directCycleValues.delete(key);
524
- this.directCycleFields.delete(key);
525
- }
526
-
527
- getConfig(worldId, entityId, loader, loaderFilter = null, filterSlots = null) {
528
- const key = this.#key(worldId, entityId);
529
- const pick = this.currentPicks.has(key) ? this.currentPicks.get(key) : this.#pick(key, loader);
530
- const place = this.currentPlaces.has(key) ? this.currentPlaces.get(key) : this.#place(key, loader);
531
- const stackBase = this.stackBases.get(key) ?? 16;
532
- const stackSource = this.stackSources.get(key) ?? "q32";
533
- const stackField = stackSource === "fixed" ? null : loader?.[stackSource];
534
- const stack = stackField == null
535
- ? this.stackBases.has(key) || this.hasPositionConfig(worldId, entityId) ? stackBase : null
536
- : stackBase + stackField;
537
- const cycle = this.cycles.has(key)
538
- ? this.cycles.get(key)
539
- : loader?.q40 == null || loader.q36 == null ? null : ((loader.q40 + loader.q36) / 20) + 1;
540
- return {
541
- pick,
542
- place,
543
- priority: this.priorities.has(key) ? this.priorities.get(key) : DEFAULT_LOADER_PRIORITY,
544
- requireOutput: this.requireOutputs.has(key) ? this.requireOutputs.get(key) : false,
545
- waitForStack: this.waitForStacks.has(key) ? this.waitForStacks.get(key) : false,
546
- stack: stack ?? DEFAULT_LOADER_STACK,
547
- cycle: cycle ?? DEFAULT_LOADER_CYCLE,
548
- filterMode: loaderFilter ? loaderFilter.q20 ?? DEFAULT_LOADER_FILTER_MODE : this.#filterMode(key, loader) ?? DEFAULT_LOADER_FILTER_MODE,
549
- filterSlots: filterSlots ? [filterSlotValue(filterSlots.q20), filterSlotValue(filterSlots.q24), filterSlotValue(filterSlots.q28)] : null
550
- };
551
- }
552
-
553
- hasPositionConfig(worldId, entityId) {
554
- const key = this.#key(worldId, entityId);
555
- return this.pickBases.has(key) && this.placeBases.has(key);
556
- }
557
-
558
- #hasTrackedConfig(key) {
559
- return this.pickBases.has(key) ||
560
- this.placeBases.has(key) ||
561
- this.priorities.has(key) ||
562
- this.priorityOffsets.has(key) ||
563
- this.filterModes.has(key) ||
564
- this.requireOutputs.has(key) ||
565
- this.waitForStacks.has(key) ||
566
- this.stackBases.has(key) ||
567
- this.cycles.has(key);
568
- }
569
-
570
- #fieldChanged(previous, loader, field) {
571
- return previous != null && loader != null && previous[field] !== loader[field];
572
- }
573
-
574
- #usesQ44CycleBase(key) {
575
- const mode = this.cycleModes.get(key);
576
- return mode === "q44-q36-delta";
577
- }
578
-
579
- #initializePositionBaseline(key, loader, mask) {
580
- const hasQ28PositionBase = loader.q28 != null && (mask & 4);
581
- if (loader.q24 != null) {
582
- this.pickBases.set(key, wrapLoaderPosition(loader.q24 + 3));
583
- this.pickDeltaBases.set(key, loader.q20 ?? 0);
584
- this.placeDeltaBases.set(key, loader.q24);
585
- const initialPlace = hasQ28PositionBase
586
- ? loader.q28 + 4
587
- : loader.q36 == null ? null : loader.q36 + 4;
588
- if (initialPlace != null) this.placeBases.set(key, wrapLoaderPosition(initialPlace));
589
- return hasQ28PositionBase;
590
- }
591
-
592
- if (hasQ28PositionBase) {
593
- this.pickBases.set(key, wrapLoaderPosition(loader.q28 + 3));
594
- this.pickDeltaBases.set(key, 0);
595
- this.placeBases.set(key, 4);
596
- this.placeDeltaBases.set(key, 0);
597
- return true;
598
- }
599
-
600
- if (loader.q20 != null && loader.q36 != null) {
601
- this.pickBases.set(key, wrapLoaderPosition(loader.q36 + 3));
602
- this.pickDeltaBases.set(key, 0);
603
- this.placeBases.set(key, 4);
604
- this.placeDeltaBases.set(key, 0);
605
- }
606
- return false;
607
- }
608
-
609
- #initializeCycleBaseline(key, loader) {
610
- if (loader?.q44 != null && (loader.q36 == null || loader.q40 == null)) {
611
- this.cycleModes.set(key, "q44-q36-delta");
612
- this.cycleDeltaBases.set(key, loader.q36 ?? 0);
613
- this.directCycleValues.set(key, loader.q44);
614
- this.directCycleFields.set(key, "q44");
615
- this.cycles.set(key, (loader.q44 / 20) + 1);
616
- return;
617
- }
618
- if (loader?.q40 == null || loader.q36 == null) return;
619
- this.cycleModes.set(key, "offset");
620
- this.cycleDeltaBases.set(key, loader.q36 ?? 0);
621
- this.directCycleValues.delete(key);
622
- this.directCycleFields.delete(key);
623
- this.cycles.set(key, (loader.q40 / 20) + 1);
624
- }
625
-
626
- #initializeStackBaseline(key, loader) {
627
- if (this.stackBases.has(key)) return;
628
- if (loader?.q32 == null) return;
629
- const baseline = this.#loaderBaseline(loader, loader?.lastMask);
630
- if (baseline) {
631
- this.stackBases.set(key, baseline.stack - loader.q32);
632
- return;
633
- }
634
- if (loader.q20 == null && loader.q24 == null && loader.q28 == null && loader.q36 != null) {
635
- this.stackBases.set(key, 17 + loader.q36);
636
- return;
637
- }
638
- this.stackBases.set(key, 16);
639
- }
640
-
641
- #initializePriorityOffset(key, loader) {
642
- if (loader?.q28 == null || loader?.q36 == null) return;
643
- const offset = loader.q36 + 2;
644
- const priority = loader.q28 + offset;
645
- if (priority < -1 || priority > 1) return;
646
- this.priorityOffsets.set(key, offset);
647
- this.priorities.set(key, priority);
648
- }
649
-
650
- #priority(key, q28) {
651
- return q28 + (this.priorityOffsets.get(key) ?? 0);
652
- }
653
-
654
- #updateCycle(key, loader) {
655
- const mode = this.cycleModes.get(key);
656
- if (mode === "direct") {
657
- if (loader?.q36 != null) {
658
- this.directCycleValues.set(key, loader.q36);
659
- this.directCycleFields.set(key, "q36");
660
- this.cycles.set(key, (loader.q36 / 20) + 1);
661
- } else if (loader?.q44 != null) {
662
- this.directCycleValues.set(key, loader.q44);
663
- this.directCycleFields.set(key, "q44");
664
- this.cycles.set(key, (loader.q44 / 20) + 1);
665
- }
666
- return;
667
- }
668
- if (mode === "q44-q36-delta") {
669
- const base = loader?.q44 ?? this.directCycleValues.get(key);
670
- if (base != null) {
671
- this.directCycleValues.set(key, base);
672
- this.directCycleFields.set(key, "q44");
673
- const q36 = loader?.q36 ?? 0;
674
- this.cycles.set(key, base < 0 && loader?.q36 != null
675
- ? (q36 / 20) + 1
676
- : ((base + q36 - (this.cycleDeltaBases.get(key) ?? 0)) / 20) + 1);
677
- }
678
- return;
679
- }
680
- if (mode === "q40-direct") {
681
- if (loader?.q40 != null) {
682
- this.directCycleValues.set(key, loader.q40);
683
- this.directCycleFields.set(key, "q40");
684
- this.cycles.set(key, (loader.q40 / 20) + 1);
685
- }
686
- return;
687
- }
688
- if (loader?.q40 == null) {
689
- if (loader?.q44 != null || loader?.q36 != null) this.cycles.set(key, ((loader.q44 ?? loader.q36) / 20) + 1);
690
- return;
691
- }
692
- const deltaBase = this.cycleDeltaBases.get(key) ?? 0;
693
- this.cycles.set(key, ((loader.q40 + (loader.q36 ?? 0) - deltaBase) / 20) + 1);
694
- }
695
-
696
- #isDirectPositionCycleBaseline(loader, mask) {
697
- return (mask & 19) === 19 &&
698
- loader.q20 != null &&
699
- loader.q24 != null &&
700
- loader.q36 != null &&
701
- loader.q40 == null &&
702
- loader.q44 == null;
703
- }
704
-
705
- #trackedConfig(worldId, entityId) {
706
- const key = this.#key(worldId, entityId);
707
- if (!this.#hasTrackedConfig(key)) return null;
708
- return {
709
- pick: this.currentPicks.has(key) ? this.currentPicks.get(key) : this.pickBases.get(key),
710
- place: this.currentPlaces.has(key) ? this.currentPlaces.get(key) : this.placeBases.get(key),
711
- priority: this.priorities.get(key) ?? DEFAULT_LOADER_PRIORITY,
712
- requireOutput: this.requireOutputs.get(key) ?? false,
713
- waitForStack: this.waitForStacks.get(key) ?? false,
714
- stack: this.stackBases.get(key) ?? DEFAULT_LOADER_STACK,
715
- cycle: this.cycles.get(key) ?? DEFAULT_LOADER_CYCLE
716
- };
717
- }
718
-
719
- #isSparsePositionBaseline(loader, mask) {
720
- return (mask & 3) === 3 &&
721
- loader.q20 != null &&
722
- loader.q24 != null &&
723
- loader.q28 == null &&
724
- loader.q32 == null &&
725
- loader.q36 == null &&
726
- loader.q44 == null;
727
- }
728
-
729
- #applySparsePositionBaseline(key, loader, mask) {
730
- const pickField = loader.q40 == null ? loader.q20 : loader.q24;
731
- const placeField = loader.q40 == null ? loader.q24 : loader.q40;
732
- const pick = wrapLoaderPosition(pickField + 3);
733
- const place = wrapLoaderPosition(placeField + 4);
734
- this.pickBases.set(key, pick);
735
- this.pickDeltaBases.set(key, loader.q20 ?? 0);
736
- this.placeBases.set(key, place);
737
- this.placeDeltaBases.set(key, loader.q24 ?? 0);
738
- this.currentPicks.set(key, pick);
739
- this.currentPlaces.set(key, place);
740
- this.sparsePositionBaselines.add(key);
741
- this.priorities.set(key, DEFAULT_LOADER_PRIORITY);
742
- this.requireOutputs.set(key, Boolean(mask & 32));
743
- this.waitForStacks.set(key, Boolean(mask & 64));
744
- this.stackBases.set(key, DEFAULT_LOADER_STACK);
745
- this.cycles.set(key, DEFAULT_LOADER_CYCLE);
746
- }
747
-
748
- #filterMode(key, loader) {
749
- if (this.filterSources.get(key) === "q32" && loader?.q32 != null) {
750
- return this.#validFilterMode(loader.q32);
751
- }
752
- if (this.filterModes.has(key)) return this.#validFilterMode(this.filterModes.get(key));
753
- const baseline = this.#loaderBaseline(loader, loader?.lastMask);
754
- if (!baseline) return null;
755
- return this.#validFilterMode(baseline.filterMode);
756
- }
757
-
758
- #validFilterMode(mode) {
759
- return mode >= 0 && mode <= 3 ? mode : null;
760
- }
761
-
762
- #semanticFilterMode(loader, mask) {
763
- const q28IsDirectPriority = loader.q28 != null && loader.q28 >= -1 && loader.q28 <= 1;
764
- const q24FilterMode = loader.q24 != null && loader.q32 != null && loader.q40 != null ? loader.q24 + 2 : null;
765
- const q28FilterMode = loader.q28 != null && loader.q32 != null ? loader.q28 + 1 : null;
766
- const q32FilterMode = !q28IsDirectPriority && loader.q28 != null && loader.q32 != null && loader.q40 != null ? loader.q32 + 1 : null;
767
- const q32DirectMode = loader.q28 == null && loader.q32 != null && (mask & 32) ? loader.q32 : null;
768
- if (q28IsDirectPriority && this.#validFilterMode(q24FilterMode) != null) return q24FilterMode;
769
- if (this.#validFilterMode(q28FilterMode) != null) return q28FilterMode;
770
- if (this.#validFilterMode(q32FilterMode) != null) return q32FilterMode;
771
- if (this.#validFilterMode(q32DirectMode) != null) return q32DirectMode;
772
- if (this.#validFilterMode(q24FilterMode) != null) return q24FilterMode;
773
- return null;
774
- }
775
-
776
- #semanticFilterField(loader, mask) {
777
- const q32DirectMode = loader.q28 == null && loader.q32 != null && (mask & 32) ? loader.q32 : null;
778
- return this.#validFilterMode(q32DirectMode) != null ? "q32" : null;
779
- }
780
-
781
- #loaderBaseline(loader, mask = loader?.lastMask, semanticSnapshot = false) {
782
- const snapshot = semanticSnapshot ? decodeLoaderSnapshotRecord(loader, mask) : null;
783
- if (snapshot) {
784
- return {
785
- pickBase: snapshot.pick,
786
- pickDeltaBase: loader.q20 ?? 0,
787
- placeBase: snapshot.place,
788
- placeDeltaBase: loader.q24 ?? 0,
789
- priority: snapshot.priority,
790
- stack: snapshot.stack,
791
- stackField: "fixed",
792
- cycle: snapshot.cycle,
793
- cycleMode: loader.q44 != null && loader.q40 == null ? "q44-q36-delta" : "offset",
794
- filterMode: this.#semanticFilterMode(loader, mask),
795
- filterField: this.#semanticFilterField(loader, mask),
796
- q32: loader.q32 ?? 0
797
- };
798
- }
799
- if (!loader || loader.q36 == null) return null;
800
- if (loader.q40 == null && loader.q44 == null) {
801
- if (loader.q20 != null || loader.q24 == null || loader.q28 == null || loader.q32 == null) return null;
802
- return {
803
- pickBase: wrapLoaderPosition(loader.q28 + 2),
804
- pickDeltaBase: 0,
805
- placeBase: wrapLoaderPosition(loader.q24 + 4),
806
- placeDeltaBase: loader.q24,
807
- priority: loader.q28,
808
- stack: 16 + loader.q32,
809
- cycle: (loader.q36 / 20) + 1,
810
- cycleMode: "direct",
811
- filterMode: loader.q28 + 1,
812
- q32: loader.q32
813
- };
814
- }
815
- if (loader.q24 == null &&
816
- loader.q28 == null &&
817
- loader.q20 != null &&
818
- loader.q32 != null &&
819
- loader.q40 != null &&
820
- loader.q44 != null) {
821
- return {
822
- pickBase: wrapLoaderPosition(loader.q20 + 7),
823
- pickDeltaBase: loader.q20,
824
- placeBase: 4,
825
- placeDeltaBase: 0,
826
- priority: 0,
827
- stack: 16 + loader.q36,
828
- stackField: "q36",
829
- cycle: (loader.q40 / 20) + 1,
830
- cycleMode: "q40-direct",
831
- filterMode: loader.q32,
832
- filterField: "q32",
833
- q32: loader.q32
834
- };
835
- }
836
- const q20 = loader.q20 ?? 0;
837
- const q32 = loader.q32 ?? 0;
838
- let pickBase = null;
839
- let placeBase = null;
840
-
841
- if (loader.q44 != null && loader.q40 == null && loader.q28 == null && loader.q24 != null && loader.q32 != null) {
842
- pickBase = wrapLoaderPosition(loader.q24 + 3);
843
- placeBase = wrapLoaderPosition(loader.q32 + 4);
844
- } else if (loader.q24 != null) {
845
- pickBase = wrapLoaderPosition(loader.q24 + 3);
846
- placeBase = loader.q28 != null
847
- ? wrapLoaderPosition(loader.q28 + 4)
848
- : wrapLoaderPosition(loader.q36 + 4);
849
- } else if (loader.q28 != null) {
850
- pickBase = wrapLoaderPosition(loader.q28 + 3);
851
- placeBase = 4;
852
- } else if (loader.q20 != null) {
853
- pickBase = wrapLoaderPosition(loader.q36 + 3);
854
- placeBase = 4;
855
- }
856
-
857
- if (pickBase == null || placeBase == null) return null;
858
- const q28IsDirectPriority = loader.q28 != null && loader.q28 >= -1 && loader.q28 <= 1;
859
- const priority = loader.q28 != null && loader.q32 != null && loader.q44 != null && loader.q40 != null
860
- ? loader.q32
861
- : loader.q28 != null && loader.q32 != null && loader.q44 == null && loader.q40 == null
862
- ? loader.q28
863
- : loader.q28 != null && loader.q32 != null && loader.q44 == null && loader.q40 != null
864
- ? loader.q32
865
- : loader.q32 != null && loader.q44 != null && loader.q40 == null
866
- ? loader.q32
867
- : null;
868
- const q28FilterMode = loader.q28 != null && loader.q32 != null && loader.q44 != null ? loader.q28 + 1 : null;
869
- const q24FilterMode = loader.q24 != null && loader.q32 != null && loader.q44 != null && loader.q40 != null ? loader.q24 + 2 : null;
870
- const q32FilterMode = !q28IsDirectPriority && loader.q28 != null && loader.q32 != null && loader.q44 != null && loader.q40 != null
871
- ? loader.q32 + 1
872
- : null;
873
- const filterMode = q28IsDirectPriority && q24FilterMode != null && q24FilterMode >= 0 && q24FilterMode <= 3
874
- ? q24FilterMode
875
- : q28FilterMode != null && q28FilterMode >= 0 && q28FilterMode <= 3
876
- ? q28FilterMode
877
- : q32FilterMode != null && q32FilterMode >= 0 && q32FilterMode <= 3 ? q32FilterMode : q24FilterMode;
878
- return {
879
- pickBase,
880
- pickDeltaBase: q20,
881
- placeBase,
882
- placeDeltaBase: loader.q24 ?? 0,
883
- priority,
884
- stack: loader.q32 == null ? null : 16 + loader.q36,
885
- cycle: ((loader.q40 ?? loader.q44) / 20) + 1,
886
- cycleMode: loader.q44 != null && loader.q40 == null ? "q44-q36-delta" : "offset",
887
- filterMode,
888
- q32
889
- };
890
- }
891
-
892
- #applyLoaderBaseline(key, loader, baseline) {
893
- this.pickBases.set(key, baseline.pickBase);
894
- this.pickDeltaBases.set(key, baseline.pickDeltaBase);
895
- this.placeBases.set(key, baseline.placeBase);
896
- this.placeDeltaBases.set(key, baseline.placeDeltaBase);
897
- this.sparsePositionBaselines.delete(key);
898
- this.#setCurrentPosition(key, loader);
899
- if (baseline.filterMode != null) {
900
- this.filterModes.set(key, baseline.filterMode);
901
- if (baseline.filterField) this.filterSources.set(key, baseline.filterField);
902
- else this.filterSources.delete(key);
903
- }
904
- if (baseline.stack != null) {
905
- const stackField = baseline.stackField === "fixed" ? 0 : baseline.stackField ? loader[baseline.stackField] ?? 0 : baseline.q32;
906
- this.stackBases.set(key, baseline.stack - stackField);
907
- if (baseline.stackField) this.stackSources.set(key, baseline.stackField);
908
- else this.stackSources.delete(key);
909
- }
910
- this.cycleModes.set(key, baseline.cycleMode);
911
- if (baseline.cycleMode === "direct") {
912
- this.cycleDeltaBases.set(key, 0);
913
- this.directCycleValues.set(key, loader.q44 ?? loader.q36);
914
- this.directCycleFields.set(key, loader.q44 == null ? "q36" : "q44");
915
- } else if (baseline.cycleMode === "q44-q36-delta") {
916
- this.cycleDeltaBases.set(key, loader.q36 ?? 0);
917
- this.directCycleValues.set(key, loader.q44);
918
- this.directCycleFields.set(key, "q44");
919
- } else if (baseline.cycleMode === "q40-direct") {
920
- this.cycleDeltaBases.set(key, 0);
921
- this.directCycleValues.set(key, loader.q40);
922
- this.directCycleFields.set(key, "q40");
923
- } else {
924
- this.cycleDeltaBases.set(key, loader.q36 ?? 0);
925
- this.directCycleValues.delete(key);
926
- this.directCycleFields.delete(key);
927
- }
928
- this.cycles.set(key, baseline.cycle);
929
- if (baseline.priority != null && baseline.priority >= -1 && baseline.priority <= 1) {
930
- if (loader.q28 != null) this.priorityOffsets.set(key, baseline.priority - loader.q28);
931
- this.priorities.set(key, baseline.priority);
932
- } else if (loader.q28 != null && loader.q36 != null) this.#initializePriorityOffset(key, loader);
933
- }
934
-
935
- #applySemanticDelta(worldId, entityId, loader, mask, previous, deltaRecord) {
936
- const key = this.#key(worldId, entityId);
937
- const delta = decodeLoaderSemanticDeltaRecord(deltaRecord ?? loaderDeltaRecord(loader, mask, previous), mask);
938
- if (!delta) return false;
939
-
940
- const previousConfig = this.getConfig(worldId, entityId, previous);
941
- const pick = delta.pick == null ? previousConfig.pick : wrapLoaderPosition((previousConfig.pick ?? DEFAULT_LOADER_PICK) + delta.pick);
942
- const place = delta.place == null ? previousConfig.place : wrapLoaderPosition((previousConfig.place ?? DEFAULT_LOADER_PLACE) + delta.place);
943
-
944
- if (pick != null) {
945
- this.pickBases.set(key, pick);
946
- this.pickDeltaBases.set(key, loader?.q20 ?? 0);
947
- this.currentPicks.set(key, pick);
948
- }
949
- if (place != null) {
950
- this.placeBases.set(key, place);
951
- this.placeDeltaBases.set(key, loader?.q24 ?? 0);
952
- this.currentPlaces.set(key, place);
953
- }
954
-
955
- if (delta.priority != null) {
956
- const priority = previousConfig.priority + delta.priority;
957
- this.priorities.set(key, priority);
958
- if (loader?.q28 != null) this.priorityOffsets.set(key, priority - loader.q28);
959
- else this.priorityOffsets.delete(key);
960
- }
961
-
962
- if (delta.stack != null) {
963
- this.stackBases.set(key, previousConfig.stack + delta.stack);
964
- this.stackSources.set(key, "fixed");
965
- }
966
-
967
- if (delta.cycleTicks != null) {
968
- this.cycles.set(key, previousConfig.cycle + (delta.cycleTicks / 20));
969
- if (loader?.q44 != null && loader.q40 == null) {
970
- this.cycleModes.set(key, "q44-q36-delta");
971
- this.cycleDeltaBases.set(key, loader.q36 ?? 0);
972
- this.directCycleValues.set(key, loader.q44);
973
- this.directCycleFields.set(key, "q44");
974
- } else {
975
- this.cycleModes.set(key, "offset");
976
- this.cycleDeltaBases.set(key, loader?.q36 ?? 0);
977
- this.directCycleValues.delete(key);
978
- this.directCycleFields.delete(key);
979
- }
980
- }
981
-
982
- if (delta.requireOutput) this.requireOutputs.set(key, !previousConfig.requireOutput);
983
- if (delta.waitForStack) this.waitForStacks.set(key, !previousConfig.waitForStack);
984
- this.sparsePositionBaselines.delete(key);
985
- return true;
986
- }
987
-
988
- #setCurrentPosition(key, loader) {
989
- const pick = this.#pick(key, loader);
990
- const place = this.#place(key, loader);
991
- if (pick != null) this.currentPicks.set(key, pick);
992
- if (place != null) this.currentPlaces.set(key, place);
993
- }
994
-
995
- #pick(key, loader) {
996
- if (!loader) return null;
997
- if (this.pickBases.has(key)) return wrapLoaderPosition(this.pickBases.get(key) + ((loader.q20 ?? 0) - (this.pickDeltaBases.get(key) ?? 0)));
998
- if (loader.q24 != null) return wrapLoaderPosition(loader.q24 + 3);
999
- if (loader.q36 != null) return wrapLoaderPosition(loader.q36 + 3);
1000
- if (loader.q20 != null) return wrapLoaderPosition(loader.q20);
1001
- return null;
1002
- }
1003
-
1004
- #place(key, loader) {
1005
- if (!loader) return null;
1006
- if (this.placeBases.has(key)) {
1007
- const base = this.placeBases.get(key);
1008
- if (loader.q24 != null && this.placeDeltaBases.has(key)) {
1009
- return wrapLoaderPosition(base + (loader.q24 - this.placeDeltaBases.get(key)));
1010
- }
1011
- return wrapLoaderPosition(base);
1012
- }
1013
- if (loader.q36 != null) return loader.q24 == null ? 4 : wrapLoaderPosition(loader.q36 + 4);
1014
- return null;
1015
- }
1016
-
1017
- #key(worldId, entityId) {
1018
- return `${worldId ?? "-"}:${entityId}`;
1019
- }
1020
- }