t2-demo-parser 2.2.0 → 3.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 (95) hide show
  1. package/README.md +170 -7
  2. package/dist/BitStream.d.ts +14 -3
  3. package/dist/BitStream.d.ts.map +1 -1
  4. package/dist/BitStream.js +28 -6
  5. package/dist/BitStream.js.map +1 -1
  6. package/dist/BitWriter.d.ts +29 -0
  7. package/dist/BitWriter.d.ts.map +1 -0
  8. package/dist/BitWriter.js +76 -0
  9. package/dist/BitWriter.js.map +1 -0
  10. package/dist/ClassRegistry.d.ts +23 -28
  11. package/dist/ClassRegistry.d.ts.map +1 -1
  12. package/dist/ClassRegistry.js +75 -84
  13. package/dist/ClassRegistry.js.map +1 -1
  14. package/dist/DataBlockParsers.d.ts.map +1 -1
  15. package/dist/DataBlockParsers.js +51 -76
  16. package/dist/DataBlockParsers.js.map +1 -1
  17. package/dist/DemoParser.d.ts +23 -22
  18. package/dist/DemoParser.d.ts.map +1 -1
  19. package/dist/DemoParser.js +218 -266
  20. package/dist/DemoParser.js.map +1 -1
  21. package/dist/EventParsers.d.ts.map +1 -1
  22. package/dist/EventParsers.js +87 -58
  23. package/dist/EventParsers.js.map +1 -1
  24. package/dist/GhostManager.d.ts +7 -1
  25. package/dist/GhostManager.d.ts.map +1 -1
  26. package/dist/GhostManager.js +231 -146
  27. package/dist/GhostManager.js.map +1 -1
  28. package/dist/HuffmanProcessor.d.ts +15 -0
  29. package/dist/HuffmanProcessor.d.ts.map +1 -1
  30. package/dist/HuffmanProcessor.js +45 -0
  31. package/dist/HuffmanProcessor.js.map +1 -1
  32. package/dist/LiveParser.d.ts +20 -1
  33. package/dist/LiveParser.d.ts.map +1 -1
  34. package/dist/LiveParser.js +31 -12
  35. package/dist/LiveParser.js.map +1 -1
  36. package/dist/PacketParser.d.ts +22 -2
  37. package/dist/PacketParser.d.ts.map +1 -1
  38. package/dist/PacketParser.js +111 -48
  39. package/dist/PacketParser.js.map +1 -1
  40. package/dist/Timeline.d.ts +5 -2
  41. package/dist/Timeline.d.ts.map +1 -1
  42. package/dist/Timeline.js +25 -12
  43. package/dist/Timeline.js.map +1 -1
  44. package/dist/cli.js +3 -0
  45. package/dist/cli.js.map +1 -1
  46. package/dist/dataBlockDataTypes.d.ts +111 -112
  47. package/dist/dataBlockDataTypes.d.ts.map +1 -1
  48. package/dist/dataBlockDataTypes.js.map +1 -1
  49. package/dist/defaultRegistry.d.ts +9 -0
  50. package/dist/defaultRegistry.d.ts.map +1 -0
  51. package/dist/defaultRegistry.js +43 -0
  52. package/dist/defaultRegistry.js.map +1 -0
  53. package/dist/eventDataTypes.d.ts +74 -72
  54. package/dist/eventDataTypes.d.ts.map +1 -1
  55. package/dist/eventDataTypes.js.map +1 -1
  56. package/dist/ghostDataTypes.d.ts +125 -131
  57. package/dist/ghostDataTypes.d.ts.map +1 -1
  58. package/dist/ghostDataTypes.js.map +1 -1
  59. package/dist/index.d.ts +6 -4
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +4 -2
  62. package/dist/index.js.map +1 -1
  63. package/dist/types.d.ts +51 -2
  64. package/dist/types.d.ts.map +1 -1
  65. package/dist/types.js +6 -0
  66. package/dist/types.js.map +1 -1
  67. package/package.json +4 -1
  68. package/dist/BitStream.test.d.ts +0 -2
  69. package/dist/BitStream.test.d.ts.map +0 -1
  70. package/dist/BitStream.test.js +0 -419
  71. package/dist/BitStream.test.js.map +0 -1
  72. package/dist/ClassRegistry.test.d.ts +0 -2
  73. package/dist/ClassRegistry.test.d.ts.map +0 -1
  74. package/dist/ClassRegistry.test.js +0 -83
  75. package/dist/ClassRegistry.test.js.map +0 -1
  76. package/dist/DataBlockParsers.test.d.ts +0 -2
  77. package/dist/DataBlockParsers.test.d.ts.map +0 -1
  78. package/dist/DataBlockParsers.test.js +0 -294
  79. package/dist/DataBlockParsers.test.js.map +0 -1
  80. package/dist/DemoParser.test.d.ts +0 -2
  81. package/dist/DemoParser.test.d.ts.map +0 -1
  82. package/dist/DemoParser.test.js +0 -472
  83. package/dist/DemoParser.test.js.map +0 -1
  84. package/dist/GhostStateAccumulator.test.d.ts +0 -2
  85. package/dist/GhostStateAccumulator.test.d.ts.map +0 -1
  86. package/dist/GhostStateAccumulator.test.js +0 -201
  87. package/dist/GhostStateAccumulator.test.js.map +0 -1
  88. package/dist/GhostTracker.test.d.ts +0 -2
  89. package/dist/GhostTracker.test.d.ts.map +0 -1
  90. package/dist/GhostTracker.test.js +0 -64
  91. package/dist/GhostTracker.test.js.map +0 -1
  92. package/dist/IncrementalParser.test.d.ts +0 -2
  93. package/dist/IncrementalParser.test.d.ts.map +0 -1
  94. package/dist/IncrementalParser.test.js +0 -226
  95. package/dist/IncrementalParser.test.js.map +0 -1
