t2-demo-parser 1.0.2 → 2.0.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.
Files changed (39) hide show
  1. package/README.md +201 -87
  2. package/dist/DataBlockParsers.d.ts.map +1 -1
  3. package/dist/DataBlockParsers.js +51 -42
  4. package/dist/DataBlockParsers.js.map +1 -1
  5. package/dist/DataBlockParsers.test.js +32 -0
  6. package/dist/DataBlockParsers.test.js.map +1 -1
  7. package/dist/DemoParser.d.ts.map +1 -1
  8. package/dist/DemoParser.js +43 -8
  9. package/dist/DemoParser.js.map +1 -1
  10. package/dist/GhostManager.d.ts.map +1 -1
  11. package/dist/GhostManager.js +36 -68
  12. package/dist/GhostManager.js.map +1 -1
  13. package/dist/GhostStateAccumulator.d.ts +36 -0
  14. package/dist/GhostStateAccumulator.d.ts.map +1 -0
  15. package/dist/GhostStateAccumulator.js +124 -0
  16. package/dist/GhostStateAccumulator.js.map +1 -0
  17. package/dist/GhostStateAccumulator.test.d.ts +2 -0
  18. package/dist/GhostStateAccumulator.test.d.ts.map +1 -0
  19. package/dist/GhostStateAccumulator.test.js +201 -0
  20. package/dist/GhostStateAccumulator.test.js.map +1 -0
  21. package/dist/LiveParser.d.ts +39 -1
  22. package/dist/LiveParser.d.ts.map +1 -1
  23. package/dist/LiveParser.js +43 -1
  24. package/dist/LiveParser.js.map +1 -1
  25. package/dist/PacketParser.d.ts +23 -2
  26. package/dist/PacketParser.d.ts.map +1 -1
  27. package/dist/PacketParser.js +62 -19
  28. package/dist/PacketParser.js.map +1 -1
  29. package/dist/dataBlockDataTypes.d.ts +22 -21
  30. package/dist/dataBlockDataTypes.d.ts.map +1 -1
  31. package/dist/dataBlockDataTypes.js.map +1 -1
  32. package/dist/index.d.ts +4 -3
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +3 -2
  35. package/dist/index.js.map +1 -1
  36. package/dist/types.d.ts +11 -0
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/types.js.map +1 -1
  39. package/package.json +1 -1
@@ -129,6 +129,38 @@ describe("projectile datablock field decoding", () => {
129
129
  expect(armor.underwaterJetEnergyDrain).toBeLessThan(5);
130
130
  expect(armor.minJetEnergy).toBeGreaterThanOrEqual(0);
131
131
  expect(armor.minJetEnergy).toBeLessThan(10);
132
+ // Heat signature rates — retail player.cs: 1/4 and 1/3. These are the
133
+ // first two reads of the ground-impact tail; the old decode shifted
134
+ // the whole section by two slots.
135
+ expect(armor.heatDecayPerSec).toBeCloseTo(0.25, 5);
136
+ expect(armor.heatIncreasePerSec).toBeCloseTo(1 / 3, 5);
137
+ expect(armor.groundImpactShakeDuration).toBeCloseTo(0.6, 5);
138
+ expect(armor.groundImpactShakeFalloff).toBeCloseTo(10, 5);
139
+ });
140
+ it("decodes StationFX node names and textures exactly", async () => {
141
+ const dataBlocks = await loadDataBlocks("exogen_Katabatic_vpad.rec");
142
+ let vehicleFX;
143
+ let personalFX;
144
+ for (const [, db] of dataBlocks) {
145
+ if (db.className === "StationFXVehicleData")
146
+ vehicleFX ??= db.data;
147
+ if (db.className === "StationFXPersonalData")
148
+ personalFX ??= db.data;
149
+ }
150
+ // serverVehicleHud.cs VehicleInvFX values.
151
+ expect(vehicleFX, "StationFXVehicleData").toBeDefined();
152
+ expect(vehicleFX.glowNodeName).toBe("GLOWFX");
153
+ expect(vehicleFX.leftNodeName0).toBe("LFX1");
154
+ expect(vehicleFX.rightNodeName0).toBe("RFX1");
155
+ expect(vehicleFX.leftNodeName3).toBe("LFX4");
156
+ expect(vehicleFX.rightNodeName3).toBe("RFX4");
157
+ expect(vehicleFX.texture0).toBe("special/stationGlow");
158
+ expect(vehicleFX.texture1).toBe("special/stationLight2");
159
+ // station.cs personal FX values.
160
+ expect(personalFX, "StationFXPersonalData").toBeDefined();
161
+ expect(personalFX.leftNodeName).toBe("FX1");
162
+ expect(personalFX.rightNodeName).toBe("FX2");
163
+ expect(personalFX.texture0).toBe("special/stationLight");
132
164
  });
133
165
  });
134
166
  //# sourceMappingURL=DataBlockParsers.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataBlockParsers.test.js","sourceRoot":"","sources":["../src/DataBlockParsers.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { DemoParser } from \"./DemoParser.js\";\nimport type {\n LinearProjectileDataBlock,\n PlayerDataBlock,\n TracerProjectileDataBlock,\n} from \"./dataBlockDataTypes.js\";\n\nconst DEMO_DIR = path.resolve(import.meta.dirname, \"..\", \"data\");\n\nasync function loadDataBlocks(file: string) {\n const buffer = fs.readFileSync(path.join(DEMO_DIR, file));\n const parser = new DemoParser(new Uint8Array(buffer));\n const { initialBlock } = await parser.load();\n return initialBlock.dataBlocks;\n}\n\n/**\n * Regression tests for projectile datablock field naming, which was\n * binary-verified against Tribes2.exe build 25034 (initPersistFields\n * FUN_0062b3c0 / FUN_0063fcb0 map names to the struct offsets that\n * unpackData reads in order). Prior to that verification several fields\n * were misassigned — most damagingly, the true lifetimeMS landed in a\n * field named `fizzleType`, breaking client-side projectile simulation.\n */\ndescribe(\"projectile datablock field decoding\", () => {\n it(\"decodes LinearProjectileData fields with engine semantics\", async () => {\n const dataBlocks = await loadDataBlocks(\"exogen_Katabatic_vpad.rec\");\n const linears: LinearProjectileDataBlock[] = [];\n for (const [, db] of dataBlocks) {\n if (\n db.className === \"LinearProjectileData\" ||\n db.className === \"TracerProjectileData\" ||\n db.className === \"LinearFlareProjectileData\"\n ) {\n linears.push(db.data as LinearProjectileDataBlock);\n }\n }\n expect(linears.length).toBeGreaterThan(0);\n\n for (const block of linears) {\n // lifetimeMS/fizzleTimeMS are real milliseconds, rounded up to a\n // 32ms tick by the engine's onAdd, and clamped to 511 ticks.\n expect(block.lifetimeMS! % 32).toBe(0);\n expect(block.lifetimeMS).toBeGreaterThanOrEqual(32);\n expect(block.lifetimeMS).toBeLessThanOrEqual(511 * 32);\n expect(block.fizzleTimeMS! % 32).toBe(0);\n // Angles are ranged 0–90 degrees on the wire.\n expect(block.reflectOnWaterImpactAngle).toBeGreaterThanOrEqual(0);\n expect(block.reflectOnWaterImpactAngle).toBeLessThanOrEqual(90);\n expect(typeof block.explodeOnDeath).toBe(\"boolean\");\n expect(typeof block.doDynamicClientHits).toBe(\"boolean\");\n }\n });\n\n it(\"decodes retail DiscProjectile exactly\", async () => {\n const dataBlocks = await loadDataBlocks(\"exogen_Katabatic_vpad.rec\");\n let disc: LinearProjectileDataBlock | undefined;\n for (const [, db] of dataBlocks) {\n const data = db.data as LinearProjectileDataBlock;\n if (\n db.className === \"LinearProjectileData\" &&\n data.dryVelocity === 90 &&\n data.explodeOnDeath === true\n ) {\n disc = data;\n break;\n }\n }\n expect(disc, \"retail DiscProjectile datablock\").toBeDefined();\n // disc.cs: lifetimeMS = fizzleTimeMS = 5000 → tick-rounded to 5024.\n expect(disc!.lifetimeMS).toBe(5024);\n expect(disc!.fizzleTimeMS).toBe(5024);\n // disc.cs: reflectOnWaterImpactAngle = 15.0.\n expect(disc!.reflectOnWaterImpactAngle).toBe(15);\n });\n\n it(\"decodes retail ChaingunBullet tracer fields exactly\", async () => {\n const dataBlocks = await loadDataBlocks(\"exogen_Katabatic_vpad.rec\");\n let bullet: TracerProjectileDataBlock | undefined;\n for (const [, db] of dataBlocks) {\n const data = db.data as TracerProjectileDataBlock;\n if (\n db.className === \"TracerProjectileData\" &&\n data.tracerTex0 === \"special/tracer00\" &&\n data.lifetimeMS === 3008\n ) {\n bullet = data;\n break;\n }\n }\n expect(bullet, \"ChaingunBullet datablock\").toBeDefined();\n // Values as recorded in this demo (a lightly modded server — tracer\n // length/width are doubled from retail, everything else matches\n // chaingun.cs). Each assertion pins a decode position: a swap with\n // any neighboring field would produce a nonsensical value here.\n expect(bullet!.dryVelocity).toBe(750);\n expect(bullet!.wetVelocity).toBe(280);\n expect(bullet!.fizzleTimeMS).toBe(3008);\n expect(bullet!.explodeOnDeath).toBe(false);\n // Chainguns are the only retail weapons with doDynamicClientHits.\n expect(bullet!.doDynamicClientHits).toBe(true);\n // activateDelayMS = -1 (retail default) read as U32.\n expect(bullet!.activateDelayMS).toBe(0xffffffff);\n expect(bullet!.tracerLength).toBe(30);\n expect(bullet!.tracerMinPixels).toBe(6);\n expect(bullet!.tracerWidth).toBeCloseTo(0.2, 5);\n expect(bullet!.tracerAlpha).toBe(false);\n // Retail chaingun.cs tracerColor: 211/255, 215/255, 120/255, 0.75.\n expect(bullet!.tracerColor!.r).toBeCloseTo(211 / 255, 2);\n expect(bullet!.tracerColor!.g).toBeCloseTo(215 / 255, 2);\n expect(bullet!.tracerColor!.b).toBeCloseTo(120 / 255, 2);\n expect(bullet!.crossViewAng).toBeCloseTo(0.99, 5);\n expect(bullet!.crossSize).toBeCloseTo(0.2, 5);\n expect(bullet!.renderCross).toBe(true);\n expect(bullet!.tracerTex1).toBe(\"special/tracercross\");\n });\n\n it(\"decodes PlayerData movement/jet fields with engine semantics\", async () => {\n const dataBlocks = await loadDataBlocks(\"exogen_Katabatic_vpad.rec\");\n let armor: PlayerDataBlock | undefined;\n for (const [, db] of dataBlocks) {\n const data = db.data as PlayerDataBlock;\n // The armor the recorder wears: retail-value run/speed section.\n if (db.className === \"PlayerData\" && data.maxForwardSpeed === 15) {\n armor = data;\n break;\n }\n }\n expect(armor, \"light armor PlayerData datablock\").toBeDefined();\n // Retail player.cs values — each pins a decode position (previously\n // these landed in fields named jumpForce/runSurfaceAngle/etc.).\n expect(armor!.runForce).toBe(4968); // 55.2 * 90\n expect(armor!.maxBackwardSpeed).toBe(13);\n expect(armor!.maxSideSpeed).toBe(13);\n expect(armor!.underwaterVertJetFactor).toBeCloseTo(1.5, 5);\n expect(armor!.minLookAngle).toBeCloseTo(-1.5, 5);\n expect(armor!.maxLookAngle).toBeCloseTo(1.5, 5);\n // Jet energy fields must decode as plausible per-tick magnitudes\n // (this server mods them slightly, so no exact match): drain is a\n // fraction of maxEnergy(60), threshold is a small energy value.\n expect(armor!.jetEnergyDrain).toBeGreaterThan(0);\n expect(armor!.jetEnergyDrain).toBeLessThan(5);\n expect(armor!.underwaterJetEnergyDrain).toBeGreaterThan(0);\n expect(armor!.underwaterJetEnergyDrain).toBeLessThan(5);\n expect(armor!.minJetEnergy).toBeGreaterThanOrEqual(0);\n expect(armor!.minJetEnergy).toBeLessThan(10);\n });\n});\n"]}
