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.
- package/dist/browser/dredless.global.js +33 -960
- package/dist/browser/dredless.global.js.map +3 -3
- package/docs/API_REFERENCE.md +14 -1
- package/package.json +1 -1
- package/src/index.d.ts +4 -1
- package/src/state/model/decoder.js +31 -46
- package/src/state/model/loader-config.js +0 -997
- package/src/state/model/state.js +6 -73
package/docs/API_REFERENCE.md
CHANGED
|
@@ -1085,6 +1085,13 @@ interface LoaderFullConfig extends LoaderConfig {
|
|
|
1085
1085
|
|
|
1086
1086
|
State output:
|
|
1087
1087
|
|
|
1088
|
+
Loader state uses the official component defaults when configuration fields
|
|
1089
|
+
are omitted: pick `3` (middle-left), place `4` (middle-right), normal priority,
|
|
1090
|
+
stack `16`, cycle `1` second, and both flags disabled. Cycle times are converted
|
|
1091
|
+
from ticks at 20 ticks per second. Flag updates set their absolute boolean
|
|
1092
|
+
values; repeated updates do not toggle them. Raw loader configuration is stored
|
|
1093
|
+
in model table `69` (wire section `162`), separately from navigation state.
|
|
1094
|
+
|
|
1088
1095
|
```ts
|
|
1089
1096
|
interface LoaderSummary {
|
|
1090
1097
|
entity: number;
|
|
@@ -1440,6 +1447,11 @@ interface CargoEjectorHandle extends MachineHandle {
|
|
|
1440
1447
|
|
|
1441
1448
|
Associated summary shapes:
|
|
1442
1449
|
|
|
1450
|
+
Cannon summaries expose `relativeAngleRadians` relative to the mount and
|
|
1451
|
+
`absoluteAngleRadians` in ship coordinates, normalized to `[0, 2π)`, replacing
|
|
1452
|
+
the raw `aim` field. The relative angle is `null` when aim is unavailable; the
|
|
1453
|
+
absolute angle is `null` when either aim or mounting rotation is unavailable.
|
|
1454
|
+
|
|
1443
1455
|
```ts
|
|
1444
1456
|
interface CannonSummary {
|
|
1445
1457
|
entity: number;
|
|
@@ -1448,7 +1460,8 @@ interface CannonSummary {
|
|
|
1448
1460
|
ammoItemId: number | null;
|
|
1449
1461
|
ammoName: string | null;
|
|
1450
1462
|
ammoCount: number;
|
|
1451
|
-
|
|
1463
|
+
relativeAngleRadians: number | null; // Barrel angle relative to its mount.
|
|
1464
|
+
absoluteAngleRadians: number | null; // Ship coordinates, normalized to [0, 2π).
|
|
1452
1465
|
recoil: number | null;
|
|
1453
1466
|
recoil2: number | null;
|
|
1454
1467
|
recoils: [number | null, number | null];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dredless",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "A fully-featured and from-scratch headless drednot.io client implementation written in pure js.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/certainhuman/dredless#readme",
|
package/src/index.d.ts
CHANGED
|
@@ -1832,7 +1832,10 @@ export interface CannonSummary {
|
|
|
1832
1832
|
ammoItemId: number | null;
|
|
1833
1833
|
ammoName: string | null;
|
|
1834
1834
|
ammoCount: number;
|
|
1835
|
-
|
|
1835
|
+
/** Barrel angle relative to its mount, in radians. */
|
|
1836
|
+
relativeAngleRadians: number | null;
|
|
1837
|
+
/** Barrel direction in ship coordinates, normalized to [0, 2π); null if aim or mounting rotation is unavailable. */
|
|
1838
|
+
absoluteAngleRadians: number | null;
|
|
1836
1839
|
recoil: number | null;
|
|
1837
1840
|
recoil2: number | null;
|
|
1838
1841
|
recoils: [number | null, number | null];
|
|
@@ -2,8 +2,7 @@ import {decoder} from "../../constants.js";
|
|
|
2
2
|
import {
|
|
3
3
|
LOADER_FILTER_MODE_NAMES,
|
|
4
4
|
LOADER_POSITION_NAMES,
|
|
5
|
-
LOADER_PRIORITY_NAMES
|
|
6
|
-
LoaderConfigTracker
|
|
5
|
+
LOADER_PRIORITY_NAMES
|
|
7
6
|
} from "./loader-config.js";
|
|
8
7
|
import {navigationDestinationFromEncodedValue, navigationZoneFromBaseId} from "../overworld.js";
|
|
9
8
|
import {maybeSolveGeneratorMazeSeed} from "../generator-maze.js";
|
|
@@ -284,7 +283,11 @@ export const MODEL_TABLE_SPECS = new Map([
|
|
|
284
283
|
[63, {name: "numeric_pair", ...TWO_FIELD_SPEC}],
|
|
285
284
|
[67, {name: "numeric_single", fields: numericFields({1: 20})}],
|
|
286
285
|
[69, {
|
|
287
|
-
name: "
|
|
286
|
+
name: "loader_config",
|
|
287
|
+
// The official loader component starts with these values. Wire section
|
|
288
|
+
// 162 sends a packed absolute flag word before the five numeric deltas.
|
|
289
|
+
defaults: {q20: 3, q24: 4, q28: 1, q32: 16, q36: 20, q41: 0, q42: 0},
|
|
290
|
+
packedBeforeValues: true,
|
|
288
291
|
packedBits: [{bit: 32, offset: 41}, {bit: 64, offset: 42}],
|
|
289
292
|
fields: numericFields({1: 20, 2: 24, 4: 28, 8: 32, 16: 36})
|
|
290
293
|
}],
|
|
@@ -407,7 +410,7 @@ export const WIRE_TAG_TABLES = new Map([
|
|
|
407
410
|
[158, 75],
|
|
408
411
|
[160, 76],
|
|
409
412
|
[161, 77],
|
|
410
|
-
[162,
|
|
413
|
+
[162, 69], // Loader configuration; distinct from navigation state (168).
|
|
411
414
|
[163, 72],
|
|
412
415
|
[164, 73],
|
|
413
416
|
[165, 74],
|
|
@@ -574,32 +577,6 @@ export function firstRecord(records, predicate = null) {
|
|
|
574
577
|
return null;
|
|
575
578
|
}
|
|
576
579
|
|
|
577
|
-
export const TABLE_78_FIELD_BITS = [
|
|
578
|
-
["q20", 1],
|
|
579
|
-
["q24", 2],
|
|
580
|
-
["q28", 4],
|
|
581
|
-
["q32", 8],
|
|
582
|
-
["q36", 16],
|
|
583
|
-
["q40", 32],
|
|
584
|
-
["q44", 64]
|
|
585
|
-
];
|
|
586
|
-
|
|
587
|
-
export function table78DeltaRecord(changed) {
|
|
588
|
-
const record = {lastMask: changed.mask};
|
|
589
|
-
for (const [field, bit] of TABLE_78_FIELD_BITS) {
|
|
590
|
-
if (!(changed.mask & bit)) continue;
|
|
591
|
-
if (field === "q44" && ((changed.mask & 32) || changed.record?.q44 == null)) continue;
|
|
592
|
-
record[field] = (changed.record?.[field] ?? 0) - (changed.previous?.[field] ?? 0);
|
|
593
|
-
}
|
|
594
|
-
return record;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
export function isSemanticLoaderDelta(changed, full) {
|
|
598
|
-
return !full &&
|
|
599
|
-
changed.previous != null &&
|
|
600
|
-
(changed.mask & 96) === 96;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
580
|
export function decodeText(blob) {
|
|
604
581
|
if (!(blob instanceof Uint8Array)) return null;
|
|
605
582
|
try {
|
|
@@ -679,8 +656,14 @@ export function summarizeCargoEjector(entity, typeId, record) {
|
|
|
679
656
|
};
|
|
680
657
|
}
|
|
681
658
|
|
|
682
|
-
export function summarizeCannon(entity, record, typeId = null) {
|
|
659
|
+
export function summarizeCannon(entity, record, typeId = null, transformRecord = null) {
|
|
683
660
|
if (!record || !CANNON_TYPE_IDS.has(typeId)) return null;
|
|
661
|
+
const relativeAngleRadians = numberOrNull(record.q32, 200);
|
|
662
|
+
const mountingAngleRadians = numberOrNull(transformRecord?.q28, 127.324);
|
|
663
|
+
const tau = 2 * Math.PI;
|
|
664
|
+
const absoluteAngleRadians = relativeAngleRadians == null || mountingAngleRadians == null
|
|
665
|
+
? null
|
|
666
|
+
: (((mountingAngleRadians + relativeAngleRadians) % tau) + tau) % tau;
|
|
684
667
|
const ammoItemId = record.q24 == null ? null : CANNON_AMMO_COLOR_ITEM_IDS.get(record.q24) ?? null;
|
|
685
668
|
const charge = record.q40 ?? null;
|
|
686
669
|
const recoil = record.q36 ?? null;
|
|
@@ -692,7 +675,8 @@ export function summarizeCannon(entity, record, typeId = null) {
|
|
|
692
675
|
ammoItemId,
|
|
693
676
|
ammoName: entityNameFromType(ammoItemId),
|
|
694
677
|
ammoCount: record.q28 ?? 0,
|
|
695
|
-
|
|
678
|
+
relativeAngleRadians,
|
|
679
|
+
absoluteAngleRadians,
|
|
696
680
|
recoil,
|
|
697
681
|
recoil2,
|
|
698
682
|
recoils: [recoil, recoil2],
|
|
@@ -1142,15 +1126,14 @@ export function summarizeHugeThruster(entity, markerRecord, sizeRecord = null) {
|
|
|
1142
1126
|
};
|
|
1143
1127
|
}
|
|
1144
1128
|
|
|
1145
|
-
export function summarizeLoader(entity, loaderRecord, loaderFilterRecord = null, filterSlotsRecord = null,
|
|
1129
|
+
export function summarizeLoader(entity, loaderRecord, loaderFilterRecord = null, filterSlotsRecord = null, includeDefaults = false, itemHolderRecord = null) {
|
|
1146
1130
|
if (!loaderRecord && !loaderFilterRecord && !includeDefaults) return null;
|
|
1147
|
-
|
|
1148
|
-
const
|
|
1149
|
-
const
|
|
1150
|
-
const
|
|
1151
|
-
const
|
|
1152
|
-
const
|
|
1153
|
-
const filterMode = config.filterMode ?? null;
|
|
1131
|
+
// Match the official component defaults, then apply the already decoded state.
|
|
1132
|
+
const loader = {...MODEL_TABLE_SPECS.get(69).defaults, ...loaderRecord};
|
|
1133
|
+
const pick = loader.q20;
|
|
1134
|
+
const place = loader.q24;
|
|
1135
|
+
const priority = loader.q28 - 1;
|
|
1136
|
+
const filterMode = loaderFilterRecord?.q20 ?? 0;
|
|
1154
1137
|
const heldItem = itemSummary(itemHolderRecord?.q20, itemHolderRecord?.q24 ?? null);
|
|
1155
1138
|
return {
|
|
1156
1139
|
entity,
|
|
@@ -1160,13 +1143,15 @@ export function summarizeLoader(entity, loaderRecord, loaderFilterRecord = null,
|
|
|
1160
1143
|
placeName: enumValueName(LOADER_POSITION_NAMES, place),
|
|
1161
1144
|
priority,
|
|
1162
1145
|
priorityName: enumValueName(LOADER_PRIORITY_NAMES, priority),
|
|
1163
|
-
requireOutput:
|
|
1164
|
-
waitForStack:
|
|
1165
|
-
stack:
|
|
1166
|
-
cycle:
|
|
1146
|
+
requireOutput: Boolean(loader.q41),
|
|
1147
|
+
waitForStack: Boolean(loader.q42),
|
|
1148
|
+
stack: loader.q32,
|
|
1149
|
+
cycle: loader.q36 / 20,
|
|
1167
1150
|
filterMode,
|
|
1168
1151
|
filterModeName: enumValueName(LOADER_FILTER_MODE_NAMES, filterMode),
|
|
1169
|
-
filterSlots:
|
|
1152
|
+
filterSlots: filterSlotsRecord
|
|
1153
|
+
? [filterSlotsRecord.q20, filterSlotsRecord.q24, filterSlotsRecord.q28].map(value => value || null)
|
|
1154
|
+
: null,
|
|
1170
1155
|
heldItemId: heldItem.itemId,
|
|
1171
1156
|
heldItemName: heldItem.itemName,
|
|
1172
1157
|
heldCount: heldItem.count,
|
|
@@ -1206,7 +1191,7 @@ export function summarizePusher(entity, pusherRecord, filterSlotsRecord = null)
|
|
|
1206
1191
|
filteredModeName: enumValueName(PUSHER_MODE_NAMES, filteredMode),
|
|
1207
1192
|
angle: numberOrNull(pusherRecord.q28, 10),
|
|
1208
1193
|
speed: pusherRecord.q32 == null ? 20 : (pusherRecord.q32 / 100) + 20,
|
|
1209
|
-
length:
|
|
1194
|
+
length: 1000 + (pusherRecord.q40 ?? 0) / 10,
|
|
1210
1195
|
filterInventory: pusherRecord.q36 === 1,
|
|
1211
1196
|
filterSlots: filterSlotsRecord ? [filterSlotsRecord.q20 ?? null, filterSlotsRecord.q24 ?? null, filterSlotsRecord.q28 ?? null] : null,
|
|
1212
1197
|
state: cloneRecord(pusherRecord),
|