package/README.md CHANGED
@@ -11,6 +11,8 @@ thread responsive: in browsers, decompression runs in a Web Worker via
11
11
  [fflate](https://github.com/101arrowz/fflate), and blocks are parsed lazily
12
12
  one at a time.
13
13
 
14
+ Requires Node.js 18 or newer (or any modern browser).
15
+
14
16
  ## Quick start
15
17
 
16
18
  ```typescript
@@ -75,7 +77,11 @@ All parser bindings (53 ghost classes, 54 DataBlock classes, 26 event classes)
75
77
  are set up deterministically in the constructor.
76
78
 
77
79
  ```typescript
78
- const parser = new DemoParser(buffer: Uint8Array);
80
+ const parser = new DemoParser(buffer: Uint8Array, options?: {
81
+ incremental?: boolean; // feed the block stream via push()/finish()
82
+ ignoreProtocolVersion?: boolean; // see below
83
+ haltOnFault?: boolean; // passed to PacketParser (default true)
84
+ });
79
85
  ```
80
86
 
81
87
  #### `async load(): Promise<LoadResult>`
@@ -83,6 +89,13 @@ const parser = new DemoParser(buffer: Uint8Array);
83
89
  Parse the header and initial block, then asynchronously decompress the block
84
90
  stream. Does **not** parse any blocks — use `nextBlock()` to consume them.
85
91
 
92
+ The header is validated the way the game's demo playback validates it: the
93
+ ident string must be `"Tribes2 Recording"` and the protocol version must be
94
+ `0x330004` (build 25034), otherwise `load()` throws. The game refuses to play
95
+ other versions too, and their block formats are not guaranteed to match; pass
96
+ `{ ignoreProtocolVersion: true }` to try anyway. A buffer too short to hold
97
+ the initial block throws a `RangeError`.
98
+
86
99
  Idempotent: calling `load()` again returns the cached result.
87
100
 
88
101
  ```typescript
@@ -96,6 +109,9 @@ interface LoadResult {
96
109
 
97
110
  Read and parse the next block from the decompressed stream. Returns `undefined`
98
111
  when the stream is exhausted. Each call advances `blockCursor` by one.
112
+ Packets that the parser cannot fully consume are reported through
113
+ `PacketData.parseFault` (see `PacketParser` below); a block whose decoder
114
+ threw carries the message in `DemoBlock.parseError`.
99
115
 
100
116
  Blocks are transient — only one exists in memory at a time (previous blocks are
101
117
  eligible for GC unless you retain a reference).
@@ -208,6 +224,9 @@ interface InitialBlockData {
208
224
  phase2Valid?: boolean;
209
225
  phase2Error?: string;
210
226
  phase2TrailingBits?: number;
227
+ // Seeded state Tribes2.exe would crash on during playback (always empty
228
+ // for recordings made by the game; see freshConnectionProtocolState).
229
+ warnings: string[];
211
230
  }
212
231
  ```
213
232
 
@@ -225,6 +244,14 @@ interface DemoBlock {
225
244
  size: number; // Payload size in bytes
226
245
  data: Uint8Array; // Raw payload
227
246
  parsed?: PacketData | Move | InfoBlock;
247
+ parseError?: string; // Set if decoding threw (a parser bug)
248
+ }
249
+
250
+ // Type 3 block: written after every received packet, replayed through
251
+ // setControlCameraFov on playback.
252
+ interface InfoBlock {
253
+ firstPerson: boolean; // $firstPerson (byte 0; the other 3 bytes are garbage)
254
+ cameraFov: number; // control camera FOV in degrees
228
255
  }
229
256
  ```
230
257
 
@@ -241,6 +268,11 @@ interface PacketData {
241
268
  gameState: GameState;
242
269
  events: NetEventInfo[];
243
270
  ghosts: GhostUpdate[];
271
+ /** Set when any section failed to parse; the ghost tracker and
272
+ * event sequence no longer mirror the server, so a live consumer
273
+ * must re-sync from a fresh connection (the engine disconnects).
274
+ * The message names the parser and the underlying error. */
275
+ parseFault?: { stage: "gameState" | "event" | "ghost"; message: string };
244
276
  }
245
277
  ```
246
278
 
@@ -259,6 +291,7 @@ interface GameState {
259
291
  controlObjectDataStart?: number; // Bit offsets of the control object
260
292
  controlObjectDataEnd?: number; // update within the packet
261
293
  controlObjectData?: Record<string, unknown>;
294
+ controlObjectError?: string; // Why readPacketData could not be applied
262
295
  compressionPoint?: { x: number; y: number; z: number };
263
296
  cameraFov?: number;
264
297
  targetVisibility?: { index: number; mask: number }[];
@@ -286,6 +319,8 @@ interface GhostUpdate {
286
319
  updateBitsStart: number;
287
320
  updateBitsEnd: number;
288
321
  parsedData?: Record<string, unknown>; // Class-specific parsed fields
322
+ failed?: boolean; // Could not be parsed; the ghost section stops here
323
+ error?: string; // Parser name and error text when failed
289
324
  }
290
325
  ```
291
326
 
@@ -304,6 +339,7 @@ interface NetEventInfo {
304
339
  parsedData?: Record<string, unknown>;
305
340
  failed?: boolean; // Event could not be parsed; stream
306
341
  // position after it is unreliable
342
+ error?: string; // Parser name and error text when failed
307
343
  }
308
344
  ```
309
345
 
@@ -357,8 +393,11 @@ interface ParsedDataBlock {
357
393
 
358
394
  #### `buildTimeline(demo, registry): DemoTimeline`
359
395
 
360
- Extract a time-indexed timeline from a fully parsed `DemoFile`. Timestamps are
361
- derived by distributing packets evenly across the demo duration.
396
+ Extract a time-indexed timeline from a fully parsed `DemoFile`. Every Move
397
+ block is one 32ms simulation tick (`MoveTickMs`), so a packet's timestamp is
398
+ the number of Move blocks before it × 32ms — exact demo time, the same clock
399
+ as `DemoParser.bufferedMoveTicks` and the seek guide below. `tickIntervalMs`
400
+ is always `MoveTickMs`.
362
401
 
363
402
  ```typescript
364
403
  import { buildTimeline } from "t2-demo-parser";
@@ -477,6 +516,27 @@ Available via `parser.getPacketParser()`. Exposes parse statistics.
477
516
  | `controlObjectFailed` | `number` | Control object updates that failed. |
478
517
  | `protocolRejected` | `number` | Packets rejected by the dnet protocol window. |
479
518
  | `protocolNoDispatch` | `number` | Packets accepted but not dispatched (duplicates/out-of-window). |
519
+ | `packetsDroppedAfterFault` | `number` | Packets returned empty because the parser had halted. |
520
+
521
+ #### Faults and halting
522
+
523
+ The engine drops the connection on any packet it cannot read ("Invalid
524
+ packet"). `PacketParser` mirrors that: the first packet whose game state,
525
+ events, or ghosts fail to parse gets a `parseFault`, and by default the
526
+ parser **halts** — every later `parsePacket()` returns an empty `PacketData`
527
+ carrying the same fault and touches no state, because it would otherwise be
528
+ parsing against ghost and event state that no longer mirrors the server.
529
+
530
+ | Member | Description |
531
+ | ----------- | ------------------------------------------------------------------- |
532
+ | `fault` | The first `ParseFault`, or `undefined`. |
533
+ | `faulted` | `true` once a fault has been recorded. |
534
+
535
+ Pass `haltOnFault: false` (to `new PacketParser`, `new DemoParser`, or
536
+ `createLiveParser`) to keep parsing regardless; each later packet still
537
+ reports its own `parseFault` when it has one. To continue after a fault,
538
+ build a fresh parser: `DemoParser.reset()`, or a new `createLiveParser`
539
+ seeded from a known-good exported state.
480
540
 
481
541
  #### State export (for seeding another parser)
482
542
 
@@ -490,8 +550,8 @@ late-joiner catch-up in live streaming.
490
550
  | `getConnectionProtocolState()` | `ConnectionProtocolState` (dnet sequence window) |
491
551
  | `getNextRecvEventSeq()` | `number` |
492
552
  | `getPendingGuaranteedEvents()` | Out-of-order guaranteed events awaiting dispatch |
493
- | `getCompressionPoint()` | `{ x, y, z }` |
494
- | `getDataBlockDataMap()` | `Map<number, ParsedData> \| undefined` |
553
+ | `getCompressionPoint()` | `{ x, y, z }` (a copy) |
554
+ | `getDataBlockDataMap()` | `ReadonlyMap<number, ParsedData> \| undefined` |
495
555
  | `setConnectionProtocolState(state)` | — (also a constructor option) |
496
556
 
497
557
  ---
@@ -533,6 +593,7 @@ interface LiveParserSeed {
533
593
  absoluteSequenceNumber: number;
534
594
  event: NetEventInfo;
535
595
  }>;
596
+ haltOnFault?: boolean; // default true, see PacketParser
536
597
  }
537
598
  ```
538
599
 
@@ -545,6 +606,13 @@ sequences the observer didn't send. Intended for the first packets of a
545
606
  connection; to attach mid-stream, seed `connectionProtocolState` from the
546
607
  exporting parser instead.
547
608
 
609
+ Parser-only: never write this state into a `.rec` initial block. The game
610
+ requires the start block's notify count to equal
611
+ `lastSendSeq - highestAckedSeq` and treats a difference above 0x1d as a
612
+ full send window, so a demo seeded this way crashes Tribes2.exe on the
613
+ first acknowledged packet. `DemoParser` reports such files in
614
+ `initialBlock.warnings`.
615
+
548
616
  ```typescript
549
617
  import { createLiveParser, passiveObserverProtocolState } from "t2-demo-parser";
550
618
 
@@ -553,6 +621,14 @@ const { packetParser } = createLiveParser();
553
621
  packetParser.setConnectionProtocolState(passiveObserverProtocolState(data[0]));
554
622
  ```
555
623
 
624
+ ### `freshConnectionProtocolState(connectSequence): ConnectionProtocolState`
625
+
626
+ The state of a connection that has not yet exchanged a sequenced packet:
627
+ everything zero except the connect sequence, with `connectionEstablished`
628
+ set. This is what a recording that starts at connect time must seed
629
+ (with a notify count of 0), writing one SendPacket marker per packet the
630
+ recorder actually sends, before the received packet that acks it.
631
+
556
632
  ---
557
633
 
558
634
  ### `GhostStateAccumulator`
@@ -596,6 +672,42 @@ const value = bs.readInt(10);
596
672
  const str = bs.readString();
597
673
  ```
598
674
 
675
+ Reads never throw on short data: a read that would pass the end of the
676
+ buffer returns zero (or an empty buffer), leaves the cursor in place, and
677
+ sets the error flag, which `isError()` reports — the same contract as the
678
+ engine's BitStream. `readInt` throws a `RangeError` for bit counts above 32.
679
+ Strings are decoded byte-per-character (Latin-1); Tribes 2 tagged strings
680
+ begin with `"\x01"`.
681
+
682
+ ### `BitWriter`
683
+
684
+ The matching LSB-first bit packer, for building test vectors and synthetic
685
+ packets: `writeFlag`, `writeInt`, `writeSignedInt`, `writeU8/U32/S32`,
686
+ `writeF32`, `writeFloat`, `writeBytes`, and `writeString` (Huffman, exactly
687
+ as the engine's `writeString`). `finish()` returns the packed `Uint8Array`.
688
+
689
+ ```typescript
690
+ import { BitWriter, BitStream } from "t2-demo-parser";
691
+
692
+ const bytes = new BitWriter().writeFlag(true).writeInt(5, 4).writeString("hi").finish();
693
+ const bs = new BitStream(bytes); // readFlag() → true, readInt(4) → 5, readString() → "hi"
694
+ ```
695
+
696
+ ### `ClassRegistry` / `createDefaultRegistry()`
697
+
698
+ `createDefaultRegistry()` returns a registry with every built-in parser bound
699
+ to its deterministic classId — the same setup `DemoParser` and
700
+ `createLiveParser` use. Lookups go both ways:
701
+
702
+ | Method | Returns |
703
+ | --------------------------------------- | -------------------------------- |
704
+ | `getGhostParser(classId)` etc. | Parser entry for a bound classId |
705
+ | `getGhostClassId(name)` etc. | Bound classId for a class name |
706
+ | `getGhostCatalog()` etc. | `ReadonlyMap<name, entry>` |
707
+ | `getGhostBindings()` etc. | `Map<classId, name>` (debug) |
708
+
709
+ The `Event` and `DataBlock` variants of each method exist too.
710
+
599
711
  ---
600
712
 
601
713
  ### `GhostTracker`
@@ -606,7 +718,7 @@ Tracks the live state of all ghost objects. Available via
606
718
  ```typescript
607
719
  const tracker = parser.getGhostTracker();
608
720
  const ghost = tracker.getGhost(index); // GhostEntry | undefined
609
- const all = tracker.getAllGhosts(); // Map<number, GhostEntry>
721
+ const all = tracker.getAllGhosts(); // ReadonlyMap<number, GhostEntry>
610
722
  tracker.size(); // Number of active ghosts
611
723
  ```
612
724
 
@@ -614,10 +726,12 @@ tracker.size(); // Number of active ghosts
614
726
  interface GhostEntry {
615
727
  classId: number;
616
728
  className: string;
617
- state: Record<string, unknown>;
618
729
  }
619
730
  ```
620
731
 
732
+ Accumulated per-ghost state lives in `GhostStateAccumulator`, not in the
733
+ tracker.
734
+
621
735
  ---
622
736
 
623
737
  ### Constants
@@ -630,6 +744,9 @@ import {
630
744
  BlockTypeSendPacket, // 1 — send-packet trigger (no data)
631
745
  BlockTypeMove, // 2 — 64-byte player input
632
746
  BlockTypeInfo, // 3 — 8-byte timing/FOV
747
+ MoveTickMs, // 32 — one Move block per simulation tick
748
+ DemoIdentString, // "Tribes2 Recording"
749
+ DemoProtocolVersion, // 0x330004 (build 25034)
633
750
  } from "t2-demo-parser";
634
751
  ```
635
752
 
@@ -886,10 +1003,56 @@ DEBUG=t2-demo-parser:initial npx t2-demo-parser demo.rec
886
1003
 
887
1004
  # Just block stream parsing
888
1005
  DEBUG=t2-demo-parser:blocks npx t2-demo-parser demo.rec
1006
+
1007
+ # Per-event / per-ghost parse failures and tracker re-creates
1008
+ DEBUG=t2-demo-parser:events,t2-demo-parser:ghosts,t2-demo-parser:ghost-tracker npx t2-demo-parser demo.rec
889
1009
  ```
890
1010
 
1011
+ ### Known limitations
1012
+
1013
+ - One archived demo (a 2000s-era recording) carries a TerrainBlock
1014
+ `GhostAlwaysObjectEvent` after a mission change whose payload holds 377 more
1015
+ bits than build 25034's `TerrainBlock::unpackUpdate` reads (a shared-prefix
1016
+ string with the terrain's material list, then 91 unidentified bits). Seven
1017
+ other mission-change TerrainBlock events in other demos match the binary
1018
+ exactly, so this is a conditional extension of an unidentified client
1019
+ build. The parser faults cleanly at that packet instead of guessing.
1020
+ - `SimVoiceStreamEvent` follows the binary's layout (which differs from the
1021
+ V12 source), but no available demo contains voice traffic, so it is
1022
+ verified against the disassembly only.
1023
+
891
1024
  ---
892
1025
 
1026
+ ## Upgrading from 2.x
1027
+
1028
+ Breaking changes in this version:
1029
+
1030
+ - **Halt on fault.** `PacketParser` stops after the first `parseFault`
1031
+ (`haltOnFault: false` restores the old behaviour).
1032
+ - **Header validation.** `DemoParser.load()` throws on a wrong ident string or
1033
+ protocol version (`ignoreProtocolVersion: true` to override).
1034
+ - **Timeline timestamps** come from Move ticks (32ms) instead of an even
1035
+ spread of packets over the demo length; `tickIntervalMs` is now 32.
1036
+ - Removed fields: `GhostEntry.state`, `ConnectionContext.currentGhostIndex`,
1037
+ `SimDataBlockEventData._payloadBitPos` / `_needsClassParser`,
1038
+ `VehicleGhostData._controlledEarlyReturn`, `DebrisDataBlock.minSpinSpeed_dup`
1039
+ / `maxSpinSpeed_dup` (the second wire copy now lands in `minSpinSpeed` /
1040
+ `maxSpinSpeed`, as on the client). `GhostAlwaysObjectEventData._hasObjectData`
1041
+ is now `hasObjectData`; `DebrisGhostData.objectRef2` is folded into
1042
+ `objectRefs` (three entries); `ShapeBaseDataBlock.jetEffect` is `null`
1043
+ rather than `undefined` when absent.
1044
+ - `SimVoiceStreamEventData` now reflects the binary's wire format
1045
+ (`sequence`, `codecId`, `streamId`, `clientId`, `partial`, `frameCount`,
1046
+ `audioData` or `frames`).
1047
+ - A `SimDataBlockEvent` with no parser (or whose payload fails) now fails the
1048
+ event (and the packet) instead of returning silently misaligned.
1049
+ - Parsed-data types are now type aliases without index signatures; property
1050
+ access on them is checked.
1051
+ - `getAllGhosts()`, `getGhostCatalog()`, and `getDataBlockDataMap()` return
1052
+ read-only maps; `getCompressionPoint()` returns a copy.
1053
+ - `ShapeBase` ghosts' `readPacketData` reads energy + recharge only (it was
1054
+ bound to the Vehicle reader).
1055
+
893
1056
  ## Supported classes
894
1057
 
895
1058
  ### Ghost classes (53)
@@ -33,9 +33,17 @@ export declare class BitStream {
33
33
  readFloat(bitCount: number): number;
34
34
  /** Read a float normalized to [-1, 1]. */
35
35
  readSignedFloat(bitCount: number): number;
36
- /** Read a ranged unsigned 32-bit integer. */
36
+ /**
37
+ * Read a ranged unsigned 32-bit integer. Bit width is
38
+ * getBinLog2(getNextPow2(rangeSize)) as in the engine (FUN_0043f120 /
39
+ * FUN_0043f150): a range of one value reads zero bits.
40
+ */
37
41
  readRangedU32(rangeStart: number, rangeEnd: number): number;
38
- /** Read raw bits into a new Uint8Array. */
42
+ /**
43
+ * Read raw bits into a new Uint8Array. Like every other read, an
44
+ * over-length request sets the error flag, leaves the cursor in place,
45
+ * and returns zeroed bytes (the engine's BitStream::readBits).
46
+ */
39
47
  readBitsBuffer(bitCount: number): Uint8Array;
40
48
  /** Read N raw bytes. Returns an array of byte values. */
41
49
  readBytes(count: number): number[];
@@ -85,11 +93,14 @@ export declare class BitStream {
85
93
  /**
86
94
  * Read a Huffman-encoded string.
87
95
  * Handles the stringBuffer optimization (shared prefix with previous string).
96
+ * Each wire byte becomes one UTF-16 code unit (Latin-1 decoding); Tribes 2
97
+ * strings are not UTF-8, and tagged strings begin with "\x01".
88
98
  */
89
99
  readString(): string;
90
100
  /** Enable/disable the string buffer for shared-prefix optimization. */
91
101
  setStringBuffer(enable: boolean): void;
92
- /** Skip N bits. */
102
+ /** Skip N bits. Sets the error flag (without moving) if that would
103
+ * pass the end of the buffer. */
93
104
  skipBits(count: number): void;
94
105
  /** Read 3x F32 as a Point3F. */
95
106
  readPoint3F(): {
@@ -1 +1 @@
1
- {"version":3,"file":"BitStream.d.ts","sourceRoot":"","sources":["../src/BitStream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BitStream.d.ts","sourceRoot":"","sources":["../src/BitStream.ts"],"names":[],"mappings":"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"}
package/dist/BitStream.js CHANGED
@@ -58,6 +58,9 @@ export class BitStream {
58
58
  readInt(bitCount) {
59
59
  if (bitCount === 0)
60
60
  return 0;
61
+ if (!(bitCount > 0 && bitCount <= 32)) {
62
+ throw new RangeError(`readInt bitCount out of range: ${bitCount}`);
63
+ }
61
64
  if (this.bitNum + bitCount > this.maxReadBitNum) {
62
65
  this.error = true;
63
66
  return 0;
@@ -100,24 +103,36 @@ export class BitStream {
100
103
  }
101
104
  /** Read a float normalized to [0, 1]. */
102
105
  readFloat(bitCount) {
103
- return this.readInt(bitCount) / ((1 << bitCount) - 1);
106
+ return this.readInt(bitCount) / (2 ** bitCount - 1);
104
107
  }
105
108
  /** Read a float normalized to [-1, 1]. */
106
109
  readSignedFloat(bitCount) {
107
- return (this.readInt(bitCount) * 2) / ((1 << bitCount) - 1) - 1.0;
110
+ return (this.readInt(bitCount) * 2) / (2 ** bitCount - 1) - 1.0;
108
111
  }
109
- /** Read a ranged unsigned 32-bit integer. */
112
+ /**
113
+ * Read a ranged unsigned 32-bit integer. Bit width is
114
+ * getBinLog2(getNextPow2(rangeSize)) as in the engine (FUN_0043f120 /
115
+ * FUN_0043f150): a range of one value reads zero bits.
116
+ */
110
117
  readRangedU32(rangeStart, rangeEnd) {
111
118
  const rangeSize = rangeEnd - rangeStart + 1;
112
- const rangeBits = Math.ceil(Math.log2(rangeSize)) || 1;
119
+ const rangeBits = Math.ceil(Math.log2(rangeSize));
113
120
  return this.readInt(rangeBits) + rangeStart;
114
121
  }
115
- /** Read raw bits into a new Uint8Array. */
122
+ /**
123
+ * Read raw bits into a new Uint8Array. Like every other read, an
124
+ * over-length request sets the error flag, leaves the cursor in place,
125
+ * and returns zeroed bytes (the engine's BitStream::readBits).
126
+ */
116
127
  readBitsBuffer(bitCount) {
117
128
  if (bitCount === 0)
118
129
  return new Uint8Array(0);
119
130
  const byteCount = (bitCount + 7) >> 3;
120
131
  const result = new Uint8Array(byteCount);
132
+ if (bitCount < 0 || this.bitNum + bitCount > this.maxReadBitNum) {
133
+ this.error = true;
134
+ return result;
135
+ }
121
136
  const startByte = this.bitNum >> 3;
122
137
  const downShift = this.bitNum & 0x7;
123
138
  const upShift = 8 - downShift;
@@ -240,6 +255,8 @@ export class BitStream {
240
255
  /**
241
256
  * Read a Huffman-encoded string.
242
257
  * Handles the stringBuffer optimization (shared prefix with previous string).
258
+ * Each wire byte becomes one UTF-16 code unit (Latin-1 decoding); Tribes 2
259
+ * strings are not UTF-8, and tagged strings begin with "\x01".
243
260
  */
244
261
  readString() {
245
262
  if (this.stringBuffer !== null) {
@@ -262,8 +279,13 @@ export class BitStream {
262
279
  setStringBuffer(enable) {
263
280
  this.stringBuffer = enable ? "" : null;
264
281
  }
265
- /** Skip N bits. */
282
+ /** Skip N bits. Sets the error flag (without moving) if that would
283
+ * pass the end of the buffer. */
266
284
  skipBits(count) {
285
+ if (count < 0 || this.bitNum + count > this.maxReadBitNum) {
286
+ this.error = true;
287
+ return;
288
+ }
267
289
  this.bitNum += count;
268
290
  }
269
291
  /** Read 3x F32 as a Point3F. */
@@ -1 +1 @@
1
- {"version":3,"file":"BitStream.js","sourceRoot":"","sources":["../src/BitStream.ts"],"names":[],"mappings":"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","sourcesContent":["import { huffProcessor } from \"./HuffmanProcessor.js\";\n\n/**\n * Bit-level stream reader, ported from the V12 engine's BitStream class.\n *\n * Bits are read LSB-first within each byte:\n * byte[bitNum >> 3] & (1 << (bitNum & 7))\n */\nexport class BitStream {\n private data: Uint8Array;\n private bitNum: number;\n private maxReadBitNum: number;\n private error: boolean;\n private stringBuffer: string | null = null;\n\n constructor(data: Uint8Array, bitOffset = 0) {\n this.data = data;\n this.bitNum = bitOffset;\n this.maxReadBitNum = data.length << 3;\n this.error = false;\n }\n\n getCurPos(): number {\n return this.bitNum;\n }\n\n setCurPos(pos: number): void {\n this.bitNum = pos;\n }\n\n /** Byte position (rounded up), matching C++ getPosition() */\n getBytePosition(): number {\n return (this.bitNum + 7) >> 3;\n }\n\n isError(): boolean {\n return this.error;\n }\n\n /** Returns true if we've read past the buffer */\n isFull(): boolean {\n return this.bitNum > this.maxReadBitNum;\n }\n\n getRemainingBits(): number {\n return this.maxReadBitNum - this.bitNum;\n }\n\n getMaxPos(): number {\n return this.maxReadBitNum;\n }\n\n /** Read a single bit as a boolean. */\n readFlag(): boolean {\n if (this.bitNum >= this.maxReadBitNum) {\n this.error = true;\n return false;\n }\n const mask = 1 << (this.bitNum & 0x7);\n const ret = (this.data[this.bitNum >> 3] & mask) !== 0;\n this.bitNum++;\n return ret;\n }\n\n /**\n * Read N bits as an unsigned integer (up to 32 bits).\n * Bits are read LSB-first, matching the C++ implementation.\n */\n readInt(bitCount: number): number {\n if (bitCount === 0) return 0;\n if (this.bitNum + bitCount > this.maxReadBitNum) {\n this.error = true;\n return 0;\n }\n\n const startByte = this.bitNum >> 3;\n const downShift = this.bitNum & 0x7;\n this.bitNum += bitCount;\n\n // When bitCount + downShift <= 32, everything fits in 32-bit operations\n if (bitCount + downShift <= 32) {\n let ret = 0;\n const bytesNeeded = (bitCount + downShift + 7) >> 3;\n for (\n let i = 0;\n i < bytesNeeded && startByte + i < this.data.length;\n i++\n ) {\n ret |= this.data[startByte + i] << (i * 8);\n }\n ret = ret >>> downShift;\n if (bitCount === 32) return ret >>> 0;\n return ret & ((1 << bitCount) - 1);\n }\n\n // Slow path: bitCount + downShift > 32 (e.g., reading 32 bits at a\n // non-byte-aligned position). Use float64 arithmetic to avoid the\n // 32-bit limit of JavaScript bitwise operators.\n let ret = 0;\n const bytesNeeded = (bitCount + downShift + 7) >> 3;\n for (let i = 0; i < bytesNeeded && startByte + i < this.data.length; i++) {\n ret += this.data[startByte + i] * 2 ** (i * 8);\n }\n ret = Math.floor(ret / 2 ** downShift);\n // Mask to bitCount bits using float64-safe operations\n if (bitCount === 32) return ret >>> 0;\n return ret & ((1 << bitCount) - 1);\n }\n\n /** Read a signed integer: 1-bit sign flag + (bitCount-1) magnitude bits. */\n readSignedInt(bitCount: number): number {\n if (this.readFlag()) {\n return -this.readInt(bitCount - 1);\n }\n return this.readInt(bitCount - 1);\n }\n\n /** Read a float normalized to [0, 1]. */\n readFloat(bitCount: number): number {\n return this.readInt(bitCount) / ((1 << bitCount) - 1);\n }\n\n /** Read a float normalized to [-1, 1]. */\n readSignedFloat(bitCount: number): number {\n return (this.readInt(bitCount) * 2) / ((1 << bitCount) - 1) - 1.0;\n }\n\n /** Read a ranged unsigned 32-bit integer. */\n readRangedU32(rangeStart: number, rangeEnd: number): number {\n const rangeSize = rangeEnd - rangeStart + 1;\n const rangeBits = Math.ceil(Math.log2(rangeSize)) || 1;\n return this.readInt(rangeBits) + rangeStart;\n }\n\n /** Read raw bits into a new Uint8Array. */\n readBitsBuffer(bitCount: number): Uint8Array {\n if (bitCount === 0) return new Uint8Array(0);\n const byteCount = (bitCount + 7) >> 3;\n const result = new Uint8Array(byteCount);\n\n const startByte = this.bitNum >> 3;\n const downShift = this.bitNum & 0x7;\n const upShift = 8 - downShift;\n\n if (downShift === 0) {\n // Byte-aligned, fast path\n result.set(this.data.subarray(startByte, startByte + byteCount));\n } else {\n let curB = this.data[startByte];\n for (let i = 0; i < byteCount; i++) {\n const nextB =\n startByte + i + 1 < this.data.length\n ? this.data[startByte + i + 1]\n : 0;\n result[i] = ((curB >> downShift) | (nextB << upShift)) & 0xff;\n curB = nextB;\n }\n }\n\n // Mask off extra bits in the last byte\n const extraBits = bitCount & 0x7;\n if (extraBits !== 0) {\n result[byteCount - 1] &= (1 << extraBits) - 1;\n }\n\n this.bitNum += bitCount;\n return result;\n }\n\n /** Read N raw bytes. Returns an array of byte values. */\n readBytes(count: number): number[] {\n const buf = this.readBitsBuffer(count * 8);\n return Array.from(buf);\n }\n\n /** Read a U8 (8 bits). */\n readU8(): number {\n return this.readInt(8);\n }\n\n /** Read a U16 (16 bits, little-endian). */\n readU16(): number {\n return this.readInt(16);\n }\n\n /** Read a U32 (32 bits, little-endian). */\n readU32(): number {\n return this.readInt(32);\n }\n\n /** Read a signed 32-bit integer (via stream.read in C++). */\n readS32(): number {\n const val = this.readU32();\n return val | 0; // convert to signed\n }\n\n /** Shared buffer for allocation-free F32 reads. */\n private static readonly f32Buf = new ArrayBuffer(4);\n private static readonly f32View = new DataView(BitStream.f32Buf);\n private static readonly f32U8 = new Uint8Array(BitStream.f32Buf);\n\n /** Read a 32-bit float (IEEE 754), allocation-free. */\n readF32(): number {\n if (this.bitNum + 32 > this.maxReadBitNum) {\n this.error = true;\n return 0;\n }\n\n const startByte = this.bitNum >> 3;\n const downShift = this.bitNum & 0x7;\n const u8 = BitStream.f32U8;\n\n if (downShift === 0) {\n u8[0] = this.data[startByte];\n u8[1] = this.data[startByte + 1];\n u8[2] = this.data[startByte + 2];\n u8[3] = this.data[startByte + 3];\n } else {\n const upShift = 8 - downShift;\n for (let i = 0; i < 4; i++) {\n const curB = this.data[startByte + i];\n const nextB =\n startByte + i + 1 < this.data.length\n ? this.data[startByte + i + 1]\n : 0;\n u8[i] = ((curB >> downShift) | (nextB << upShift)) & 0xff;\n }\n }\n\n this.bitNum += 32;\n return BitStream.f32View.getFloat32(0, true);\n }\n\n /** Read a boolean value stored as a U8 (matches C++ Stream::read(bool*)). */\n readBool(): boolean {\n return this.readU8() !== 0;\n }\n\n /**\n * Read a compressed 3D normal vector.\n * Uses phi (azimuth) and theta (elevation) angles.\n */\n readNormalVector(bitCount: number): { x: number; y: number; z: number } {\n const phi = this.readSignedFloat(bitCount + 1) * Math.PI;\n const theta = this.readSignedFloat(bitCount) * (Math.PI / 2.0);\n\n return {\n x: Math.sin(phi) * Math.cos(theta),\n y: Math.cos(phi) * Math.cos(theta),\n z: Math.sin(theta),\n };\n }\n\n /**\n * Read an affine transform (position + quaternion rotation).\n * Position: 3x F32\n * Quaternion: 3x F32 (x,y,z) + 1-bit sign for w\n */\n readAffineTransform(): {\n position: { x: number; y: number; z: number };\n rotation: { x: number; y: number; z: number; w: number };\n } {\n const position = {\n x: this.readF32(),\n y: this.readF32(),\n z: this.readF32(),\n };\n\n const qx = this.readF32();\n const qy = this.readF32();\n const qz = this.readF32();\n let qw = Math.sqrt(\n Math.max(0, 1.0 - (qx * qx + qy * qy + qz * qz))\n );\n if (this.readFlag()) {\n qw = -qw;\n }\n\n return {\n position,\n rotation: { x: qx, y: qy, z: qz, w: qw },\n };\n }\n\n /**\n * Read a Huffman-encoded string.\n * Handles the stringBuffer optimization (shared prefix with previous string).\n */\n readString(): string {\n if (this.stringBuffer !== null) {\n if (this.readFlag()) {\n // Shared prefix optimization: offset into previous string\n const offset = this.readInt(8);\n const suffix = huffProcessor.readHuffBuffer(this);\n const result = this.stringBuffer.substring(0, offset) + suffix;\n this.stringBuffer = result;\n return result;\n }\n }\n const result = huffProcessor.readHuffBuffer(this);\n if (this.stringBuffer !== null) {\n this.stringBuffer = result;\n }\n return result;\n }\n\n /** Enable/disable the string buffer for shared-prefix optimization. */\n setStringBuffer(enable: boolean): void {\n this.stringBuffer = enable ? \"\" : null;\n }\n\n /** Skip N bits. */\n skipBits(count: number): void {\n this.bitNum += count;\n }\n\n /** Read 3x F32 as a Point3F. */\n readPoint3F(): { x: number; y: number; z: number } {\n return { x: this.readF32(), y: this.readF32(), z: this.readF32() };\n }\n\n /**\n * Read a compressed 3D point relative to a compression point.\n * Format: 2-bit type, then either absolute (3x F32) or relative delta.\n * Used by Player MoveMask and Vehicle PositionMask.\n */\n readCompressedPoint(\n compressionPoint: { x: number; y: number; z: number },\n scale: number = 0.01\n ): { x: number; y: number; z: number } {\n const type = this.readInt(2);\n if (type === 3) {\n // Absolute position\n return { x: this.readF32(), y: this.readF32(), z: this.readF32() };\n }\n // Relative to compression point\n const bitCounts = [16, 18, 20];\n const bits = bitCounts[type];\n const dx = this.readSignedInt(bits);\n const dy = this.readSignedInt(bits);\n const dz = this.readSignedInt(bits);\n return {\n x: compressionPoint.x + dx * scale,\n y: compressionPoint.y + dy * scale,\n z: compressionPoint.z + dz * scale,\n };\n }\n\n /**\n * Read a MatrixF written via mathWrite(MatrixF).\n * Format: 16x F32 (row-major in Torque's MatrixF storage) = 512 bits.\n */\n readMatrixF(): {\n elements: number[];\n position: { x: number; y: number; z: number };\n } {\n const elements = new Array<number>(16);\n for (let i = 0; i < 16; i++) {\n elements[i] = this.readF32();\n }\n\n // MatrixF is written row-major: each row is [r0, r1, r2, translation].\n // Position (column 3) is at indices 3, 7, 11 (last element of each row).\n return {\n elements,\n position: { x: elements[3], y: elements[7], z: elements[11] },\n };\n }\n\n /**\n * Read a Torque \"packed string\" with 2-bit type code.\n * Used by RemoteCommandEvent for script arguments.\n * Tribes 2 binary (FUN_00588690) format:\n * 0 = null/empty\n * 1 = normal packed string\n * 2 = tagged string id (10-bit), decoded to \"\\x01<decimalId>\"\n * 3 = integer string (sign + 7/15/31-bit magnitude)\n */\n unpackNetString(): string {\n const code = this.readInt(2);\n switch (code) {\n case 0:\n return \"\"; // null string\n case 1:\n return this.readString(); // Huffman-encoded string\n case 2: {\n // Decompiled binary uses 10 bits here, not 12.\n const tag = this.readInt(10);\n // Keep Tribes 2 tagged-string wire representation.\n return `\\x01${tag}`;\n }\n case 3: {\n // Integer encoding: sign + variable-size magnitude\n const neg = this.readFlag();\n let num: number;\n if (this.readFlag()) {\n num = this.readInt(7); // small\n } else if (this.readFlag()) {\n num = this.readInt(15); // medium\n } else {\n num = this.readInt(31); // large\n }\n if (neg) num = -num;\n return String(num);\n }\n default:\n return \"\";\n }\n }\n\n /** Create a snapshot of the current position that can be restored. */\n savePos(): number {\n return this.bitNum;\n }\n\n /** Restore a previously saved position. */\n restorePos(pos: number): void {\n this.bitNum = pos;\n this.error = false;\n }\n\n /** Get the underlying data buffer. */\n getBuffer(): Uint8Array {\n return this.data;\n }\n}\n"]}
1
+ {"version":3,"file":"BitStream.js","sourceRoot":"","sources":["../src/BitStream.ts"],"names":[],"mappings":"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","sourcesContent":["import { huffProcessor } from \"./HuffmanProcessor.js\";\n\n/**\n * Bit-level stream reader, ported from the V12 engine's BitStream class.\n *\n * Bits are read LSB-first within each byte:\n * byte[bitNum >> 3] & (1 << (bitNum & 7))\n */\nexport class BitStream {\n private data: Uint8Array;\n private bitNum: number;\n private maxReadBitNum: number;\n private error: boolean;\n private stringBuffer: string | null = null;\n\n constructor(data: Uint8Array, bitOffset = 0) {\n this.data = data;\n this.bitNum = bitOffset;\n this.maxReadBitNum = data.length << 3;\n this.error = false;\n }\n\n getCurPos(): number {\n return this.bitNum;\n }\n\n setCurPos(pos: number): void {\n this.bitNum = pos;\n }\n\n /** Byte position (rounded up), matching C++ getPosition() */\n getBytePosition(): number {\n return (this.bitNum + 7) >> 3;\n }\n\n isError(): boolean {\n return this.error;\n }\n\n /** Returns true if we've read past the buffer */\n isFull(): boolean {\n return this.bitNum > this.maxReadBitNum;\n }\n\n getRemainingBits(): number {\n return this.maxReadBitNum - this.bitNum;\n }\n\n getMaxPos(): number {\n return this.maxReadBitNum;\n }\n\n /** Read a single bit as a boolean. */\n readFlag(): boolean {\n if (this.bitNum >= this.maxReadBitNum) {\n this.error = true;\n return false;\n }\n const mask = 1 << (this.bitNum & 0x7);\n const ret = (this.data[this.bitNum >> 3] & mask) !== 0;\n this.bitNum++;\n return ret;\n }\n\n /**\n * Read N bits as an unsigned integer (up to 32 bits).\n * Bits are read LSB-first, matching the C++ implementation.\n */\n readInt(bitCount: number): number {\n if (bitCount === 0) return 0;\n if (!(bitCount > 0 && bitCount <= 32)) {\n throw new RangeError(`readInt bitCount out of range: ${bitCount}`);\n }\n if (this.bitNum + bitCount > this.maxReadBitNum) {\n this.error = true;\n return 0;\n }\n\n const startByte = this.bitNum >> 3;\n const downShift = this.bitNum & 0x7;\n this.bitNum += bitCount;\n\n // When bitCount + downShift <= 32, everything fits in 32-bit operations\n if (bitCount + downShift <= 32) {\n let ret = 0;\n const bytesNeeded = (bitCount + downShift + 7) >> 3;\n for (\n let i = 0;\n i < bytesNeeded && startByte + i < this.data.length;\n i++\n ) {\n ret |= this.data[startByte + i] << (i * 8);\n }\n ret = ret >>> downShift;\n if (bitCount === 32) return ret >>> 0;\n return ret & ((1 << bitCount) - 1);\n }\n\n // Slow path: bitCount + downShift > 32 (e.g., reading 32 bits at a\n // non-byte-aligned position). Use float64 arithmetic to avoid the\n // 32-bit limit of JavaScript bitwise operators.\n let ret = 0;\n const bytesNeeded = (bitCount + downShift + 7) >> 3;\n for (let i = 0; i < bytesNeeded && startByte + i < this.data.length; i++) {\n ret += this.data[startByte + i] * 2 ** (i * 8);\n }\n ret = Math.floor(ret / 2 ** downShift);\n // Mask to bitCount bits using float64-safe operations\n if (bitCount === 32) return ret >>> 0;\n return ret & ((1 << bitCount) - 1);\n }\n\n /** Read a signed integer: 1-bit sign flag + (bitCount-1) magnitude bits. */\n readSignedInt(bitCount: number): number {\n if (this.readFlag()) {\n return -this.readInt(bitCount - 1);\n }\n return this.readInt(bitCount - 1);\n }\n\n /** Read a float normalized to [0, 1]. */\n readFloat(bitCount: number): number {\n return this.readInt(bitCount) / (2 ** bitCount - 1);\n }\n\n /** Read a float normalized to [-1, 1]. */\n readSignedFloat(bitCount: number): number {\n return (this.readInt(bitCount) * 2) / (2 ** bitCount - 1) - 1.0;\n }\n\n /**\n * Read a ranged unsigned 32-bit integer. Bit width is\n * getBinLog2(getNextPow2(rangeSize)) as in the engine (FUN_0043f120 /\n * FUN_0043f150): a range of one value reads zero bits.\n */\n readRangedU32(rangeStart: number, rangeEnd: number): number {\n const rangeSize = rangeEnd - rangeStart + 1;\n const rangeBits = Math.ceil(Math.log2(rangeSize));\n return this.readInt(rangeBits) + rangeStart;\n }\n\n /**\n * Read raw bits into a new Uint8Array. Like every other read, an\n * over-length request sets the error flag, leaves the cursor in place,\n * and returns zeroed bytes (the engine's BitStream::readBits).\n */\n readBitsBuffer(bitCount: number): Uint8Array {\n if (bitCount === 0) return new Uint8Array(0);\n const byteCount = (bitCount + 7) >> 3;\n const result = new Uint8Array(byteCount);\n if (bitCount < 0 || this.bitNum + bitCount > this.maxReadBitNum) {\n this.error = true;\n return result;\n }\n\n const startByte = this.bitNum >> 3;\n const downShift = this.bitNum & 0x7;\n const upShift = 8 - downShift;\n\n if (downShift === 0) {\n // Byte-aligned, fast path\n result.set(this.data.subarray(startByte, startByte + byteCount));\n } else {\n let curB = this.data[startByte];\n for (let i = 0; i < byteCount; i++) {\n const nextB =\n startByte + i + 1 < this.data.length\n ? this.data[startByte + i + 1]\n : 0;\n result[i] = ((curB >> downShift) | (nextB << upShift)) & 0xff;\n curB = nextB;\n }\n }\n\n // Mask off extra bits in the last byte\n const extraBits = bitCount & 0x7;\n if (extraBits !== 0) {\n result[byteCount - 1] &= (1 << extraBits) - 1;\n }\n\n this.bitNum += bitCount;\n return result;\n }\n\n /** Read N raw bytes. Returns an array of byte values. */\n readBytes(count: number): number[] {\n const buf = this.readBitsBuffer(count * 8);\n return Array.from(buf);\n }\n\n /** Read a U8 (8 bits). */\n readU8(): number {\n return this.readInt(8);\n }\n\n /** Read a U16 (16 bits, little-endian). */\n readU16(): number {\n return this.readInt(16);\n }\n\n /** Read a U32 (32 bits, little-endian). */\n readU32(): number {\n return this.readInt(32);\n }\n\n /** Read a signed 32-bit integer (via stream.read in C++). */\n readS32(): number {\n const val = this.readU32();\n return val | 0; // convert to signed\n }\n\n /** Shared buffer for allocation-free F32 reads. */\n private static readonly f32Buf = new ArrayBuffer(4);\n private static readonly f32View = new DataView(BitStream.f32Buf);\n private static readonly f32U8 = new Uint8Array(BitStream.f32Buf);\n\n /** Read a 32-bit float (IEEE 754), allocation-free. */\n readF32(): number {\n if (this.bitNum + 32 > this.maxReadBitNum) {\n this.error = true;\n return 0;\n }\n\n const startByte = this.bitNum >> 3;\n const downShift = this.bitNum & 0x7;\n const u8 = BitStream.f32U8;\n\n if (downShift === 0) {\n u8[0] = this.data[startByte];\n u8[1] = this.data[startByte + 1];\n u8[2] = this.data[startByte + 2];\n u8[3] = this.data[startByte + 3];\n } else {\n const upShift = 8 - downShift;\n for (let i = 0; i < 4; i++) {\n const curB = this.data[startByte + i];\n const nextB =\n startByte + i + 1 < this.data.length\n ? this.data[startByte + i + 1]\n : 0;\n u8[i] = ((curB >> downShift) | (nextB << upShift)) & 0xff;\n }\n }\n\n this.bitNum += 32;\n return BitStream.f32View.getFloat32(0, true);\n }\n\n /** Read a boolean value stored as a U8 (matches C++ Stream::read(bool*)). */\n readBool(): boolean {\n return this.readU8() !== 0;\n }\n\n /**\n * Read a compressed 3D normal vector.\n * Uses phi (azimuth) and theta (elevation) angles.\n */\n readNormalVector(bitCount: number): { x: number; y: number; z: number } {\n const phi = this.readSignedFloat(bitCount + 1) * Math.PI;\n const theta = this.readSignedFloat(bitCount) * (Math.PI / 2.0);\n\n return {\n x: Math.sin(phi) * Math.cos(theta),\n y: Math.cos(phi) * Math.cos(theta),\n z: Math.sin(theta),\n };\n }\n\n /**\n * Read an affine transform (position + quaternion rotation).\n * Position: 3x F32\n * Quaternion: 3x F32 (x,y,z) + 1-bit sign for w\n */\n readAffineTransform(): {\n position: { x: number; y: number; z: number };\n rotation: { x: number; y: number; z: number; w: number };\n } {\n const position = {\n x: this.readF32(),\n y: this.readF32(),\n z: this.readF32(),\n };\n\n const qx = this.readF32();\n const qy = this.readF32();\n const qz = this.readF32();\n let qw = Math.sqrt(Math.max(0, 1.0 - (qx * qx + qy * qy + qz * qz)));\n if (this.readFlag()) {\n qw = -qw;\n }\n\n return {\n position,\n rotation: { x: qx, y: qy, z: qz, w: qw },\n };\n }\n\n /**\n * Read a Huffman-encoded string.\n * Handles the stringBuffer optimization (shared prefix with previous string).\n * Each wire byte becomes one UTF-16 code unit (Latin-1 decoding); Tribes 2\n * strings are not UTF-8, and tagged strings begin with \"\\x01\".\n */\n readString(): string {\n if (this.stringBuffer !== null) {\n if (this.readFlag()) {\n // Shared prefix optimization: offset into previous string\n const offset = this.readInt(8);\n const suffix = huffProcessor.readHuffBuffer(this);\n const result = this.stringBuffer.substring(0, offset) + suffix;\n this.stringBuffer = result;\n return result;\n }\n }\n const result = huffProcessor.readHuffBuffer(this);\n if (this.stringBuffer !== null) {\n this.stringBuffer = result;\n }\n return result;\n }\n\n /** Enable/disable the string buffer for shared-prefix optimization. */\n setStringBuffer(enable: boolean): void {\n this.stringBuffer = enable ? \"\" : null;\n }\n\n /** Skip N bits. Sets the error flag (without moving) if that would\n * pass the end of the buffer. */\n skipBits(count: number): void {\n if (count < 0 || this.bitNum + count > this.maxReadBitNum) {\n this.error = true;\n return;\n }\n this.bitNum += count;\n }\n\n /** Read 3x F32 as a Point3F. */\n readPoint3F(): { x: number; y: number; z: number } {\n return { x: this.readF32(), y: this.readF32(), z: this.readF32() };\n }\n\n /**\n * Read a compressed 3D point relative to a compression point.\n * Format: 2-bit type, then either absolute (3x F32) or relative delta.\n * Used by Player MoveMask and Vehicle PositionMask.\n */\n readCompressedPoint(\n compressionPoint: { x: number; y: number; z: number },\n scale: number = 0.01,\n ): { x: number; y: number; z: number } {\n const type = this.readInt(2);\n if (type === 3) {\n // Absolute position\n return { x: this.readF32(), y: this.readF32(), z: this.readF32() };\n }\n // Relative to compression point\n const bitCounts = [16, 18, 20];\n const bits = bitCounts[type];\n const dx = this.readSignedInt(bits);\n const dy = this.readSignedInt(bits);\n const dz = this.readSignedInt(bits);\n return {\n x: compressionPoint.x + dx * scale,\n y: compressionPoint.y + dy * scale,\n z: compressionPoint.z + dz * scale,\n };\n }\n\n /**\n * Read a MatrixF written via mathWrite(MatrixF).\n * Format: 16x F32 (row-major in Torque's MatrixF storage) = 512 bits.\n */\n readMatrixF(): {\n elements: number[];\n position: { x: number; y: number; z: number };\n } {\n const elements = new Array<number>(16);\n for (let i = 0; i < 16; i++) {\n elements[i] = this.readF32();\n }\n\n // MatrixF is written row-major: each row is [r0, r1, r2, translation].\n // Position (column 3) is at indices 3, 7, 11 (last element of each row).\n return {\n elements,\n position: { x: elements[3], y: elements[7], z: elements[11] },\n };\n }\n\n /**\n * Read a Torque \"packed string\" with 2-bit type code.\n * Used by RemoteCommandEvent for script arguments.\n * Tribes 2 binary (FUN_00588690) format:\n * 0 = null/empty\n * 1 = normal packed string\n * 2 = tagged string id (10-bit), decoded to \"\\x01<decimalId>\"\n * 3 = integer string (sign + 7/15/31-bit magnitude)\n */\n unpackNetString(): string {\n const code = this.readInt(2);\n switch (code) {\n case 0:\n return \"\"; // null string\n case 1:\n return this.readString(); // Huffman-encoded string\n case 2: {\n // Decompiled binary uses 10 bits here, not 12.\n const tag = this.readInt(10);\n // Keep Tribes 2 tagged-string wire representation.\n return `\\x01${tag}`;\n }\n case 3: {\n // Integer encoding: sign + variable-size magnitude\n const neg = this.readFlag();\n let num: number;\n if (this.readFlag()) {\n num = this.readInt(7); // small\n } else if (this.readFlag()) {\n num = this.readInt(15); // medium\n } else {\n num = this.readInt(31); // large\n }\n if (neg) num = -num;\n return String(num);\n }\n default:\n return \"\";\n }\n }\n\n /** Create a snapshot of the current position that can be restored. */\n savePos(): number {\n return this.bitNum;\n }\n\n /** Restore a previously saved position. */\n restorePos(pos: number): void {\n this.bitNum = pos;\n this.error = false;\n }\n\n /** Get the underlying data buffer. */\n getBuffer(): Uint8Array {\n return this.data;\n }\n}\n"]}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * LSB-first bit packer producing buffers that BitStream reads back
3
+ * bit-for-bit. Mirrors the write side of the engine's BitStream for the
4
+ * primitives the parser consumes; intended for building test vectors and
5
+ * synthetic packets.
6
+ */
7
+ export declare class BitWriter {
8
+ private bytes;
9
+ private bitNum;
10
+ getCurPos(): number;
11
+ writeFlag(value: boolean): this;
12
+ /** Write the low `bitCount` bits of `value` (up to 32), LSB first. */
13
+ writeInt(value: number, bitCount: number): this;
14
+ writeSignedInt(value: number, bitCount: number): this;
15
+ writeU8(value: number): this;
16
+ writeU32(value: number): this;
17
+ writeS32(value: number): this;
18
+ writeF32(value: number): this;
19
+ /** Write a float in [0, 1] quantized to `bitCount` bits. */
20
+ writeFloat(value: number, bitCount: number): this;
21
+ writeBytes(bytes: ArrayLike<number>): this;
22
+ /** Write a Huffman string exactly as the engine's writeString does
23
+ * (no string-buffer prefix optimization). */
24
+ writeString(value: string): this;
25
+ /** Pad to a byte boundary (plus optional extra zero bytes) and return
26
+ * the packed buffer. */
27
+ finish(padBytes?: number): Uint8Array;
28
+ }
29
+ //# sourceMappingURL=BitWriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BitWriter.d.ts","sourceRoot":"","sources":["../src/BitWriter.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,MAAM,CAAK;IAEnB,SAAS,IAAI,MAAM;IAInB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI/B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAgB/C,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKrD,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI5B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAM7B,4DAA4D;IAC5D,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIjD,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI;IAK1C;kDAC8C;IAC9C,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKhC;6BACyB;IACzB,MAAM,CAAC,QAAQ,SAAI,GAAG,UAAU;CAMjC"}