1
+ {"version":3,"file":"DataBlockParsers.test.js","sourceRoot":"","sources":["../src/DataBlockParsers.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { DemoParser } from \"./DemoParser.js\";\nimport type {\n LinearProjectileDataBlock,\n PlayerDataBlock,\n TracerProjectileDataBlock,\n} from \"./dataBlockDataTypes.js\";\n\nconst DEMO_DIR = path.resolve(import.meta.dirname, \"..\", \"data\");\n\nasync function loadDataBlocks(file: string) {\n const buffer = fs.readFileSync(path.join(DEMO_DIR, file));\n const parser = new DemoParser(new Uint8Array(buffer));\n const { initialBlock } = await parser.load();\n return initialBlock.dataBlocks;\n}\n\n/**\n * Regression tests for projectile datablock field naming, which was\n * binary-verified against Tribes2.exe build 25034 (initPersistFields\n * FUN_0062b3c0 / FUN_0063fcb0 map names to the struct offsets that\n * unpackData reads in order). Prior to that verification several fields\n * were misassigned — most damagingly, the true lifetimeMS landed in a\n * field named `fizzleType`, breaking client-side projectile simulation.\n */\ndescribe(\"projectile datablock field decoding\", () => {\n it(\"decodes LinearProjectileData fields with engine semantics\", async () => {\n const dataBlocks = await loadDataBlocks(\"exogen_Katabatic_vpad.rec\");\n const linears: LinearProjectileDataBlock[] = [];\n for (const [, db] of dataBlocks) {\n if (\n db.className === \"LinearProjectileData\" ||\n db.className === \"TracerProjectileData\" ||\n db.className === \"LinearFlareProjectileData\"\n ) {\n linears.push(db.data as LinearProjectileDataBlock);\n }\n }\n expect(linears.length).toBeGreaterThan(0);\n\n for (const block of linears) {\n // lifetimeMS/fizzleTimeMS are real milliseconds, rounded up to a\n // 32ms tick by the engine's onAdd, and clamped to 511 ticks.\n expect(block.lifetimeMS! % 32).toBe(0);\n expect(block.lifetimeMS).toBeGreaterThanOrEqual(32);\n expect(block.lifetimeMS).toBeLessThanOrEqual(511 * 32);\n expect(block.fizzleTimeMS! % 32).toBe(0);\n // Angles are ranged 0–90 degrees on the wire.\n expect(block.reflectOnWaterImpactAngle).toBeGreaterThanOrEqual(0);\n expect(block.reflectOnWaterImpactAngle).toBeLessThanOrEqual(90);\n expect(typeof block.explodeOnDeath).toBe(\"boolean\");\n expect(typeof block.doDynamicClientHits).toBe(\"boolean\");\n }\n });\n\n it(\"decodes retail DiscProjectile exactly\", async () => {\n const dataBlocks = await loadDataBlocks(\"exogen_Katabatic_vpad.rec\");\n let disc: LinearProjectileDataBlock | undefined;\n for (const [, db] of dataBlocks) {\n const data = db.data as LinearProjectileDataBlock;\n if (\n db.className === \"LinearProjectileData\" &&\n data.dryVelocity === 90 &&\n data.explodeOnDeath === true\n ) {\n disc = data;\n break;\n }\n }\n expect(disc, \"retail DiscProjectile datablock\").toBeDefined();\n // disc.cs: lifetimeMS = fizzleTimeMS = 5000 → tick-rounded to 5024.\n expect(disc!.lifetimeMS).toBe(5024);\n expect(disc!.fizzleTimeMS).toBe(5024);\n // disc.cs: reflectOnWaterImpactAngle = 15.0.\n expect(disc!.reflectOnWaterImpactAngle).toBe(15);\n });\n\n it(\"decodes retail ChaingunBullet tracer fields exactly\", async () => {\n const dataBlocks = await loadDataBlocks(\"exogen_Katabatic_vpad.rec\");\n let bullet: TracerProjectileDataBlock | undefined;\n for (const [, db] of dataBlocks) {\n const data = db.data as TracerProjectileDataBlock;\n if (\n db.className === \"TracerProjectileData\" &&\n data.tracerTex0 === \"special/tracer00\" &&\n data.lifetimeMS === 3008\n ) {\n bullet = data;\n break;\n }\n }\n expect(bullet, \"ChaingunBullet datablock\").toBeDefined();\n // Values as recorded in this demo (a lightly modded server — tracer\n // length/width are doubled from retail, everything else matches\n // chaingun.cs). Each assertion pins a decode position: a swap with\n // any neighboring field would produce a nonsensical value here.\n expect(bullet!.dryVelocity).toBe(750);\n expect(bullet!.wetVelocity).toBe(280);\n expect(bullet!.fizzleTimeMS).toBe(3008);\n expect(bullet!.explodeOnDeath).toBe(false);\n // Chainguns are the only retail weapons with doDynamicClientHits.\n expect(bullet!.doDynamicClientHits).toBe(true);\n // activateDelayMS = -1 (retail default) read as U32.\n expect(bullet!.activateDelayMS).toBe(0xffffffff);\n expect(bullet!.tracerLength).toBe(30);\n expect(bullet!.tracerMinPixels).toBe(6);\n expect(bullet!.tracerWidth).toBeCloseTo(0.2, 5);\n expect(bullet!.tracerAlpha).toBe(false);\n // Retail chaingun.cs tracerColor: 211/255, 215/255, 120/255, 0.75.\n expect(bullet!.tracerColor!.r).toBeCloseTo(211 / 255, 2);\n expect(bullet!.tracerColor!.g).toBeCloseTo(215 / 255, 2);\n expect(bullet!.tracerColor!.b).toBeCloseTo(120 / 255, 2);\n expect(bullet!.crossViewAng).toBeCloseTo(0.99, 5);\n expect(bullet!.crossSize).toBeCloseTo(0.2, 5);\n expect(bullet!.renderCross).toBe(true);\n expect(bullet!.tracerTex1).toBe(\"special/tracercross\");\n });\n\n it(\"decodes PlayerData movement/jet fields with engine semantics\", async () => {\n const dataBlocks = await loadDataBlocks(\"exogen_Katabatic_vpad.rec\");\n let armor: PlayerDataBlock | undefined;\n for (const [, db] of dataBlocks) {\n const data = db.data as PlayerDataBlock;\n // The armor the recorder wears: retail-value run/speed section.\n if (db.className === \"PlayerData\" && data.maxForwardSpeed === 15) {\n armor = data;\n break;\n }\n }\n expect(armor, \"light armor PlayerData datablock\").toBeDefined();\n // Retail player.cs values — each pins a decode position (previously\n // these landed in fields named jumpForce/runSurfaceAngle/etc.).\n expect(armor!.runForce).toBe(4968); // 55.2 * 90\n expect(armor!.maxBackwardSpeed).toBe(13);\n expect(armor!.maxSideSpeed).toBe(13);\n expect(armor!.underwaterVertJetFactor).toBeCloseTo(1.5, 5);\n expect(armor!.minLookAngle).toBeCloseTo(-1.5, 5);\n expect(armor!.maxLookAngle).toBeCloseTo(1.5, 5);\n // Jet energy fields must decode as plausible per-tick magnitudes\n // (this server mods them slightly, so no exact match): drain is a\n // fraction of maxEnergy(60), threshold is a small energy value.\n expect(armor!.jetEnergyDrain).toBeGreaterThan(0);\n expect(armor!.jetEnergyDrain).toBeLessThan(5);\n expect(armor!.underwaterJetEnergyDrain).toBeGreaterThan(0);\n expect(armor!.underwaterJetEnergyDrain).toBeLessThan(5);\n expect(armor!.minJetEnergy).toBeGreaterThanOrEqual(0);\n expect(armor!.minJetEnergy).toBeLessThan(10);\n // Heat signature rates — retail player.cs: 1/4 and 1/3. These are the\n // first two reads of the ground-impact tail; the old decode shifted\n // the whole section by two slots.\n expect(armor!.heatDecayPerSec).toBeCloseTo(0.25, 5);\n expect(armor!.heatIncreasePerSec).toBeCloseTo(1 / 3, 5);\n expect(armor!.groundImpactShakeDuration).toBeCloseTo(0.6, 5);\n expect(armor!.groundImpactShakeFalloff).toBeCloseTo(10, 5);\n });\n\n it(\"decodes StationFX node names and textures exactly\", async () => {\n const dataBlocks = await loadDataBlocks(\"exogen_Katabatic_vpad.rec\");\n let vehicleFX: Record<string, unknown> | undefined;\n let personalFX: Record<string, unknown> | undefined;\n for (const [, db] of dataBlocks) {\n if (db.className === \"StationFXVehicleData\") vehicleFX ??= db.data;\n if (db.className === \"StationFXPersonalData\") personalFX ??= db.data;\n }\n // serverVehicleHud.cs VehicleInvFX values.\n expect(vehicleFX, \"StationFXVehicleData\").toBeDefined();\n expect(vehicleFX!.glowNodeName).toBe(\"GLOWFX\");\n expect(vehicleFX!.leftNodeName0).toBe(\"LFX1\");\n expect(vehicleFX!.rightNodeName0).toBe(\"RFX1\");\n expect(vehicleFX!.leftNodeName3).toBe(\"LFX4\");\n expect(vehicleFX!.rightNodeName3).toBe(\"RFX4\");\n expect(vehicleFX!.texture0).toBe(\"special/stationGlow\");\n expect(vehicleFX!.texture1).toBe(\"special/stationLight2\");\n // station.cs personal FX values.\n expect(personalFX, \"StationFXPersonalData\").toBeDefined();\n expect(personalFX!.leftNodeName).toBe(\"FX1\");\n expect(personalFX!.rightNodeName).toBe(\"FX2\");\n expect(personalFX!.texture0).toBe(\"special/stationLight\");\n });\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"DemoParser.d.ts","sourceRoot":"","sources":["../src/DemoParser.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,YAAY,EAAwB,MAAM,mBAAmB,CAAC;AAuBvE,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,gBAAgB,EAWhB,UAAU,EACX,MAAM,YAAY,CAAC;AAMpB,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAe;IAEnC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAC,CAAa;IAC7B,OAAO,CAAC,aAAa,CAAC,CAAmB;IACzC,OAAO,CAAC,iBAAiB,CAAC,CAAa;IACvC,OAAO,CAAC,iBAAiB,CAAC,CAAW;IACrC,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAK;gBAEb,MAAM,EAAE,UAAU;IA+D9B,WAAW,IAAI,aAAa;IAI5B,eAAe,IAAI,YAAY;IAI/B,eAAe,IAAI,YAAY;IAM/B,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,MAAM,IAAI,UAAU,CAGvB;IAED,IAAI,YAAY,IAAI,gBAAgB,CAGnC;IAED,IAAI,UAAU,IAAI,MAAM,CAkBvB;IAED,IAAI,WAAW,IAAI,MAAM,CAGxB;IAID;;;;;;OAMG;IACG,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IAwDjC;;;;;OAKG;IACH,SAAS,IAAI,SAAS,GAAG,SAAS;IAwDlC;;;;;OAKG;IACH,KAAK,IAAI,IAAI;IAWb;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUpC;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,QAAQ,CAAC;IAQxC,OAAO,CAAC,UAAU;IAwBlB;4DACwD;IACxD,OAAO,CAAC,gBAAgB;IA0OxB;;;OAGG;IACH,OAAO,CAAC,cAAc;IActB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;;;OAMG;IACH,OAAO,CAAC,wBAAwB;IA6EhC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,eAAe;IAoBvB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,mBAAmB;IAyD3B,OAAO,CAAC,mBAAmB;IA8F3B;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IA2DtB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IAuCjC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,WAAW;IA6BnB;;;OAGG;IACH,OAAO,CAAC,aAAa;CAOtB"}
1
+ {"version":3,"file":"DemoParser.d.ts","sourceRoot":"","sources":["../src/DemoParser.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,YAAY,EAAwB,MAAM,mBAAmB,CAAC;AAuBvE,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,gBAAgB,EAWhB,UAAU,EACX,MAAM,YAAY,CAAC;AAMpB,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAe;IAEnC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAC,CAAa;IAC7B,OAAO,CAAC,aAAa,CAAC,CAAmB;IACzC,OAAO,CAAC,iBAAiB,CAAC,CAAa;IACvC,OAAO,CAAC,iBAAiB,CAAC,CAAW;IACrC,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAK;gBAEb,MAAM,EAAE,UAAU;IAyE9B,WAAW,IAAI,aAAa;IAI5B,eAAe,IAAI,YAAY;IAI/B,eAAe,IAAI,YAAY;IAM/B,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,MAAM,IAAI,UAAU,CAGvB;IAED,IAAI,YAAY,IAAI,gBAAgB,CAGnC;IAED,IAAI,UAAU,IAAI,MAAM,CAkBvB;IAED,IAAI,WAAW,IAAI,MAAM,CAGxB;IAID;;;;;;OAMG;IACG,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IA4DjC;;;;;OAKG;IACH,SAAS,IAAI,SAAS,GAAG,SAAS;IA2DlC;;;;;OAKG;IACH,KAAK,IAAI,IAAI;IAWb;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUpC;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IA8BzB;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,QAAQ,CAAC;IAQxC,OAAO,CAAC,UAAU;IAwBlB;4DACwD;IACxD,OAAO,CAAC,gBAAgB;IA4TxB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAuBtB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;;;OAMG;IACH,OAAO,CAAC,wBAAwB;IA6EhC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,eAAe;IAyBvB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,mBAAmB;IAmE3B,OAAO,CAAC,mBAAmB;IAuH3B;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAsEtB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IA4CjC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,WAAW;IA0CnB;;;OAGG;IACH,OAAO,CAAC,aAAa;CAOtB"}
@@ -270,6 +270,7 @@ export class DemoParser {
270
270
  dataBlockDataMap,
271
271
  connectionProtocolState: initialBlock.connectionState,
272
272
  nextRecvEventSeq: initialBlock.nextRecvEventSeq,
273
+ compressionPoint: initialBlock.initialCompressionPoint,
273
274
  });
274
275
  this.ghostTracker = gt;
275
276
  this.packetParser = pp;
@@ -406,13 +407,15 @@ export class DemoParser {
406
407
  let initialGhosts = [];
407
408
  let controlObjectGhostIndex = -1;
408
409
  let controlObjectData;
410
+ let initialCompressionPoint;
409
411
  let missionName = "";
410
412
  let missionCRC = 0;
411
413
  let phase2Error;
412
414
  try {
413
415
  debugInitial("phase2 start bit=%d remaining=%d", bs.getCurPos(), totalBits - bs.getCurPos());
414
416
  // B.10f Events
415
- ({ nextRecvEventSeq, events: initialEvents } = this.readEventStartBlock(bs));
417
+ ({ nextRecvEventSeq, events: initialEvents } =
418
+ this.readEventStartBlock(bs));
416
419
  debugInitial("after initial events bit=%d count=%d", bs.getCurPos(), initialEvents.length);
417
420
  // B.10g Ghosts
418
421
  const ghostResult = this.readGhostStartBlock(bs, dataBlocks);
@@ -428,11 +431,20 @@ export class DemoParser {
428
431
  if (ghost) {
429
432
  const parser = this.registry.getGhostParser(ghost.classId);
430
433
  if (parser?.readPacketData) {
434
+ // getGhostParser enables the nested vehicle readPacketData
435
+ // when the recorder was piloting at recording start — without
436
+ // it those bytes go unread and every later read in the
437
+ // initial block (mission name, CRC) is misaligned.
431
438
  const conn = {
432
439
  compressionPoint: { x: 0, y: 0, z: 0 },
433
440
  ghostTracker: ibGhostTracker,
441
+ getGhostParser: (classId) => this.registry.getGhostParser(classId),
434
442
  };
435
443
  controlObjectData = parser.readPacketData(bs, conn);
444
+ // The control object's readPacketData establishes the
445
+ // connection's compression point (its position) — carry it
446
+ // into the packet parser seed.
447
+ initialCompressionPoint = conn.compressionPoint;
436
448
  debugInitial("after control readPacketData bit=%d parser=%s", bs.getCurPos(), parser.name);
437
449
  }
438
450
  }
@@ -456,9 +468,7 @@ export class DemoParser {
456
468
  }
457
469
  const remaining = totalBits - bs.getCurPos();
458
470
  const missionPrintableRatio = missionName.length > 0
459
- ? missionName
460
- .split("")
461
- .filter((c) => {
471
+ ? missionName.split("").filter((c) => {
462
472
  const code = c.charCodeAt(0);
463
473
  return code >= 0x20 && code <= 0x7e;
464
474
  }).length / missionName.length
@@ -490,6 +500,7 @@ export class DemoParser {
490
500
  initialEvents,
491
501
  controlObjectGhostIndex,
492
502
  controlObjectData,
503
+ initialCompressionPoint,
493
504
  missionName,
494
505
  missionCRC,
495
506
  phase2TrailingBits: remaining,
@@ -513,7 +524,16 @@ export class DemoParser {
513
524
  const triggerFlags = [];
514
525
  for (let i = 0; i < 6; i++)
515
526
  triggerFlags.push(bs.readFlag());
516
- return { clientId, teamId, score, field0, field1, field2, isBot, triggerFlags };
527
+ return {
528
+ clientId,
529
+ teamId,
530
+ score,
531
+ field0,
532
+ field1,
533
+ field2,
534
+ isBot,
535
+ triggerFlags,
536
+ };
517
537
  }
518
538
  /**
519
539
  * Read DemoValues from FUN_005fb5c0 lines 388966-388980.
@@ -696,6 +716,7 @@ export class DemoParser {
696
716
  guaranteed: true,
697
717
  dataBitsStart,
698
718
  dataBitsEnd: dataBitsStart,
719
+ failed: true,
699
720
  });
700
721
  break;
701
722
  }
@@ -707,6 +728,7 @@ export class DemoParser {
707
728
  guaranteed: true,
708
729
  dataBitsStart,
709
730
  dataBitsEnd: dataBitsStart,
731
+ failed: true,
710
732
  });
711
733
  break;
712
734
  }
@@ -923,9 +945,22 @@ export class DemoParser {
923
945
  trigger.push(data[57 + i] !== 0);
924
946
  }
925
947
  return {
926
- px, py, pz, pyaw, ppitch, proll,
927
- x, y, z, yaw, pitch, roll,
928
- id, sendCount, freeLook, trigger,
948
+ px,
949
+ py,
950
+ pz,
951
+ pyaw,
952
+ ppitch,
953
+ proll,
954
+ x,
955
+ y,
956
+ z,
957
+ yaw,
958
+ pitch,
959
+ roll,
960
+ id,
961
+ sendCount,
962
+ freeLook,
963
+ trigger,
929
964
  };
930
965
  }
931
966
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"DemoParser.js","sourceRoot":"","sources":["../src/DemoParser.ts"],"names":[],"mappings":"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","sourcesContent":["import { inflate } from \"fflate\";\nimport createDebug from \"debug\";\nimport { BitStream } from \"./BitStream.js\";\nimport { PacketParser } from \"./PacketParser.js\";\nimport { ClassRegistry } from \"./ClassRegistry.js\";\nimport type { GhostParserEntry } from \"./ClassRegistry.js\";\nimport { GhostTracker, registerGhostParsers } from \"./GhostManager.js\";\nimport { registerEventParsers } from \"./EventParsers.js\";\nimport { registerDataBlockParsers } from \"./DataBlockParsers.js\";\nimport {\n BlockTypePacket,\n BlockTypeSendPacket,\n BlockTypeMove,\n BlockTypeInfo,\n MaxTriggerKeys,\n NetEventClassBitSize,\n NetEventClassFirst,\n NetObjectClassBitSize,\n NetObjectClassFirst,\n GhostIdBitSize,\n DataBlockClassFirst,\n DataBlockClassNames,\n NetObjectClassNames,\n NetEventClassNames,\n SimDBEventObjectIdBits,\n SimDBEventClassIdBits,\n SimDBEventIndexBits,\n SimDBEventTotalBits,\n} from \"./types.js\";\nimport type {\n DemoHeader,\n DemoFile,\n DemoBlock,\n InitialBlockData,\n ConnectionProtocolState,\n DataBlockHeader,\n ParsedDataBlock,\n PathManagerEntry,\n ScoreEntry,\n TargetEntry,\n Move,\n InfoBlock,\n GhostUpdate,\n NetEventInfo,\n LoadResult,\n} from \"./types.js\";\n\nconst debug = createDebug(\"t2-demo-parser\");\nconst debugInitial = createDebug(\"t2-demo-parser:initial\");\nconst debugBlocks = createDebug(\"t2-demo-parser:blocks\");\n\nexport class DemoParser {\n private buffer: Uint8Array;\n private view: DataView;\n private offset: number;\n private registry: ClassRegistry;\n private ghostTracker: GhostTracker;\n private packetParser: PacketParser;\n // Stepping API state\n private _loaded = false;\n private _header?: DemoHeader;\n private _initialBlock?: InitialBlockData;\n private _decompressedData?: Uint8Array;\n private _decompressedView?: DataView;\n private _blockStreamOffset = 0;\n private _blockCount?: number;\n private _blockCursor = 0;\n\n constructor(buffer: Uint8Array) {\n this.buffer = buffer;\n this.view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n this.offset = 0;\n this.registry = new ClassRegistry();\n this.ghostTracker = new GhostTracker();\n\n // Register parser catalogs\n registerEventParsers(this.registry);\n registerGhostParsers(this.registry);\n registerDataBlockParsers(this.registry);\n\n // Bind DataBlock parsers deterministically using the known class name\n // mapping derived from binary analysis of the Tribes 2 executable.\n // ClassIds are assigned alphabetically (C strcmp) starting at\n // DataBlockClassFirst (128).\n const { bound: dbBound, missing: dbMissing } =\n this.registry.bindDeterministicDataBlocks(\n DataBlockClassNames,\n DataBlockClassFirst\n );\n if (dbMissing.length > 0) {\n debug(\n \"DataBlock binding: %d/%d bound, missing parsers: %s\",\n dbBound, DataBlockClassNames.length, dbMissing.join(\", \")\n );\n }\n\n // Bind ghost (NetObject) parsers deterministically using the known\n // class name mapping derived from binary analysis. The 53 NetObject\n // classes are sorted alphabetically (C strcmp) and assigned sequential\n // classIds starting at NetObjectClassFirst (0).\n const { bound: ghostBound, missing: ghostMissing } =\n this.registry.bindDeterministicGhosts(\n NetObjectClassNames,\n NetObjectClassFirst\n );\n if (ghostMissing.length > 0) {\n debug(\n \"Ghost binding: %d/%d bound, missing parsers: %s\",\n ghostBound, NetObjectClassNames.length, ghostMissing.join(\", \")\n );\n }\n\n // Bind event (NetEvent) parsers deterministically using the known\n // class name mapping derived from binary analysis. The 26 NetEvent\n // classes are sorted alphabetically (C strcmp) and assigned sequential\n // classIds starting at NetEventClassFirst (255).\n const { bound: eventBound, missing: eventMissing } =\n this.registry.bindDeterministicEvents(\n NetEventClassNames,\n NetEventClassFirst\n );\n if (eventMissing.length > 0) {\n debug(\n \"Event binding: %d/%d bound, missing parsers: %s\",\n eventBound, NetEventClassNames.length, eventMissing.join(\", \")\n );\n }\n\n this.packetParser = new PacketParser(this.registry, this.ghostTracker);\n }\n\n getRegistry(): ClassRegistry {\n return this.registry;\n }\n\n getGhostTracker(): GhostTracker {\n return this.ghostTracker;\n }\n\n getPacketParser(): PacketParser {\n return this.packetParser;\n }\n\n // --- Stepping API getters ---\n\n get loaded(): boolean {\n return this._loaded;\n }\n\n get header(): DemoHeader {\n if (!this._loaded) throw new Error(\"must call load() first\");\n return this._header!;\n }\n\n get initialBlock(): InitialBlockData {\n if (!this._loaded) throw new Error(\"must call load() first\");\n return this._initialBlock!;\n }\n\n get blockCount(): number {\n if (!this._loaded) throw new Error(\"must call load() first\");\n if (this._blockCount === undefined) {\n // Lazy scan: walk decompressed buffer counting U16 headers\n const data = this._decompressedData!;\n const view = this._decompressedView!;\n let count = 0;\n let off = 0;\n while (off + 2 <= data.length) {\n const typeSize = view.getUint16(off, true);\n const size = typeSize & 0xfff;\n off += 2 + size;\n if (off > data.length) break;\n count++;\n }\n this._blockCount = count;\n }\n return this._blockCount;\n }\n\n get blockCursor(): number {\n if (!this._loaded) throw new Error(\"must call load() first\");\n return this._blockCursor;\n }\n\n // --- Stepping API methods ---\n\n /**\n * Async load: parses header, initial block (DataBlocks, events,\n * ghosts, control object, mission name), and asynchronously decompresses\n * the block stream. No block indexing — blocks are read lazily via nextBlock().\n *\n * Idempotent — second call returns cached result.\n */\n async load(): Promise<LoadResult> {\n if (this._loaded) {\n return {\n header: this._header!,\n initialBlock: this._initialBlock!,\n };\n }\n\n // Phase 1: header + initial block\n const header = this.readHeader();\n debug(\n 'header: \"%s\" version=0x%s length=%dms (%smin) initialBlockSize=%d',\n header.identString, header.protocolVersion.toString(16),\n header.demoLengthMs, (header.demoLengthMs / 1000 / 60).toFixed(1),\n header.initialBlockSize\n );\n\n const initialBlockData = this.buffer.subarray(\n this.offset,\n this.offset + header.initialBlockSize\n );\n const initialBlock = this.readInitialBlock(initialBlockData);\n this.offset += header.initialBlockSize;\n\n // Phase 2: async decompress block stream\n const compressedData = this.buffer.subarray(this.offset);\n debug(\"compressed block stream: %d bytes\", compressedData.length);\n\n const decompressedData = await new Promise<Uint8Array>((resolve, reject) => {\n inflate(compressedData, (err, data) => {\n if (err) reject(err);\n else resolve(data);\n });\n });\n debug(\"decompressed block stream: %d bytes\", decompressedData.length);\n\n this._decompressedData = decompressedData;\n this._decompressedView = new DataView(\n decompressedData.buffer,\n decompressedData.byteOffset,\n decompressedData.byteLength\n );\n\n // Phase 3: set up PacketParser with seeded ghost tracker\n this.setupPacketParser(initialBlock);\n\n // Cache results\n this._header = header;\n this._initialBlock = initialBlock;\n this._blockStreamOffset = 0;\n this._blockCursor = 0;\n this._loaded = true;\n\n return { header, initialBlock };\n }\n\n /**\n * Read and parse the next block from the decompressed buffer.\n * Returns the parsed block, or undefined when all blocks are exhausted.\n * Each block is transient — only one in memory at a time.\n * Throws if load() has not been called.\n */\n nextBlock(): DemoBlock | undefined {\n if (!this._loaded) throw new Error(\"must call load() first\");\n const data = this._decompressedData!;\n const view = this._decompressedView!;\n const off = this._blockStreamOffset;\n\n if (off + 2 > data.length) return undefined;\n\n const typeSize = view.getUint16(off, true);\n const type = typeSize >> 12;\n const size = typeSize & 0xfff;\n\n if (off + 2 + size > data.length) {\n debugBlocks(\n \"block %d: size %d would exceed decompressed data (offset=%d remaining=%d), stopping\",\n this._blockCursor, size, off + 2, data.length - off - 2\n );\n return undefined;\n }\n\n const blockData = data.subarray(off + 2, off + 2 + size);\n this._blockStreamOffset = off + 2 + size;\n\n const block: DemoBlock = {\n index: this._blockCursor,\n type,\n size,\n data: blockData,\n };\n this._blockCursor++;\n\n if (type === BlockTypePacket) {\n try {\n block.parsed = this.packetParser.parsePacket(blockData);\n } catch {\n // Skip unparseable packets\n }\n } else if (type === BlockTypeSendPacket) {\n this.packetParser.onSendPacketTrigger();\n } else if (type === BlockTypeMove && size === 64) {\n try {\n block.parsed = this.readRawMove(blockData);\n } catch {\n // Skip unparseable moves\n }\n } else if (type === BlockTypeInfo && size === 8) {\n try {\n block.parsed = this.readInfoBlock(blockData);\n } catch {\n // Skip unparseable info blocks\n }\n }\n\n return block;\n }\n\n /**\n * Reset stepping state: resets stream offset and cursor to 0,\n * clears cached block count, and re-initializes the PacketParser\n * with a fresh ghost tracker seeded from the initial block.\n * Throws if load() has not been called.\n */\n reset(): void {\n if (!this._loaded) throw new Error(\"must call load() first\");\n\n this._blockStreamOffset = 0;\n this._blockCursor = 0;\n this._blockCount = undefined;\n\n // Fresh ghost tracker + packet parser\n this.setupPacketParser(this._initialBlock!);\n }\n\n /**\n * Fast-forward through N blocks, processing each but not returning them.\n * Returns the number of blocks actually processed (may be less than count\n * if the stream is exhausted).\n * Throws if load() has not been called.\n */\n processBlocks(count: number): number {\n if (!this._loaded) throw new Error(\"must call load() first\");\n let processed = 0;\n for (let i = 0; i < count; i++) {\n if (!this.nextBlock()) break;\n processed++;\n }\n return processed;\n }\n\n /**\n * Set up a fresh PacketParser seeded from the initial block's ghosts\n * and with the DataBlock data map for ghost parsers. Replaces\n * this.ghostTracker and this.packetParser.\n */\n private setupPacketParser(initialBlock: InitialBlockData): void {\n // Build DataBlock data map (objectId → parsed data)\n const dataBlockDataMap = new Map<number, Record<string, unknown>>();\n for (const [objectId, db] of initialBlock.dataBlocks) {\n dataBlockDataMap.set(objectId, db.data);\n }\n\n // Seed ghost tracker from initial block ghosts\n const gt = new GhostTracker();\n for (const ghost of initialBlock.initialGhosts) {\n if (ghost.type !== \"create\" || ghost.classId === undefined) continue;\n const parserEntry = this.registry.getGhostParser(ghost.classId);\n gt.createGhost(\n ghost.index,\n ghost.classId,\n parserEntry?.name ?? `unknown_${ghost.classId}`\n );\n }\n\n const pp = new PacketParser(this.registry, gt, {\n dataBlockDataMap,\n connectionProtocolState: initialBlock.connectionState,\n nextRecvEventSeq: initialBlock.nextRecvEventSeq,\n });\n\n this.ghostTracker = gt;\n this.packetParser = pp;\n }\n\n /**\n * Full parse: async load + drain all blocks.\n */\n async parseFullDemo(): Promise<DemoFile> {\n const { header, initialBlock } = await this.load();\n const blocks: DemoBlock[] = [];\n let block: DemoBlock | undefined;\n while ((block = this.nextBlock())) blocks.push(block);\n return { header, initialBlock, blocks };\n }\n\n private readHeader(): DemoHeader {\n // Read the identification string: U8 length + string\n const strLen = this.view.getUint8(this.offset);\n this.offset += 1;\n const identString = new TextDecoder(\"ascii\").decode(\n this.buffer.subarray(this.offset, this.offset + strLen)\n );\n this.offset += strLen;\n\n // U32 protocol version\n const protocolVersion = this.view.getUint32(this.offset, true);\n this.offset += 4;\n\n // U32 demo length in ms\n const demoLengthMs = this.view.getUint32(this.offset, true);\n this.offset += 4;\n\n // U32 initial block size\n const initialBlockSize = this.view.getUint32(this.offset, true);\n this.offset += 4;\n\n return { identString, protocolVersion, demoLengthMs, initialBlockSize };\n }\n\n /** Parse the initial block: DataBlocks, scores, targets, connection state,\n * events, ghosts, control object, and mission name. */\n private readInitialBlock(data: Uint8Array): InitialBlockData {\n const bs = new BitStream(data);\n\n // --- A. Tagged string table (1024 entries) ---\n const taggedStrings = new Map<number, string>();\n for (let i = 0; i < 1024; i++) {\n if (bs.readFlag()) {\n taggedStrings.set(i, bs.readString());\n }\n }\n debugInitial(\"after tagged strings bit=%d count=%d\", bs.getCurPos(), taggedStrings.size);\n\n // --- B.1 U32 datablockCount ---\n const expectedDataBlockCount = bs.readU32();\n\n // --- B.2 DataBlock loop ---\n const dataBlockHeaders: DataBlockHeader[] = [];\n const dataBlocks = new Map<number, ParsedDataBlock>();\n let dataBlockCount = 0;\n\n while (bs.readFlag()) {\n dataBlockCount++;\n const modified = bs.readFlag();\n if (!modified) {\n continue;\n }\n\n const objectId = bs.readInt(SimDBEventObjectIdBits);\n const classId = bs.readInt(SimDBEventClassIdBits) + DataBlockClassFirst;\n const index = bs.readInt(SimDBEventIndexBits);\n const total = bs.readInt(SimDBEventTotalBits);\n const dataBitsStart = bs.getCurPos();\n\n dataBlockHeaders.push({ objectId, classId, index, total, dataBitsStart });\n\n const parserEntry = this.registry.getDataBlockParser(classId);\n if (parserEntry) {\n const parsedData = parserEntry.unpackData(bs);\n dataBlocks.set(objectId, {\n classId,\n className: parserEntry.name,\n objectId,\n data: parsedData,\n });\n } else {\n const className = classId >= DataBlockClassFirst &&\n classId < DataBlockClassFirst + DataBlockClassNames.length\n ? DataBlockClassNames[classId - DataBlockClassFirst]\n : `unknown(${classId})`;\n throw new Error(\n `No parser for DataBlock classId ${classId} (${className}) at bit ${dataBitsStart}`\n );\n }\n }\n\n debug(\n \"all %d/%d DataBlocks parsed (%d payloads), bit position after DataBlocks: %d\",\n dataBlockCount, expectedDataBlockCount, dataBlocks.size, bs.getCurPos()\n );\n\n // --- B.3 $firstPerson (U8 boolean from GameConnection::writeDemoStartBlock) ---\n const firstPerson = bs.readU8() !== 0;\n // --- B.4 6× U32 connection fields ---\n // @0x8384, @0x8388, @0x83f8, @0x83fc, @0x8400, @0x8434\n const connectionFields: number[] = [];\n for (let i = 0; i < 6; i++) connectionFields.push(bs.readU32());\n\n // --- B.5 16× U32 state array ---\n // @0x83b8 + i*4, i=0..15\n const stateArray: number[] = [];\n for (let i = 0; i < 16; i++) stateArray.push(bs.readU32());\n\n // --- B.6 U32 score entry count ---\n const scoreCount = bs.readU32();\n\n // --- B.7 Score entries × count (FUN_00601800) ---\n const scoreEntries: ScoreEntry[] = [];\n for (let i = 0; i < scoreCount; i++) {\n scoreEntries.push(this.readScoreEntry(bs));\n }\n debugInitial(\"after score entries bit=%d scoreCount=%d\", bs.getCurPos(), scoreCount);\n\n // B.8: FUN_005fb130 — clears internal state, no bitstream I/O\n\n // --- B.8 DemoValues ---\n const demoValues = this.readDemoValues(bs);\n debugInitial(\"after demo values bit=%d demoValues=%d\", bs.getCurPos(), demoValues.length);\n\n // --- B.9 Complex TargetManager (FUN_00670660) ---\n const { sensorGroupColors, targets: targetEntries } = this.readComplexTargetManager(bs);\n debugInitial(\"after complex target manager bit=%d targets=%d sensorGroupColors=%d\", bs.getCurPos(), targetEntries.length, sensorGroupColors.length);\n\n // --- B.10 Parent: NetConnection::readDemoStartBlock (FUN_00588260) ---\n\n // B.10a ConnectionProtocol (FUN_0043d820)\n const connectionState = this.readConnectionProtocol(bs);\n debugInitial(\n \"after connection protocol bit=%d lastRecv=%d highestAck=%d lastSend=%d connected=%s\",\n bs.getCurPos(), connectionState.lastSeqRecvd, connectionState.highestAckedSeq,\n connectionState.lastSendSeq, connectionState.connectionEstablished\n );\n\n // B.10b RTT, B.10c packet loss\n const roundTripTime = bs.readF32();\n const packetLoss = bs.readF32();\n debugInitial(\"after RTT/loss bit=%d rtt=%d loss=%d\", bs.getCurPos(), roundTripTime, packetLoss);\n\n // B.10d PathManager (FUN_00591ce0)\n const pathManager = this.readPathManager(bs);\n debugInitial(\"after path manager bit=%d entries=%d\", bs.getCurPos(), pathManager.length);\n\n // B.10e Notify count only (FUN_00588260).\n // The reader allocates notify nodes in memory but does not consume\n // per-notify records from the bitstream in this phase.\n const notifyCount = bs.readU32();\n debugInitial(\"after notify count bit=%d notifyCount=%d\", bs.getCurPos(), notifyCount);\n\n // --- B.10f through B.15: events, ghosts, control object, mission ---\n // Uses a temporary ghost tracker for initial-block ghost parsing only.\n const totalBits = bs.getBuffer().length * 8;\n const ibGhostTracker = new GhostTracker();\n const savedGhostTracker = this.ghostTracker;\n this.ghostTracker = ibGhostTracker;\n\n let initialEvents: NetEventInfo[] = [];\n let nextRecvEventSeq = 0;\n let ghostingSequence = 0;\n let initialGhosts: GhostUpdate[] = [];\n let controlObjectGhostIndex = -1;\n let controlObjectData: Record<string, unknown> | undefined;\n let missionName = \"\";\n let missionCRC = 0;\n let phase2Error: string | undefined;\n try {\n debugInitial(\"phase2 start bit=%d remaining=%d\", bs.getCurPos(), totalBits - bs.getCurPos());\n\n // B.10f Events\n ({ nextRecvEventSeq, events: initialEvents } = this.readEventStartBlock(bs));\n debugInitial(\"after initial events bit=%d count=%d\", bs.getCurPos(), initialEvents.length);\n\n // B.10g Ghosts\n const ghostResult = this.readGhostStartBlock(bs, dataBlocks);\n ghostingSequence = ghostResult.ghostingSequence;\n initialGhosts = ghostResult.ghosts;\n debugInitial(\"after initial ghosts bit=%d count=%d seq=%d\", bs.getCurPos(), initialGhosts.length, ghostingSequence);\n\n // B.11 controlObjectGhostIndex\n controlObjectGhostIndex = bs.readS32();\n debugInitial(\"after control ghost index bit=%d control=%d\", bs.getCurPos(), controlObjectGhostIndex);\n\n // B.12 If != -1: controlObject readPacketData\n if (controlObjectGhostIndex !== -1) {\n const ghost = ibGhostTracker.getGhost(controlObjectGhostIndex);\n if (ghost) {\n const parser = this.registry.getGhostParser(ghost.classId);\n if (parser?.readPacketData) {\n const conn = {\n compressionPoint: { x: 0, y: 0, z: 0 },\n ghostTracker: ibGhostTracker,\n };\n controlObjectData = parser.readPacketData(bs, conn);\n debugInitial(\"after control readPacketData bit=%d parser=%s\", bs.getCurPos(), parser.name);\n }\n }\n }\n\n // B.13 $MissionName\n missionName = bs.readString();\n // B.14 mMissionCRC\n missionCRC = bs.readU32();\n // Byte-align (validate) before SimpleTargetManagers\n bs.setCurPos(((bs.getCurPos() + 7) >> 3) << 3);\n // B.15 Simple TargetManager ×2\n this.readSimpleTargetManager(bs);\n this.readSimpleTargetManager(bs);\n debugInitial('after sequential tail bit=%d mission=\"%s\" CRC=0x%s', bs.getCurPos(), missionName, missionCRC.toString(16));\n } catch (e) {\n phase2Error = e instanceof Error ? e.message : String(e);\n } finally {\n this.ghostTracker = savedGhostTracker;\n }\n\n const remaining = totalBits - bs.getCurPos();\n const missionPrintableRatio = missionName.length > 0\n ? missionName\n .split(\"\")\n .filter((c) => {\n const code = c.charCodeAt(0);\n return code >= 0x20 && code <= 0x7e;\n }).length / missionName.length\n : 1;\n const phase2Valid =\n missionName.length > 0 &&\n missionPrintableRatio >= 0.8 &&\n phase2Error === undefined;\n\n debug(\n 'initial block: events=%d ghosts=%d ghostingSeq=%d controlObj=%d mission=\"%s\" CRC=0x%s valid=%s%s',\n initialEvents.length, initialGhosts.length, ghostingSequence,\n controlObjectGhostIndex, missionName, missionCRC.toString(16),\n phase2Valid, phase2Error ? ` error=${phase2Error}` : \"\"\n );\n\n return {\n taggedStrings,\n dataBlockHeaders,\n dataBlockCount,\n dataBlocks,\n firstPerson,\n connectionFields,\n stateArray,\n scoreEntries,\n demoValues,\n sensorGroupColors,\n targetEntries,\n connectionState,\n roundTripTime,\n packetLoss,\n pathManager,\n notifyCount,\n nextRecvEventSeq,\n ghostingSequence,\n initialGhosts,\n initialEvents,\n controlObjectGhostIndex,\n controlObjectData,\n missionName,\n missionCRC,\n phase2TrailingBits: remaining,\n phase2Valid,\n phase2Error,\n };\n }\n\n /**\n * Read a score entry from FUN_00601800.\n * Format: 3 conditional U16s + 3 U6s + 1 flag + 6 flags.\n */\n private readScoreEntry(bs: BitStream): ScoreEntry {\n const clientId = bs.readFlag() ? bs.readInt(16) : 0;\n const teamId = bs.readFlag() ? bs.readInt(16) : 0;\n const score = bs.readFlag() ? bs.readInt(16) : 0;\n const field0 = bs.readInt(6);\n const field1 = bs.readInt(6);\n const field2 = bs.readInt(6);\n // FUN_006014e0: post-processing, no stream reads\n const isBot = bs.readFlag();\n const triggerFlags: boolean[] = [];\n for (let i = 0; i < 6; i++) triggerFlags.push(bs.readFlag());\n return { clientId, teamId, score, field0, field1, field2, isBot, triggerFlags };\n }\n\n /**\n * Read DemoValues from FUN_005fb5c0 lines 388966-388980.\n * Format: while(readFlag()) { readString(value) }\n * Variable names are derived from index ($DemoValue_0, $DemoValue_1, etc.).\n */\n private readDemoValues(bs: BitStream): string[] {\n const values: string[] = [];\n while (bs.readFlag()) {\n values.push(bs.readString());\n }\n return values;\n }\n\n /**\n * Read Complex TargetManager from FUN_00670660.\n *\n * Phase 1: 4×U8 initial data\n * Phase 2: 32×32 grid — each cell: readFlag + if true: 4×U8\n * Phase 3: 512 target entries with conditional fields\n */\n private readComplexTargetManager(bs: BitStream): {\n sensorGroupColors: import(\"./types.js\").SensorGroupColor[];\n targets: TargetEntry[];\n } {\n // Phase 1: FUN_0043efe0 — read 4 bytes (4×U8)\n bs.readU8();\n bs.readU8();\n bs.readU8();\n bs.readU8();\n\n // Phase 2: 32×32 sensor group color grid (IFF colors).\n // sensorGroupColors[group][targetGroup] = RGBA determines how targetGroup\n // appears to group (e.g., red for enemy, green for friendly).\n const sensorGroupColors: import(\"./types.js\").SensorGroupColor[] = [];\n for (let group = 0; group < 32; group++) {\n for (let targetGroup = 0; targetGroup < 32; targetGroup++) {\n if (bs.readFlag()) {\n sensorGroupColors.push({\n group,\n targetGroup,\n r: bs.readU8(),\n g: bs.readU8(),\n b: bs.readU8(),\n a: bs.readU8(),\n });\n }\n }\n }\n\n // Phase 3: 512 target entries\n const targets: TargetEntry[] = [];\n for (let i = 0; i < 512; i++) {\n if (!bs.readFlag()) continue; // Target not active\n\n const entry: TargetEntry = {\n targetId: i,\n sensorGroup: 0,\n targetData: 0,\n damageLevel: 0,\n };\n\n // Conditional sensor data\n if (bs.readFlag()) {\n entry.sensorData = bs.readU32(); // F32 sensorData\n }\n // Conditional voice map data\n if (bs.readFlag()) {\n entry.voiceMapData = bs.readU32(); // F32 voiceMapData\n }\n // 5 conditional strings: name, skin, skinPref, voice, typeDescription\n if (bs.readFlag()) entry.name = bs.readString();\n if (bs.readFlag()) entry.skin = bs.readString();\n if (bs.readFlag()) entry.skinPref = bs.readString();\n if (bs.readFlag()) entry.voice = bs.readString();\n if (bs.readFlag()) entry.typeDescription = bs.readString();\n\n // Always-read fields\n entry.sensorGroup = bs.readInt(5); // team/type\n entry.targetData = bs.readInt(9); // target data\n\n // Targets >= 32 have additional DataBlock reference\n if (i >= 32) {\n if (bs.readFlag()) {\n entry.dataBlockRef = bs.readInt(11); // DataBlock reference (FUN_00436d10: readClassId)\n }\n // Virtual call notification — no bitstream I/O\n }\n\n // Damage level: readFloat(7) — always read for all active targets\n entry.damageLevel = bs.readFloat(7);\n\n targets.push(entry);\n }\n\n return { sensorGroupColors, targets };\n }\n\n /**\n * Read PathManager from FUN_00591ce0.\n * Decompiled format:\n * - U32 entryCount\n * - repeat entryCount:\n * - U32 entryId\n * - U32 recordCount\n * - repeat recordCount:\n * - U32 field0\n * - U32 field1\n * - U32 field2\n * - U32 auxField\n */\n private readPathManager(bs: BitStream): PathManagerEntry[] {\n const entries: PathManagerEntry[] = [];\n const entryCount = bs.readU32();\n for (let i = 0; i < entryCount; i++) {\n const entryId = bs.readU32();\n const recordCount = bs.readU32();\n const records: { field0: number; field1: number; field2: number; auxField: number }[] = [];\n for (let j = 0; j < recordCount; j++) {\n records.push({\n field0: bs.readU32(),\n field1: bs.readU32(),\n field2: bs.readU32(),\n auxField: bs.readU32(),\n });\n }\n entries.push({ entryId, records });\n }\n return entries;\n }\n\n /**\n * Read Simple TargetManager from FUN_006021b0.\n * Format: U8 flag + 4×U32 = 136 bits total.\n */\n private readSimpleTargetManager(bs: BitStream): void {\n bs.readU8(); // _read(1) = 8 bits\n bs.readU32(); // 4× _read(4)\n bs.readU32();\n bs.readU32();\n bs.readU32();\n }\n\n private readConnectionProtocol(bs: BitStream): ConnectionProtocolState {\n const lastSeqRecvdAtSend: number[] = [];\n for (let i = 0; i < 32; i++) {\n lastSeqRecvdAtSend.push(bs.readU32());\n }\n const lastSeqRecvd = bs.readU32();\n const highestAckedSeq = bs.readU32();\n const lastSendSeq = bs.readU32();\n const ackMask = bs.readU32();\n const connectSequence = bs.readU32();\n const lastRecvAckAck = bs.readU32();\n const connectionEstablished = bs.readBool();\n\n return {\n lastSeqRecvdAtSend,\n lastSeqRecvd,\n highestAckedSeq,\n lastSendSeq,\n ackMask,\n connectSequence,\n lastRecvAckAck,\n connectionEstablished,\n };\n }\n\n private readEventStartBlock(\n bs: BitStream\n ): { nextRecvEventSeq: number; events: NetEventInfo[] } {\n const nextRecvEventSeq = bs.readU32();\n const events: NetEventInfo[] = [];\n debugInitial(\"event block: nextRecvEventSeq=%d bit=%d\", nextRecvEventSeq, bs.getCurPos());\n while (bs.readFlag()) {\n const classId =\n bs.readInt(NetEventClassBitSize) + NetEventClassFirst;\n const dataBitsStart = bs.getCurPos();\n\n // Try to parse the event payload using the registry\n const parserEntry = this.registry.getEventParser(classId);\n let parsedData: Record<string, unknown> | undefined;\n\n if (parserEntry) {\n try {\n const conn = {\n compressionPoint: { x: 0, y: 0, z: 0 },\n ghostTracker: this.ghostTracker,\n getDataBlockParser: (cid: number) =>\n this.registry.getDataBlockParser(cid),\n };\n parsedData = parserEntry.unpack(bs, conn);\n } catch {\n // Can't parse — stop here\n events.push({\n classId,\n guaranteed: true,\n dataBitsStart,\n dataBitsEnd: dataBitsStart,\n });\n break;\n }\n } else {\n // No parser — can't advance past this event\n events.push({\n classId,\n guaranteed: true,\n dataBitsStart,\n dataBitsEnd: dataBitsStart,\n });\n break;\n }\n\n events.push({\n classId,\n guaranteed: true,\n dataBitsStart,\n dataBitsEnd: bs.getCurPos(),\n parsedData,\n });\n debugInitial(\" event classId=%d bits=%d\", classId, bs.getCurPos() - dataBitsStart);\n }\n return { nextRecvEventSeq, events };\n }\n\n private readGhostStartBlock(\n bs: BitStream,\n dataBlocks: Map<number, ParsedDataBlock>\n ): { ghostingSequence: number; ghosts: GhostUpdate[] } {\n const ghostingSequence = bs.readU32();\n const ghosts: GhostUpdate[] = [];\n debugInitial(\"ghost block: seq=%d bit=%d\", ghostingSequence, bs.getCurPos());\n const ghostCatalog = this.registry.getGhostCatalog();\n const totalBits = bs.getBuffer().length * 8;\n\n // Build DataBlock data lookup for ghost parsers that need it\n // (e.g., WheeledVehicle needs shape name to determine wheel count).\n const dataBlockDataMap = new Map<number, Record<string, unknown>>();\n for (const [objectId, db] of dataBlocks) {\n dataBlockDataMap.set(objectId, db.data);\n }\n\n while (bs.readFlag()) {\n if (bs.isError()) break;\n\n const index = bs.readInt(GhostIdBitSize);\n const classId =\n bs.readInt(NetObjectClassBitSize) + NetObjectClassFirst;\n const updateBitsStart = bs.getCurPos();\n\n // Build ordered list of parser candidates.\n // Registry binding (from deterministic classId) is preferred over\n // DataBlock-based identification because the classId is authoritative\n // while the DataBlock type may be a base class (e.g., StaticShapeData\n // used by a BeaconObject, which extends StaticShape with extra fields).\n const candidates: { entry: GhostParserEntry; method: string }[] = [];\n const seen = new Set<GhostParserEntry>();\n\n // Peek at DataBlock flag to identify ghost via DataBlock type\n const { entry: dbEntry } = this.identifyGhostViaDataBlock(bs, dataBlocks, ghostCatalog);\n\n // Candidate 1: registry binding (deterministic classId)\n const regEntry = this.registry.getGhostParser(classId);\n if (regEntry) {\n candidates.push({ entry: regEntry, method: \"registry\" });\n seen.add(regEntry);\n }\n\n // Candidate 2: DataBlock-based identification (fallback)\n if (dbEntry && !seen.has(dbEntry)) {\n candidates.push({ entry: dbEntry, method: \"datablock\" });\n seen.add(dbEntry);\n }\n\n // Try each candidate with alignment validation\n const connOverrides = {\n getDataBlockData: (objectId: number) => dataBlockDataMap.get(objectId),\n getDataBlockParser: (cid: number) => this.registry.getDataBlockParser(cid),\n };\n let parsed = false;\n for (const { entry, method } of candidates) {\n const isTrusted = method === \"registry\";\n const result = this.tryGhostParser(bs, entry, updateBitsStart, totalBits, false, connOverrides, isTrusted);\n if (result !== false) {\n this.ghostTracker.createGhost(index, classId, entry.name);\n debugInitial(\n \" ghost idx=%d classId=%d parser=%s bits=%d via=%s\",\n index, classId, entry.name, bs.getCurPos() - updateBitsStart, method\n );\n ghosts.push({\n index,\n type: \"create\",\n classId,\n updateBitsStart,\n updateBitsEnd: bs.getCurPos(),\n parsedData: result,\n });\n parsed = true;\n break;\n }\n }\n\n if (parsed) continue;\n\n // No candidate worked — stop parsing ghosts\n debugInitial(\n \" ghost idx=%d classId=%d NO PARSER (stopping at bit=%d, remaining=%d)\",\n index, classId, updateBitsStart, totalBits - updateBitsStart\n );\n break;\n }\n\n debugInitial(\n \"ghost loop ended at bit=%d remaining=%d count=%d\",\n bs.getCurPos(), totalBits - bs.getCurPos(), ghosts.length\n );\n return { ghostingSequence, ghosts };\n }\n\n /**\n * Try parsing a ghost with a given parser and validate alignment.\n * Returns true if parsing succeeded and alignment is valid.\n * On success, the BitStream is positioned after the parsed ghost data.\n * On failure, the BitStream is restored to updateBitsStart.\n */\n private tryGhostParser(\n bs: BitStream,\n entry: GhostParserEntry,\n updateBitsStart: number,\n totalBits: number,\n silent = false,\n connOverrides?: Partial<import(\"./ClassRegistry.js\").ConnectionContext>,\n trusted = false\n ): Record<string, unknown> | false {\n const savedPos = bs.savePos();\n if (!silent) {\n debugInitial(\" try %s: startBit=%d\", entry.name, updateBitsStart);\n }\n try {\n const parsedData = entry.unpackUpdate(bs, true, {\n compressionPoint: { x: 0, y: 0, z: 0 },\n ghostTracker: this.ghostTracker,\n ...connOverrides,\n });\n const bitsConsumed = bs.getCurPos() - updateBitsStart;\n const remaining = totalBits - bs.getCurPos();\n\n if (bs.isError() || (!trusted && bitsConsumed < 3)) {\n if (!silent) {\n debugInitial(\" reject %s: bits=%d isError=%s\", entry.name, bitsConsumed, bs.isError());\n }\n bs.restorePos(savedPos);\n return false;\n }\n\n // Validate alignment: if substantial data remains, the next\n // continuation flag must be 1 (more ghosts in the snapshot).\n if (remaining > 1000) {\n const peekPos = bs.getCurPos();\n const nextFlag = bs.readFlag();\n bs.setCurPos(peekPos);\n if (!nextFlag) {\n if (!silent) {\n debugInitial(\" reject %s: bits=%d misaligned (remaining=%d)\", entry.name, bitsConsumed, remaining);\n }\n bs.restorePos(savedPos);\n return false;\n }\n }\n\n return parsedData ?? {};\n } catch (e) {\n if (!silent) {\n debugInitial(\n \" reject %s: error at bit=%d: %s\",\n entry.name, bs.getCurPos(),\n e instanceof Error ? e.message : String(e)\n );\n }\n bs.restorePos(savedPos);\n return false;\n }\n }\n\n /**\n * Peek at the GameBase DataBlock prefix to identify a ghost's parser.\n * GameBase subclass ghost creates always start with:\n * flag(1b) + if flag: DataBlockId(11b)\n * The DataBlock type (e.g., \"PlayerData\") maps to the ghost parser\n * (e.g., \"Player\") by stripping the \"Data\" suffix.\n *\n * Returns { entry, dbFlag } where entry is the parser (if found) and\n * dbFlag indicates whether the first bit was 1 (DataBlock flag set).\n * In the initial block (mask=0xFFFFFFFF), dbFlag=false means the ghost\n * is definitely NOT a GameBase subclass.\n * The BitStream position is always restored after peeking.\n */\n private identifyGhostViaDataBlock(\n bs: BitStream,\n dataBlocks: Map<number, ParsedDataBlock> | undefined,\n ghostCatalog: Map<string, GhostParserEntry>\n ): { entry: GhostParserEntry | undefined; dbFlag: boolean } {\n if (!dataBlocks) return { entry: undefined, dbFlag: false };\n\n const savedPos = bs.savePos();\n let entry: GhostParserEntry | undefined;\n let dbFlag = false;\n\n try {\n dbFlag = bs.readFlag();\n if (dbFlag) {\n const dbId = bs.readInt(11);\n const db = dataBlocks.get(dbId);\n if (db) {\n const ghostName = db.className.replace(/Data$/, \"\");\n entry = ghostCatalog.get(ghostName);\n if (!entry) {\n debugInitial(\n \" identifyGhostViaDataBlock: dbId=%d className=%s ghostName=%s (no ghost parser)\",\n dbId, db.className, ghostName\n );\n }\n } else {\n debugInitial(\" identifyGhostViaDataBlock: dbId=%d (no DataBlock found)\", dbId);\n }\n } else {\n debugInitial(\" identifyGhostViaDataBlock: DataBlock flag=0\");\n }\n } catch {\n // Ignore errors during peek\n }\n\n bs.restorePos(savedPos);\n return { entry, dbFlag };\n }\n\n /**\n * Parse a raw 64-byte Move struct from a type 2 block.\n *\n * Layout (all little-endian):\n * S32 px, py, pz (12 bytes, offsets 0-11)\n * U32 pyaw, ppitch, proll (12 bytes, offsets 12-23)\n * F32 x, y, z (12 bytes, offsets 24-35)\n * F32 yaw, pitch, roll (12 bytes, offsets 36-47)\n * U32 id (4 bytes, offset 48)\n * U32 sendCount (4 bytes, offset 52)\n * bool freeLook (1 byte, offset 56)\n * bool trigger[6] (6 bytes, offsets 57-62)\n * padding (1 byte, offset 63)\n */\n private readRawMove(data: Uint8Array): Move {\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const px = dv.getInt32(0, true);\n const py = dv.getInt32(4, true);\n const pz = dv.getInt32(8, true);\n const pyaw = dv.getUint32(12, true);\n const ppitch = dv.getUint32(16, true);\n const proll = dv.getUint32(20, true);\n const x = dv.getFloat32(24, true);\n const y = dv.getFloat32(28, true);\n const z = dv.getFloat32(32, true);\n const yaw = dv.getFloat32(36, true);\n const pitch = dv.getFloat32(40, true);\n const roll = dv.getFloat32(44, true);\n const id = dv.getUint32(48, true);\n const sendCount = dv.getUint32(52, true);\n const freeLook = data[56] !== 0;\n const trigger: boolean[] = [];\n for (let i = 0; i < MaxTriggerKeys; i++) {\n trigger.push(data[57 + i] !== 0);\n }\n\n return {\n px, py, pz, pyaw, ppitch, proll,\n x, y, z, yaw, pitch, roll,\n id, sendCount, freeLook, trigger,\n };\n }\n\n /**\n * Parse an 8-byte info block (type 3).\n * Contains U32 + F32 (observed: always 1 + 120.0).\n */\n private readInfoBlock(data: Uint8Array): InfoBlock {\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\n return {\n value1: dv.getUint32(0, true),\n value2: dv.getFloat32(4, true),\n };\n }\n}\n"]}
1
+ {"version":3,"file":"DemoParser.js","sourceRoot":"","sources":["../src/DemoParser.ts"],"names":[],"mappings":"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","sourcesContent":["import { inflate } from \"fflate\";\nimport createDebug from \"debug\";\nimport { BitStream } from \"./BitStream.js\";\nimport { PacketParser } from \"./PacketParser.js\";\nimport { ClassRegistry } from \"./ClassRegistry.js\";\nimport type { GhostParserEntry } from \"./ClassRegistry.js\";\nimport { GhostTracker, registerGhostParsers } from \"./GhostManager.js\";\nimport { registerEventParsers } from \"./EventParsers.js\";\nimport { registerDataBlockParsers } from \"./DataBlockParsers.js\";\nimport {\n BlockTypePacket,\n BlockTypeSendPacket,\n BlockTypeMove,\n BlockTypeInfo,\n MaxTriggerKeys,\n NetEventClassBitSize,\n NetEventClassFirst,\n NetObjectClassBitSize,\n NetObjectClassFirst,\n GhostIdBitSize,\n DataBlockClassFirst,\n DataBlockClassNames,\n NetObjectClassNames,\n NetEventClassNames,\n SimDBEventObjectIdBits,\n SimDBEventClassIdBits,\n SimDBEventIndexBits,\n SimDBEventTotalBits,\n} from \"./types.js\";\nimport type {\n DemoHeader,\n DemoFile,\n DemoBlock,\n InitialBlockData,\n ConnectionProtocolState,\n DataBlockHeader,\n ParsedDataBlock,\n PathManagerEntry,\n ScoreEntry,\n TargetEntry,\n Move,\n InfoBlock,\n GhostUpdate,\n NetEventInfo,\n LoadResult,\n} from \"./types.js\";\n\nconst debug = createDebug(\"t2-demo-parser\");\nconst debugInitial = createDebug(\"t2-demo-parser:initial\");\nconst debugBlocks = createDebug(\"t2-demo-parser:blocks\");\n\nexport class DemoParser {\n private buffer: Uint8Array;\n private view: DataView;\n private offset: number;\n private registry: ClassRegistry;\n private ghostTracker: GhostTracker;\n private packetParser: PacketParser;\n // Stepping API state\n private _loaded = false;\n private _header?: DemoHeader;\n private _initialBlock?: InitialBlockData;\n private _decompressedData?: Uint8Array;\n private _decompressedView?: DataView;\n private _blockStreamOffset = 0;\n private _blockCount?: number;\n private _blockCursor = 0;\n\n constructor(buffer: Uint8Array) {\n this.buffer = buffer;\n this.view = new DataView(\n buffer.buffer,\n buffer.byteOffset,\n buffer.byteLength,\n );\n this.offset = 0;\n this.registry = new ClassRegistry();\n this.ghostTracker = new GhostTracker();\n\n // Register parser catalogs\n registerEventParsers(this.registry);\n registerGhostParsers(this.registry);\n registerDataBlockParsers(this.registry);\n\n // Bind DataBlock parsers deterministically using the known class name\n // mapping derived from binary analysis of the Tribes 2 executable.\n // ClassIds are assigned alphabetically (C strcmp) starting at\n // DataBlockClassFirst (128).\n const { bound: dbBound, missing: dbMissing } =\n this.registry.bindDeterministicDataBlocks(\n DataBlockClassNames,\n DataBlockClassFirst,\n );\n if (dbMissing.length > 0) {\n debug(\n \"DataBlock binding: %d/%d bound, missing parsers: %s\",\n dbBound,\n DataBlockClassNames.length,\n dbMissing.join(\", \"),\n );\n }\n\n // Bind ghost (NetObject) parsers deterministically using the known\n // class name mapping derived from binary analysis. The 53 NetObject\n // classes are sorted alphabetically (C strcmp) and assigned sequential\n // classIds starting at NetObjectClassFirst (0).\n const { bound: ghostBound, missing: ghostMissing } =\n this.registry.bindDeterministicGhosts(\n NetObjectClassNames,\n NetObjectClassFirst,\n );\n if (ghostMissing.length > 0) {\n debug(\n \"Ghost binding: %d/%d bound, missing parsers: %s\",\n ghostBound,\n NetObjectClassNames.length,\n ghostMissing.join(\", \"),\n );\n }\n\n // Bind event (NetEvent) parsers deterministically using the known\n // class name mapping derived from binary analysis. The 26 NetEvent\n // classes are sorted alphabetically (C strcmp) and assigned sequential\n // classIds starting at NetEventClassFirst (255).\n const { bound: eventBound, missing: eventMissing } =\n this.registry.bindDeterministicEvents(\n NetEventClassNames,\n NetEventClassFirst,\n );\n if (eventMissing.length > 0) {\n debug(\n \"Event binding: %d/%d bound, missing parsers: %s\",\n eventBound,\n NetEventClassNames.length,\n eventMissing.join(\", \"),\n );\n }\n\n this.packetParser = new PacketParser(this.registry, this.ghostTracker);\n }\n\n getRegistry(): ClassRegistry {\n return this.registry;\n }\n\n getGhostTracker(): GhostTracker {\n return this.ghostTracker;\n }\n\n getPacketParser(): PacketParser {\n return this.packetParser;\n }\n\n // --- Stepping API getters ---\n\n get loaded(): boolean {\n return this._loaded;\n }\n\n get header(): DemoHeader {\n if (!this._loaded) throw new Error(\"must call load() first\");\n return this._header!;\n }\n\n get initialBlock(): InitialBlockData {\n if (!this._loaded) throw new Error(\"must call load() first\");\n return this._initialBlock!;\n }\n\n get blockCount(): number {\n if (!this._loaded) throw new Error(\"must call load() first\");\n if (this._blockCount === undefined) {\n // Lazy scan: walk decompressed buffer counting U16 headers\n const data = this._decompressedData!;\n const view = this._decompressedView!;\n let count = 0;\n let off = 0;\n while (off + 2 <= data.length) {\n const typeSize = view.getUint16(off, true);\n const size = typeSize & 0xfff;\n off += 2 + size;\n if (off > data.length) break;\n count++;\n }\n this._blockCount = count;\n }\n return this._blockCount;\n }\n\n get blockCursor(): number {\n if (!this._loaded) throw new Error(\"must call load() first\");\n return this._blockCursor;\n }\n\n // --- Stepping API methods ---\n\n /**\n * Async load: parses header, initial block (DataBlocks, events,\n * ghosts, control object, mission name), and asynchronously decompresses\n * the block stream. No block indexing — blocks are read lazily via nextBlock().\n *\n * Idempotent — second call returns cached result.\n */\n async load(): Promise<LoadResult> {\n if (this._loaded) {\n return {\n header: this._header!,\n initialBlock: this._initialBlock!,\n };\n }\n\n // Phase 1: header + initial block\n const header = this.readHeader();\n debug(\n 'header: \"%s\" version=0x%s length=%dms (%smin) initialBlockSize=%d',\n header.identString,\n header.protocolVersion.toString(16),\n header.demoLengthMs,\n (header.demoLengthMs / 1000 / 60).toFixed(1),\n header.initialBlockSize,\n );\n\n const initialBlockData = this.buffer.subarray(\n this.offset,\n this.offset + header.initialBlockSize,\n );\n const initialBlock = this.readInitialBlock(initialBlockData);\n this.offset += header.initialBlockSize;\n\n // Phase 2: async decompress block stream\n const compressedData = this.buffer.subarray(this.offset);\n debug(\"compressed block stream: %d bytes\", compressedData.length);\n\n const decompressedData = await new Promise<Uint8Array>(\n (resolve, reject) => {\n inflate(compressedData, (err, data) => {\n if (err) reject(err);\n else resolve(data);\n });\n },\n );\n debug(\"decompressed block stream: %d bytes\", decompressedData.length);\n\n this._decompressedData = decompressedData;\n this._decompressedView = new DataView(\n decompressedData.buffer,\n decompressedData.byteOffset,\n decompressedData.byteLength,\n );\n\n // Phase 3: set up PacketParser with seeded ghost tracker\n this.setupPacketParser(initialBlock);\n\n // Cache results\n this._header = header;\n this._initialBlock = initialBlock;\n this._blockStreamOffset = 0;\n this._blockCursor = 0;\n this._loaded = true;\n\n return { header, initialBlock };\n }\n\n /**\n * Read and parse the next block from the decompressed buffer.\n * Returns the parsed block, or undefined when all blocks are exhausted.\n * Each block is transient — only one in memory at a time.\n * Throws if load() has not been called.\n */\n nextBlock(): DemoBlock | undefined {\n if (!this._loaded) throw new Error(\"must call load() first\");\n const data = this._decompressedData!;\n const view = this._decompressedView!;\n const off = this._blockStreamOffset;\n\n if (off + 2 > data.length) return undefined;\n\n const typeSize = view.getUint16(off, true);\n const type = typeSize >> 12;\n const size = typeSize & 0xfff;\n\n if (off + 2 + size > data.length) {\n debugBlocks(\n \"block %d: size %d would exceed decompressed data (offset=%d remaining=%d), stopping\",\n this._blockCursor,\n size,\n off + 2,\n data.length - off - 2,\n );\n return undefined;\n }\n\n const blockData = data.subarray(off + 2, off + 2 + size);\n this._blockStreamOffset = off + 2 + size;\n\n const block: DemoBlock = {\n index: this._blockCursor,\n type,\n size,\n data: blockData,\n };\n this._blockCursor++;\n\n if (type === BlockTypePacket) {\n try {\n block.parsed = this.packetParser.parsePacket(blockData);\n } catch {\n // Skip unparseable packets\n }\n } else if (type === BlockTypeSendPacket) {\n this.packetParser.onSendPacketTrigger();\n } else if (type === BlockTypeMove && size === 64) {\n try {\n block.parsed = this.readRawMove(blockData);\n } catch {\n // Skip unparseable moves\n }\n } else if (type === BlockTypeInfo && size === 8) {\n try {\n block.parsed = this.readInfoBlock(blockData);\n } catch {\n // Skip unparseable info blocks\n }\n }\n\n return block;\n }\n\n /**\n * Reset stepping state: resets stream offset and cursor to 0,\n * clears cached block count, and re-initializes the PacketParser\n * with a fresh ghost tracker seeded from the initial block.\n * Throws if load() has not been called.\n */\n reset(): void {\n if (!this._loaded) throw new Error(\"must call load() first\");\n\n this._blockStreamOffset = 0;\n this._blockCursor = 0;\n this._blockCount = undefined;\n\n // Fresh ghost tracker + packet parser\n this.setupPacketParser(this._initialBlock!);\n }\n\n /**\n * Fast-forward through N blocks, processing each but not returning them.\n * Returns the number of blocks actually processed (may be less than count\n * if the stream is exhausted).\n * Throws if load() has not been called.\n */\n processBlocks(count: number): number {\n if (!this._loaded) throw new Error(\"must call load() first\");\n let processed = 0;\n for (let i = 0; i < count; i++) {\n if (!this.nextBlock()) break;\n processed++;\n }\n return processed;\n }\n\n /**\n * Set up a fresh PacketParser seeded from the initial block's ghosts\n * and with the DataBlock data map for ghost parsers. Replaces\n * this.ghostTracker and this.packetParser.\n */\n private setupPacketParser(initialBlock: InitialBlockData): void {\n // Build DataBlock data map (objectId → parsed data)\n const dataBlockDataMap = new Map<number, Record<string, unknown>>();\n for (const [objectId, db] of initialBlock.dataBlocks) {\n dataBlockDataMap.set(objectId, db.data);\n }\n\n // Seed ghost tracker from initial block ghosts\n const gt = new GhostTracker();\n for (const ghost of initialBlock.initialGhosts) {\n if (ghost.type !== \"create\" || ghost.classId === undefined) continue;\n const parserEntry = this.registry.getGhostParser(ghost.classId);\n gt.createGhost(\n ghost.index,\n ghost.classId,\n parserEntry?.name ?? `unknown_${ghost.classId}`,\n );\n }\n\n const pp = new PacketParser(this.registry, gt, {\n dataBlockDataMap,\n connectionProtocolState: initialBlock.connectionState,\n nextRecvEventSeq: initialBlock.nextRecvEventSeq,\n compressionPoint: initialBlock.initialCompressionPoint,\n });\n\n this.ghostTracker = gt;\n this.packetParser = pp;\n }\n\n /**\n * Full parse: async load + drain all blocks.\n */\n async parseFullDemo(): Promise<DemoFile> {\n const { header, initialBlock } = await this.load();\n const blocks: DemoBlock[] = [];\n let block: DemoBlock | undefined;\n while ((block = this.nextBlock())) blocks.push(block);\n return { header, initialBlock, blocks };\n }\n\n private readHeader(): DemoHeader {\n // Read the identification string: U8 length + string\n const strLen = this.view.getUint8(this.offset);\n this.offset += 1;\n const identString = new TextDecoder(\"ascii\").decode(\n this.buffer.subarray(this.offset, this.offset + strLen),\n );\n this.offset += strLen;\n\n // U32 protocol version\n const protocolVersion = this.view.getUint32(this.offset, true);\n this.offset += 4;\n\n // U32 demo length in ms\n const demoLengthMs = this.view.getUint32(this.offset, true);\n this.offset += 4;\n\n // U32 initial block size\n const initialBlockSize = this.view.getUint32(this.offset, true);\n this.offset += 4;\n\n return { identString, protocolVersion, demoLengthMs, initialBlockSize };\n }\n\n /** Parse the initial block: DataBlocks, scores, targets, connection state,\n * events, ghosts, control object, and mission name. */\n private readInitialBlock(data: Uint8Array): InitialBlockData {\n const bs = new BitStream(data);\n\n // --- A. Tagged string table (1024 entries) ---\n const taggedStrings = new Map<number, string>();\n for (let i = 0; i < 1024; i++) {\n if (bs.readFlag()) {\n taggedStrings.set(i, bs.readString());\n }\n }\n debugInitial(\n \"after tagged strings bit=%d count=%d\",\n bs.getCurPos(),\n taggedStrings.size,\n );\n\n // --- B.1 U32 datablockCount ---\n const expectedDataBlockCount = bs.readU32();\n\n // --- B.2 DataBlock loop ---\n const dataBlockHeaders: DataBlockHeader[] = [];\n const dataBlocks = new Map<number, ParsedDataBlock>();\n let dataBlockCount = 0;\n\n while (bs.readFlag()) {\n dataBlockCount++;\n const modified = bs.readFlag();\n if (!modified) {\n continue;\n }\n\n const objectId = bs.readInt(SimDBEventObjectIdBits);\n const classId = bs.readInt(SimDBEventClassIdBits) + DataBlockClassFirst;\n const index = bs.readInt(SimDBEventIndexBits);\n const total = bs.readInt(SimDBEventTotalBits);\n const dataBitsStart = bs.getCurPos();\n\n dataBlockHeaders.push({ objectId, classId, index, total, dataBitsStart });\n\n const parserEntry = this.registry.getDataBlockParser(classId);\n if (parserEntry) {\n const parsedData = parserEntry.unpackData(bs);\n dataBlocks.set(objectId, {\n classId,\n className: parserEntry.name,\n objectId,\n data: parsedData,\n });\n } else {\n const className =\n classId >= DataBlockClassFirst &&\n classId < DataBlockClassFirst + DataBlockClassNames.length\n ? DataBlockClassNames[classId - DataBlockClassFirst]\n : `unknown(${classId})`;\n throw new Error(\n `No parser for DataBlock classId ${classId} (${className}) at bit ${dataBitsStart}`,\n );\n }\n }\n\n debug(\n \"all %d/%d DataBlocks parsed (%d payloads), bit position after DataBlocks: %d\",\n dataBlockCount,\n expectedDataBlockCount,\n dataBlocks.size,\n bs.getCurPos(),\n );\n\n // --- B.3 $firstPerson (U8 boolean from GameConnection::writeDemoStartBlock) ---\n const firstPerson = bs.readU8() !== 0;\n // --- B.4 6× U32 connection fields ---\n // @0x8384, @0x8388, @0x83f8, @0x83fc, @0x8400, @0x8434\n const connectionFields: number[] = [];\n for (let i = 0; i < 6; i++) connectionFields.push(bs.readU32());\n\n // --- B.5 16× U32 state array ---\n // @0x83b8 + i*4, i=0..15\n const stateArray: number[] = [];\n for (let i = 0; i < 16; i++) stateArray.push(bs.readU32());\n\n // --- B.6 U32 score entry count ---\n const scoreCount = bs.readU32();\n\n // --- B.7 Score entries × count (FUN_00601800) ---\n const scoreEntries: ScoreEntry[] = [];\n for (let i = 0; i < scoreCount; i++) {\n scoreEntries.push(this.readScoreEntry(bs));\n }\n debugInitial(\n \"after score entries bit=%d scoreCount=%d\",\n bs.getCurPos(),\n scoreCount,\n );\n\n // B.8: FUN_005fb130 — clears internal state, no bitstream I/O\n\n // --- B.8 DemoValues ---\n const demoValues = this.readDemoValues(bs);\n debugInitial(\n \"after demo values bit=%d demoValues=%d\",\n bs.getCurPos(),\n demoValues.length,\n );\n\n // --- B.9 Complex TargetManager (FUN_00670660) ---\n const { sensorGroupColors, targets: targetEntries } =\n this.readComplexTargetManager(bs);\n debugInitial(\n \"after complex target manager bit=%d targets=%d sensorGroupColors=%d\",\n bs.getCurPos(),\n targetEntries.length,\n sensorGroupColors.length,\n );\n\n // --- B.10 Parent: NetConnection::readDemoStartBlock (FUN_00588260) ---\n\n // B.10a ConnectionProtocol (FUN_0043d820)\n const connectionState = this.readConnectionProtocol(bs);\n debugInitial(\n \"after connection protocol bit=%d lastRecv=%d highestAck=%d lastSend=%d connected=%s\",\n bs.getCurPos(),\n connectionState.lastSeqRecvd,\n connectionState.highestAckedSeq,\n connectionState.lastSendSeq,\n connectionState.connectionEstablished,\n );\n\n // B.10b RTT, B.10c packet loss\n const roundTripTime = bs.readF32();\n const packetLoss = bs.readF32();\n debugInitial(\n \"after RTT/loss bit=%d rtt=%d loss=%d\",\n bs.getCurPos(),\n roundTripTime,\n packetLoss,\n );\n\n // B.10d PathManager (FUN_00591ce0)\n const pathManager = this.readPathManager(bs);\n debugInitial(\n \"after path manager bit=%d entries=%d\",\n bs.getCurPos(),\n pathManager.length,\n );\n\n // B.10e Notify count only (FUN_00588260).\n // The reader allocates notify nodes in memory but does not consume\n // per-notify records from the bitstream in this phase.\n const notifyCount = bs.readU32();\n debugInitial(\n \"after notify count bit=%d notifyCount=%d\",\n bs.getCurPos(),\n notifyCount,\n );\n\n // --- B.10f through B.15: events, ghosts, control object, mission ---\n // Uses a temporary ghost tracker for initial-block ghost parsing only.\n const totalBits = bs.getBuffer().length * 8;\n const ibGhostTracker = new GhostTracker();\n const savedGhostTracker = this.ghostTracker;\n this.ghostTracker = ibGhostTracker;\n\n let initialEvents: NetEventInfo[] = [];\n let nextRecvEventSeq = 0;\n let ghostingSequence = 0;\n let initialGhosts: GhostUpdate[] = [];\n let controlObjectGhostIndex = -1;\n let controlObjectData: Record<string, unknown> | undefined;\n let initialCompressionPoint:\n { x: number; y: number; z: number } | undefined;\n let missionName = \"\";\n let missionCRC = 0;\n let phase2Error: string | undefined;\n try {\n debugInitial(\n \"phase2 start bit=%d remaining=%d\",\n bs.getCurPos(),\n totalBits - bs.getCurPos(),\n );\n\n // B.10f Events\n ({ nextRecvEventSeq, events: initialEvents } =\n this.readEventStartBlock(bs));\n debugInitial(\n \"after initial events bit=%d count=%d\",\n bs.getCurPos(),\n initialEvents.length,\n );\n\n // B.10g Ghosts\n const ghostResult = this.readGhostStartBlock(bs, dataBlocks);\n ghostingSequence = ghostResult.ghostingSequence;\n initialGhosts = ghostResult.ghosts;\n debugInitial(\n \"after initial ghosts bit=%d count=%d seq=%d\",\n bs.getCurPos(),\n initialGhosts.length,\n ghostingSequence,\n );\n\n // B.11 controlObjectGhostIndex\n controlObjectGhostIndex = bs.readS32();\n debugInitial(\n \"after control ghost index bit=%d control=%d\",\n bs.getCurPos(),\n controlObjectGhostIndex,\n );\n\n // B.12 If != -1: controlObject readPacketData\n if (controlObjectGhostIndex !== -1) {\n const ghost = ibGhostTracker.getGhost(controlObjectGhostIndex);\n if (ghost) {\n const parser = this.registry.getGhostParser(ghost.classId);\n if (parser?.readPacketData) {\n // getGhostParser enables the nested vehicle readPacketData\n // when the recorder was piloting at recording start — without\n // it those bytes go unread and every later read in the\n // initial block (mission name, CRC) is misaligned.\n const conn = {\n compressionPoint: { x: 0, y: 0, z: 0 },\n ghostTracker: ibGhostTracker,\n getGhostParser: (classId: number) =>\n this.registry.getGhostParser(classId),\n };\n controlObjectData = parser.readPacketData(bs, conn);\n // The control object's readPacketData establishes the\n // connection's compression point (its position) — carry it\n // into the packet parser seed.\n initialCompressionPoint = conn.compressionPoint;\n debugInitial(\n \"after control readPacketData bit=%d parser=%s\",\n bs.getCurPos(),\n parser.name,\n );\n }\n }\n }\n\n // B.13 $MissionName\n missionName = bs.readString();\n // B.14 mMissionCRC\n missionCRC = bs.readU32();\n // Byte-align (validate) before SimpleTargetManagers\n bs.setCurPos(((bs.getCurPos() + 7) >> 3) << 3);\n // B.15 Simple TargetManager ×2\n this.readSimpleTargetManager(bs);\n this.readSimpleTargetManager(bs);\n debugInitial(\n 'after sequential tail bit=%d mission=\"%s\" CRC=0x%s',\n bs.getCurPos(),\n missionName,\n missionCRC.toString(16),\n );\n } catch (e) {\n phase2Error = e instanceof Error ? e.message : String(e);\n } finally {\n this.ghostTracker = savedGhostTracker;\n }\n\n const remaining = totalBits - bs.getCurPos();\n const missionPrintableRatio =\n missionName.length > 0\n ? missionName.split(\"\").filter((c) => {\n const code = c.charCodeAt(0);\n return code >= 0x20 && code <= 0x7e;\n }).length / missionName.length\n : 1;\n const phase2Valid =\n missionName.length > 0 &&\n missionPrintableRatio >= 0.8 &&\n phase2Error === undefined;\n\n debug(\n 'initial block: events=%d ghosts=%d ghostingSeq=%d controlObj=%d mission=\"%s\" CRC=0x%s valid=%s%s',\n initialEvents.length,\n initialGhosts.length,\n ghostingSequence,\n controlObjectGhostIndex,\n missionName,\n missionCRC.toString(16),\n phase2Valid,\n phase2Error ? ` error=${phase2Error}` : \"\",\n );\n\n return {\n taggedStrings,\n dataBlockHeaders,\n dataBlockCount,\n dataBlocks,\n firstPerson,\n connectionFields,\n stateArray,\n scoreEntries,\n demoValues,\n sensorGroupColors,\n targetEntries,\n connectionState,\n roundTripTime,\n packetLoss,\n pathManager,\n notifyCount,\n nextRecvEventSeq,\n ghostingSequence,\n initialGhosts,\n initialEvents,\n controlObjectGhostIndex,\n controlObjectData,\n initialCompressionPoint,\n missionName,\n missionCRC,\n phase2TrailingBits: remaining,\n phase2Valid,\n phase2Error,\n };\n }\n\n /**\n * Read a score entry from FUN_00601800.\n * Format: 3 conditional U16s + 3 U6s + 1 flag + 6 flags.\n */\n private readScoreEntry(bs: BitStream): ScoreEntry {\n const clientId = bs.readFlag() ? bs.readInt(16) : 0;\n const teamId = bs.readFlag() ? bs.readInt(16) : 0;\n const score = bs.readFlag() ? bs.readInt(16) : 0;\n const field0 = bs.readInt(6);\n const field1 = bs.readInt(6);\n const field2 = bs.readInt(6);\n // FUN_006014e0: post-processing, no stream reads\n const isBot = bs.readFlag();\n const triggerFlags: boolean[] = [];\n for (let i = 0; i < 6; i++) triggerFlags.push(bs.readFlag());\n return {\n clientId,\n teamId,\n score,\n field0,\n field1,\n field2,\n isBot,\n triggerFlags,\n };\n }\n\n /**\n * Read DemoValues from FUN_005fb5c0 lines 388966-388980.\n * Format: while(readFlag()) { readString(value) }\n * Variable names are derived from index ($DemoValue_0, $DemoValue_1, etc.).\n */\n private readDemoValues(bs: BitStream): string[] {\n const values: string[] = [];\n while (bs.readFlag()) {\n values.push(bs.readString());\n }\n return values;\n }\n\n /**\n * Read Complex TargetManager from FUN_00670660.\n *\n * Phase 1: 4×U8 initial data\n * Phase 2: 32×32 grid — each cell: readFlag + if true: 4×U8\n * Phase 3: 512 target entries with conditional fields\n */\n private readComplexTargetManager(bs: BitStream): {\n sensorGroupColors: import(\"./types.js\").SensorGroupColor[];\n targets: TargetEntry[];\n } {\n // Phase 1: FUN_0043efe0 — read 4 bytes (4×U8)\n bs.readU8();\n bs.readU8();\n bs.readU8();\n bs.readU8();\n\n // Phase 2: 32×32 sensor group color grid (IFF colors).\n // sensorGroupColors[group][targetGroup] = RGBA determines how targetGroup\n // appears to group (e.g., red for enemy, green for friendly).\n const sensorGroupColors: import(\"./types.js\").SensorGroupColor[] = [];\n for (let group = 0; group < 32; group++) {\n for (let targetGroup = 0; targetGroup < 32; targetGroup++) {\n if (bs.readFlag()) {\n sensorGroupColors.push({\n group,\n targetGroup,\n r: bs.readU8(),\n g: bs.readU8(),\n b: bs.readU8(),\n a: bs.readU8(),\n });\n }\n }\n }\n\n // Phase 3: 512 target entries\n const targets: TargetEntry[] = [];\n for (let i = 0; i < 512; i++) {\n if (!bs.readFlag()) continue; // Target not active\n\n const entry: TargetEntry = {\n targetId: i,\n sensorGroup: 0,\n targetData: 0,\n damageLevel: 0,\n };\n\n // Conditional sensor data\n if (bs.readFlag()) {\n entry.sensorData = bs.readU32(); // F32 sensorData\n }\n // Conditional voice map data\n if (bs.readFlag()) {\n entry.voiceMapData = bs.readU32(); // F32 voiceMapData\n }\n // 5 conditional strings: name, skin, skinPref, voice, typeDescription\n if (bs.readFlag()) entry.name = bs.readString();\n if (bs.readFlag()) entry.skin = bs.readString();\n if (bs.readFlag()) entry.skinPref = bs.readString();\n if (bs.readFlag()) entry.voice = bs.readString();\n if (bs.readFlag()) entry.typeDescription = bs.readString();\n\n // Always-read fields\n entry.sensorGroup = bs.readInt(5); // team/type\n entry.targetData = bs.readInt(9); // target data\n\n // Targets >= 32 have additional DataBlock reference\n if (i >= 32) {\n if (bs.readFlag()) {\n entry.dataBlockRef = bs.readInt(11); // DataBlock reference (FUN_00436d10: readClassId)\n }\n // Virtual call notification — no bitstream I/O\n }\n\n // Damage level: readFloat(7) — always read for all active targets\n entry.damageLevel = bs.readFloat(7);\n\n targets.push(entry);\n }\n\n return { sensorGroupColors, targets };\n }\n\n /**\n * Read PathManager from FUN_00591ce0.\n * Decompiled format:\n * - U32 entryCount\n * - repeat entryCount:\n * - U32 entryId\n * - U32 recordCount\n * - repeat recordCount:\n * - U32 field0\n * - U32 field1\n * - U32 field2\n * - U32 auxField\n */\n private readPathManager(bs: BitStream): PathManagerEntry[] {\n const entries: PathManagerEntry[] = [];\n const entryCount = bs.readU32();\n for (let i = 0; i < entryCount; i++) {\n const entryId = bs.readU32();\n const recordCount = bs.readU32();\n const records: {\n field0: number;\n field1: number;\n field2: number;\n auxField: number;\n }[] = [];\n for (let j = 0; j < recordCount; j++) {\n records.push({\n field0: bs.readU32(),\n field1: bs.readU32(),\n field2: bs.readU32(),\n auxField: bs.readU32(),\n });\n }\n entries.push({ entryId, records });\n }\n return entries;\n }\n\n /**\n * Read Simple TargetManager from FUN_006021b0.\n * Format: U8 flag + 4×U32 = 136 bits total.\n */\n private readSimpleTargetManager(bs: BitStream): void {\n bs.readU8(); // _read(1) = 8 bits\n bs.readU32(); // 4× _read(4)\n bs.readU32();\n bs.readU32();\n bs.readU32();\n }\n\n private readConnectionProtocol(bs: BitStream): ConnectionProtocolState {\n const lastSeqRecvdAtSend: number[] = [];\n for (let i = 0; i < 32; i++) {\n lastSeqRecvdAtSend.push(bs.readU32());\n }\n const lastSeqRecvd = bs.readU32();\n const highestAckedSeq = bs.readU32();\n const lastSendSeq = bs.readU32();\n const ackMask = bs.readU32();\n const connectSequence = bs.readU32();\n const lastRecvAckAck = bs.readU32();\n const connectionEstablished = bs.readBool();\n\n return {\n lastSeqRecvdAtSend,\n lastSeqRecvd,\n highestAckedSeq,\n lastSendSeq,\n ackMask,\n connectSequence,\n lastRecvAckAck,\n connectionEstablished,\n };\n }\n\n private readEventStartBlock(bs: BitStream): {\n nextRecvEventSeq: number;\n events: NetEventInfo[];\n } {\n const nextRecvEventSeq = bs.readU32();\n const events: NetEventInfo[] = [];\n debugInitial(\n \"event block: nextRecvEventSeq=%d bit=%d\",\n nextRecvEventSeq,\n bs.getCurPos(),\n );\n while (bs.readFlag()) {\n const classId = bs.readInt(NetEventClassBitSize) + NetEventClassFirst;\n const dataBitsStart = bs.getCurPos();\n\n // Try to parse the event payload using the registry\n const parserEntry = this.registry.getEventParser(classId);\n let parsedData: Record<string, unknown> | undefined;\n\n if (parserEntry) {\n try {\n const conn = {\n compressionPoint: { x: 0, y: 0, z: 0 },\n ghostTracker: this.ghostTracker,\n getDataBlockParser: (cid: number) =>\n this.registry.getDataBlockParser(cid),\n };\n parsedData = parserEntry.unpack(bs, conn);\n } catch {\n // Can't parse — stop here\n events.push({\n classId,\n guaranteed: true,\n dataBitsStart,\n dataBitsEnd: dataBitsStart,\n failed: true,\n });\n break;\n }\n } else {\n // No parser — can't advance past this event\n events.push({\n classId,\n guaranteed: true,\n dataBitsStart,\n dataBitsEnd: dataBitsStart,\n failed: true,\n });\n break;\n }\n\n events.push({\n classId,\n guaranteed: true,\n dataBitsStart,\n dataBitsEnd: bs.getCurPos(),\n parsedData,\n });\n debugInitial(\n \" event classId=%d bits=%d\",\n classId,\n bs.getCurPos() - dataBitsStart,\n );\n }\n return { nextRecvEventSeq, events };\n }\n\n private readGhostStartBlock(\n bs: BitStream,\n dataBlocks: Map<number, ParsedDataBlock>,\n ): { ghostingSequence: number; ghosts: GhostUpdate[] } {\n const ghostingSequence = bs.readU32();\n const ghosts: GhostUpdate[] = [];\n debugInitial(\n \"ghost block: seq=%d bit=%d\",\n ghostingSequence,\n bs.getCurPos(),\n );\n const ghostCatalog = this.registry.getGhostCatalog();\n const totalBits = bs.getBuffer().length * 8;\n\n // Build DataBlock data lookup for ghost parsers that need it\n // (e.g., WheeledVehicle needs shape name to determine wheel count).\n const dataBlockDataMap = new Map<number, Record<string, unknown>>();\n for (const [objectId, db] of dataBlocks) {\n dataBlockDataMap.set(objectId, db.data);\n }\n\n while (bs.readFlag()) {\n if (bs.isError()) break;\n\n const index = bs.readInt(GhostIdBitSize);\n const classId = bs.readInt(NetObjectClassBitSize) + NetObjectClassFirst;\n const updateBitsStart = bs.getCurPos();\n\n // Build ordered list of parser candidates.\n // Registry binding (from deterministic classId) is preferred over\n // DataBlock-based identification because the classId is authoritative\n // while the DataBlock type may be a base class (e.g., StaticShapeData\n // used by a BeaconObject, which extends StaticShape with extra fields).\n const candidates: { entry: GhostParserEntry; method: string }[] = [];\n const seen = new Set<GhostParserEntry>();\n\n // Peek at DataBlock flag to identify ghost via DataBlock type\n const { entry: dbEntry } = this.identifyGhostViaDataBlock(\n bs,\n dataBlocks,\n ghostCatalog,\n );\n\n // Candidate 1: registry binding (deterministic classId)\n const regEntry = this.registry.getGhostParser(classId);\n if (regEntry) {\n candidates.push({ entry: regEntry, method: \"registry\" });\n seen.add(regEntry);\n }\n\n // Candidate 2: DataBlock-based identification (fallback)\n if (dbEntry && !seen.has(dbEntry)) {\n candidates.push({ entry: dbEntry, method: \"datablock\" });\n seen.add(dbEntry);\n }\n\n // Try each candidate with alignment validation\n const connOverrides = {\n getDataBlockData: (objectId: number) => dataBlockDataMap.get(objectId),\n getDataBlockParser: (cid: number) =>\n this.registry.getDataBlockParser(cid),\n };\n let parsed = false;\n for (const { entry, method } of candidates) {\n const isTrusted = method === \"registry\";\n const result = this.tryGhostParser(\n bs,\n entry,\n updateBitsStart,\n totalBits,\n false,\n connOverrides,\n isTrusted,\n );\n if (result !== false) {\n this.ghostTracker.createGhost(index, classId, entry.name);\n debugInitial(\n \" ghost idx=%d classId=%d parser=%s bits=%d via=%s\",\n index,\n classId,\n entry.name,\n bs.getCurPos() - updateBitsStart,\n method,\n );\n ghosts.push({\n index,\n type: \"create\",\n classId,\n updateBitsStart,\n updateBitsEnd: bs.getCurPos(),\n parsedData: result,\n });\n parsed = true;\n break;\n }\n }\n\n if (parsed) continue;\n\n // No candidate worked — stop parsing ghosts\n debugInitial(\n \" ghost idx=%d classId=%d NO PARSER (stopping at bit=%d, remaining=%d)\",\n index,\n classId,\n updateBitsStart,\n totalBits - updateBitsStart,\n );\n break;\n }\n\n debugInitial(\n \"ghost loop ended at bit=%d remaining=%d count=%d\",\n bs.getCurPos(),\n totalBits - bs.getCurPos(),\n ghosts.length,\n );\n return { ghostingSequence, ghosts };\n }\n\n /**\n * Try parsing a ghost with a given parser and validate alignment.\n * Returns true if parsing succeeded and alignment is valid.\n * On success, the BitStream is positioned after the parsed ghost data.\n * On failure, the BitStream is restored to updateBitsStart.\n */\n private tryGhostParser(\n bs: BitStream,\n entry: GhostParserEntry,\n updateBitsStart: number,\n totalBits: number,\n silent = false,\n connOverrides?: Partial<import(\"./ClassRegistry.js\").ConnectionContext>,\n trusted = false,\n ): Record<string, unknown> | false {\n const savedPos = bs.savePos();\n if (!silent) {\n debugInitial(\" try %s: startBit=%d\", entry.name, updateBitsStart);\n }\n try {\n const parsedData = entry.unpackUpdate(bs, true, {\n compressionPoint: { x: 0, y: 0, z: 0 },\n ghostTracker: this.ghostTracker,\n ...connOverrides,\n });\n const bitsConsumed = bs.getCurPos() - updateBitsStart;\n const remaining = totalBits - bs.getCurPos();\n\n if (bs.isError() || (!trusted && bitsConsumed < 3)) {\n if (!silent) {\n debugInitial(\n \" reject %s: bits=%d isError=%s\",\n entry.name,\n bitsConsumed,\n bs.isError(),\n );\n }\n bs.restorePos(savedPos);\n return false;\n }\n\n // Validate alignment: if substantial data remains, the next\n // continuation flag must be 1 (more ghosts in the snapshot).\n if (remaining > 1000) {\n const peekPos = bs.getCurPos();\n const nextFlag = bs.readFlag();\n bs.setCurPos(peekPos);\n if (!nextFlag) {\n if (!silent) {\n debugInitial(\n \" reject %s: bits=%d misaligned (remaining=%d)\",\n entry.name,\n bitsConsumed,\n remaining,\n );\n }\n bs.restorePos(savedPos);\n return false;\n }\n }\n\n return parsedData ?? {};\n } catch (e) {\n if (!silent) {\n debugInitial(\n \" reject %s: error at bit=%d: %s\",\n entry.name,\n bs.getCurPos(),\n e instanceof Error ? e.message : String(e),\n );\n }\n bs.restorePos(savedPos);\n return false;\n }\n }\n\n /**\n * Peek at the GameBase DataBlock prefix to identify a ghost's parser.\n * GameBase subclass ghost creates always start with:\n * flag(1b) + if flag: DataBlockId(11b)\n * The DataBlock type (e.g., \"PlayerData\") maps to the ghost parser\n * (e.g., \"Player\") by stripping the \"Data\" suffix.\n *\n * Returns { entry, dbFlag } where entry is the parser (if found) and\n * dbFlag indicates whether the first bit was 1 (DataBlock flag set).\n * In the initial block (mask=0xFFFFFFFF), dbFlag=false means the ghost\n * is definitely NOT a GameBase subclass.\n * The BitStream position is always restored after peeking.\n */\n private identifyGhostViaDataBlock(\n bs: BitStream,\n dataBlocks: Map<number, ParsedDataBlock> | undefined,\n ghostCatalog: Map<string, GhostParserEntry>,\n ): { entry: GhostParserEntry | undefined; dbFlag: boolean } {\n if (!dataBlocks) return { entry: undefined, dbFlag: false };\n\n const savedPos = bs.savePos();\n let entry: GhostParserEntry | undefined;\n let dbFlag = false;\n\n try {\n dbFlag = bs.readFlag();\n if (dbFlag) {\n const dbId = bs.readInt(11);\n const db = dataBlocks.get(dbId);\n if (db) {\n const ghostName = db.className.replace(/Data$/, \"\");\n entry = ghostCatalog.get(ghostName);\n if (!entry) {\n debugInitial(\n \" identifyGhostViaDataBlock: dbId=%d className=%s ghostName=%s (no ghost parser)\",\n dbId,\n db.className,\n ghostName,\n );\n }\n } else {\n debugInitial(\n \" identifyGhostViaDataBlock: dbId=%d (no DataBlock found)\",\n dbId,\n );\n }\n } else {\n debugInitial(\" identifyGhostViaDataBlock: DataBlock flag=0\");\n }\n } catch {\n // Ignore errors during peek\n }\n\n bs.restorePos(savedPos);\n return { entry, dbFlag };\n }\n\n /**\n * Parse a raw 64-byte Move struct from a type 2 block.\n *\n * Layout (all little-endian):\n * S32 px, py, pz (12 bytes, offsets 0-11)\n * U32 pyaw, ppitch, proll (12 bytes, offsets 12-23)\n * F32 x, y, z (12 bytes, offsets 24-35)\n * F32 yaw, pitch, roll (12 bytes, offsets 36-47)\n * U32 id (4 bytes, offset 48)\n * U32 sendCount (4 bytes, offset 52)\n * bool freeLook (1 byte, offset 56)\n * bool trigger[6] (6 bytes, offsets 57-62)\n * padding (1 byte, offset 63)\n */\n private readRawMove(data: Uint8Array): Move {\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const px = dv.getInt32(0, true);\n const py = dv.getInt32(4, true);\n const pz = dv.getInt32(8, true);\n const pyaw = dv.getUint32(12, true);\n const ppitch = dv.getUint32(16, true);\n const proll = dv.getUint32(20, true);\n const x = dv.getFloat32(24, true);\n const y = dv.getFloat32(28, true);\n const z = dv.getFloat32(32, true);\n const yaw = dv.getFloat32(36, true);\n const pitch = dv.getFloat32(40, true);\n const roll = dv.getFloat32(44, true);\n const id = dv.getUint32(48, true);\n const sendCount = dv.getUint32(52, true);\n const freeLook = data[56] !== 0;\n const trigger: boolean[] = [];\n for (let i = 0; i < MaxTriggerKeys; i++) {\n trigger.push(data[57 + i] !== 0);\n }\n\n return {\n px,\n py,\n pz,\n pyaw,\n ppitch,\n proll,\n x,\n y,\n z,\n yaw,\n pitch,\n roll,\n id,\n sendCount,\n freeLook,\n trigger,\n };\n }\n\n /**\n * Parse an 8-byte info block (type 3).\n * Contains U32 + F32 (observed: always 1 + 120.0).\n */\n private readInfoBlock(data: Uint8Array): InfoBlock {\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\n return {\n value1: dv.getUint32(0, true),\n value2: dv.getFloat32(4, true),\n };\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"GhostManager.d.ts","sourceRoot":"","sources":["../src/GhostManager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EAEb,UAAU,EACV,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAiE5B,qBAAa,YAAa,YAAW,qBAAqB;IACxD,OAAO,CAAC,MAAM,CAAiC;IAE/C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI/C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIhC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU;IAM1E,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIhC,YAAY,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;IAIvC,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,IAAI;CAGd;AA0qED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAwRlE"}
1
+ {"version":3,"file":"GhostManager.d.ts","sourceRoot":"","sources":["../src/GhostManager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EAEb,UAAU,EACV,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAiE5B,qBAAa,YAAa,YAAW,qBAAqB;IACxD,OAAO,CAAC,MAAM,CAAiC;IAE/C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI/C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIhC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU;IAM1E,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIhC,YAAY,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;IAIvC,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,IAAI;CAGd;AA4uED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAwRlE"}