t2-demo-parser 5.0.1 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -27
- package/dist/BitStream.d.ts +2 -0
- package/dist/BitStream.d.ts.map +1 -1
- package/dist/BitStream.js +8 -0
- package/dist/BitStream.js.map +1 -1
- package/dist/ClassRegistry.d.ts +4 -0
- package/dist/ClassRegistry.d.ts.map +1 -1
- package/dist/ClassRegistry.js.map +1 -1
- package/dist/DemoParser.d.ts +5 -0
- package/dist/DemoParser.d.ts.map +1 -1
- package/dist/DemoParser.js +17 -18
- package/dist/DemoParser.js.map +1 -1
- package/dist/GhostManager.d.ts.map +1 -1
- package/dist/GhostManager.js +33 -1
- package/dist/GhostManager.js.map +1 -1
- package/dist/LiveParser.d.ts +2 -0
- package/dist/LiveParser.d.ts.map +1 -1
- package/dist/LiveParser.js +1 -0
- package/dist/LiveParser.js.map +1 -1
- package/dist/PacketParser.d.ts +7 -1
- package/dist/PacketParser.d.ts.map +1 -1
- package/dist/PacketParser.js +14 -1
- package/dist/PacketParser.js.map +1 -1
- package/dist/ghostDataTypes.d.ts +2 -0
- package/dist/ghostDataTypes.d.ts.map +1 -1
- package/dist/ghostDataTypes.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -502,21 +502,21 @@ interface ControlObjectKeyframe {
|
|
|
502
502
|
|
|
503
503
|
Available via `parser.getPacketParser()`. Exposes parse statistics.
|
|
504
504
|
|
|
505
|
-
| Property
|
|
506
|
-
|
|
|
507
|
-
| `packetsParsed`
|
|
508
|
-
| `ghostCreatesParsed`
|
|
509
|
-
| `ghostUpdatesParsed`
|
|
510
|
-
| `ghostDeletes`
|
|
511
|
-
| `ghostsFailed`
|
|
512
|
-
| `ghostsTrackerDiverged`
|
|
513
|
-
| `eventsParsed`
|
|
514
|
-
| `eventsFailed`
|
|
515
|
-
| `controlObjectParsed`
|
|
516
|
-
| `controlObjectFailed`
|
|
517
|
-
| `protocolRejected`
|
|
518
|
-
| `protocolNoDispatch`
|
|
519
|
-
| `packetsDroppedAfterFault` | `number` | Packets returned empty because the parser had halted.
|
|
505
|
+
| Property | Type | Description |
|
|
506
|
+
| -------------------------- | -------- | --------------------------------------------------------------- |
|
|
507
|
+
| `packetsParsed` | `number` | Total packets successfully parsed. |
|
|
508
|
+
| `ghostCreatesParsed` | `number` | Ghost create operations parsed. |
|
|
509
|
+
| `ghostUpdatesParsed` | `number` | Ghost update operations parsed. |
|
|
510
|
+
| `ghostDeletes` | `number` | Ghost delete operations. |
|
|
511
|
+
| `ghostsFailed` | `number` | Ghost operations that failed to parse. |
|
|
512
|
+
| `ghostsTrackerDiverged` | `number` | Ghost tracker inconsistencies detected. |
|
|
513
|
+
| `eventsParsed` | `number` | Events parsed. |
|
|
514
|
+
| `eventsFailed` | `number` | Events that failed to parse. |
|
|
515
|
+
| `controlObjectParsed` | `number` | Control object updates parsed. |
|
|
516
|
+
| `controlObjectFailed` | `number` | Control object updates that failed. |
|
|
517
|
+
| `protocolRejected` | `number` | Packets rejected by the dnet protocol window. |
|
|
518
|
+
| `protocolNoDispatch` | `number` | Packets accepted but not dispatched (duplicates/out-of-window). |
|
|
519
|
+
| `packetsDroppedAfterFault` | `number` | Packets returned empty because the parser had halted. |
|
|
520
520
|
|
|
521
521
|
#### Faults and halting
|
|
522
522
|
|
|
@@ -527,10 +527,10 @@ parser **halts** — every later `parsePacket()` returns an empty `PacketData`
|
|
|
527
527
|
carrying the same fault and touches no state, because it would otherwise be
|
|
528
528
|
parsing against ghost and event state that no longer mirrors the server.
|
|
529
529
|
|
|
530
|
-
| Member
|
|
531
|
-
|
|
|
532
|
-
| `fault`
|
|
533
|
-
| `faulted`
|
|
530
|
+
| Member | Description |
|
|
531
|
+
| --------- | --------------------------------------- |
|
|
532
|
+
| `fault` | The first `ParseFault`, or `undefined`. |
|
|
533
|
+
| `faulted` | `true` once a fault has been recorded. |
|
|
534
534
|
|
|
535
535
|
Pass `haltOnFault: false` (to `new PacketParser`, `new DemoParser`, or
|
|
536
536
|
`createLiveParser`) to keep parsing regardless; each later packet still
|
|
@@ -565,7 +565,9 @@ parsing packets from a live Tribes 2 connection (e.g. via a network proxy).
|
|
|
565
565
|
```typescript
|
|
566
566
|
import { createLiveParser } from "t2-demo-parser";
|
|
567
567
|
|
|
568
|
-
const { registry, ghostTracker, packetParser } = createLiveParser(
|
|
568
|
+
const { registry, ghostTracker, packetParser } = createLiveParser({
|
|
569
|
+
protocolVersion: 51, // version negotiated by the connection handshake
|
|
570
|
+
});
|
|
569
571
|
// Feed raw packet data through packetParser...
|
|
570
572
|
```
|
|
571
573
|
|
|
@@ -584,6 +586,7 @@ with the exporter (the late-joiner catch-up scenario — see
|
|
|
584
586
|
|
|
585
587
|
```typescript
|
|
586
588
|
interface LiveParserSeed {
|
|
589
|
+
protocolVersion?: number | null; // negotiated wire version; null/omitted = unknown
|
|
587
590
|
dataBlocks?: Iterable<[number, ParsedData]>; // objectId → parsed datablock
|
|
588
591
|
ghosts?: Iterable<{ index: number; classId: number }>;
|
|
589
592
|
connectionProtocolState?: ConnectionProtocolState;
|
|
@@ -597,6 +600,19 @@ interface LiveParserSeed {
|
|
|
597
600
|
}
|
|
598
601
|
```
|
|
599
602
|
|
|
603
|
+
Pass the **negotiated connection version**, not the server's maximum version:
|
|
604
|
+
51 selects retail terrain payloads; 52 selects the QoL terrain extension.
|
|
605
|
+
Export it with `packetParser.getProtocolVersion()` when seeding another parser.
|
|
606
|
+
It is separate from `connectionProtocolState`, which holds packet sequence windows.
|
|
607
|
+
|
|
608
|
+
Recordings do not preserve this version: even QoL recordings use the
|
|
609
|
+
`0x330004` header and retail saved-ghost layout. With no known version, the
|
|
610
|
+
parser recognizes an eight-slot terrain material string using non-consuming
|
|
611
|
+
lookahead within the current packet. This fallback is necessarily heuristic;
|
|
612
|
+
it never learns a global format from one map. If the recording's wire version
|
|
613
|
+
is known externally, use `new DemoParser(bytes, { packetProtocolVersion: 52 })`.
|
|
614
|
+
Saved initial ghosts still use retail layout, including with that override.
|
|
615
|
+
|
|
600
616
|
### `passiveObserverProtocolState(firstPacketByte): ConnectionProtocolState`
|
|
601
617
|
|
|
602
618
|
Protocol state for a parser that passively observes the server→client
|
|
@@ -689,7 +705,11 @@ as the engine's `writeString`). `finish()` returns the packed `Uint8Array`.
|
|
|
689
705
|
```typescript
|
|
690
706
|
import { BitWriter, BitStream } from "t2-demo-parser";
|
|
691
707
|
|
|
692
|
-
const bytes = new BitWriter()
|
|
708
|
+
const bytes = new BitWriter()
|
|
709
|
+
.writeFlag(true)
|
|
710
|
+
.writeInt(5, 4)
|
|
711
|
+
.writeString("hi")
|
|
712
|
+
.finish();
|
|
693
713
|
const bs = new BitStream(bytes); // readFlag() → true, readInt(4) → 5, readString() → "hi"
|
|
694
714
|
```
|
|
695
715
|
|
|
@@ -699,12 +719,12 @@ const bs = new BitStream(bytes); // readFlag() → true, readInt(4) → 5, readS
|
|
|
699
719
|
to its deterministic classId — the same setup `DemoParser` and
|
|
700
720
|
`createLiveParser` use. Lookups go both ways:
|
|
701
721
|
|
|
702
|
-
| Method
|
|
703
|
-
|
|
|
704
|
-
| `getGhostParser(classId)` etc.
|
|
705
|
-
| `getGhostClassId(name)` etc.
|
|
706
|
-
| `getGhostCatalog()` etc.
|
|
707
|
-
| `getGhostBindings()` etc.
|
|
722
|
+
| Method | Returns |
|
|
723
|
+
| ------------------------------ | -------------------------------- |
|
|
724
|
+
| `getGhostParser(classId)` etc. | Parser entry for a bound classId |
|
|
725
|
+
| `getGhostClassId(name)` etc. | Bound classId for a class name |
|
|
726
|
+
| `getGhostCatalog()` etc. | `ReadonlyMap<name, entry>` |
|
|
727
|
+
| `getGhostBindings()` etc. | `Map<classId, name>` (debug) |
|
|
708
728
|
|
|
709
729
|
The `Event` and `DataBlock` variants of each method exist too.
|
|
710
730
|
|
package/dist/BitStream.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export declare class BitStream {
|
|
|
11
11
|
private error;
|
|
12
12
|
private stringBuffer;
|
|
13
13
|
constructor(data: Uint8Array, bitOffset?: number);
|
|
14
|
+
/** Independent lookahead, including string-prefix and error state. */
|
|
15
|
+
fork(): BitStream;
|
|
14
16
|
getCurPos(): number;
|
|
15
17
|
setCurPos(pos: number): void;
|
|
16
18
|
/** Byte position (rounded up), matching C++ getPosition() */
|
package/dist/BitStream.d.ts.map
CHANGED
|
@@ -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
|
@@ -17,6 +17,14 @@ export class BitStream {
|
|
|
17
17
|
this.maxReadBitNum = data.length << 3;
|
|
18
18
|
this.error = false;
|
|
19
19
|
}
|
|
20
|
+
/** Independent lookahead, including string-prefix and error state. */
|
|
21
|
+
fork() {
|
|
22
|
+
const copy = new BitStream(this.data, this.bitNum);
|
|
23
|
+
copy.maxReadBitNum = this.maxReadBitNum;
|
|
24
|
+
copy.error = this.error;
|
|
25
|
+
copy.stringBuffer = this.stringBuffer;
|
|
26
|
+
return copy;
|
|
27
|
+
}
|
|
20
28
|
getCurPos() {
|
|
21
29
|
return this.bitNum;
|
|
22
30
|
}
|
package/dist/BitStream.js.map
CHANGED
|
@@ -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 (!(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"]}
|
|
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 /** Independent lookahead, including string-prefix and error state. */\n fork(): BitStream {\n const copy = new BitStream(this.data, this.bitNum);\n copy.maxReadBitNum = this.maxReadBitNum;\n copy.error = this.error;\n copy.stringBuffer = this.stringBuffer;\n return copy;\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"]}
|
package/dist/ClassRegistry.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export type GhostPacketDataParser = (bs: BitStream, conn: ConnectionContext) =>
|
|
|
13
13
|
export type DataBlockParser = (bs: BitStream) => ParsedData;
|
|
14
14
|
/** Shared context passed to parsers from the connection state. */
|
|
15
15
|
export interface ConnectionContext {
|
|
16
|
+
/** Saved demo ghosts use the retail layout even on TribesNEXT clients. */
|
|
17
|
+
isDemoStartBlock?: boolean;
|
|
18
|
+
/** Negotiated wire protocol (51 retail, 52 QoL); absent/null for demos. */
|
|
19
|
+
protocolVersion?: number | null;
|
|
16
20
|
compressionPoint: {
|
|
17
21
|
x: number;
|
|
18
22
|
y: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClassRegistry.d.ts","sourceRoot":"","sources":["../src/ClassRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAIpD,MAAM,MAAM,WAAW,GAAG,
|
|
1
|
+
{"version":3,"file":"ClassRegistry.d.ts","sourceRoot":"","sources":["../src/ClassRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClassRegistry.js","sourceRoot":"","sources":["../src/ClassRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BitStream } from \"./BitStream.js\";\nimport type { EventData } from \"./eventDataTypes.js\";\n\n/**\n * Base type for all parsed data objects. Individual parsers return more\n * specific interfaces, but the registry stores them generically.\n */\nexport type ParsedData = { [key: string]: unknown };\n\n// --- Parser function signatures ---\n\nexport type EventParser = (\n bs: BitStream,\n conn: ConnectionContext\n) => EventData;\n\nexport type GhostUpdateParser = (\n bs: BitStream,\n isInitial: boolean,\n conn: ConnectionContext\n) => ParsedData;\n\nexport type GhostPacketDataParser = (\n bs: BitStream,\n conn: ConnectionContext\n) => ParsedData;\n\nexport type DataBlockParser = (\n bs: BitStream\n) => ParsedData;\n\n/** Shared context passed to parsers from the connection state. */\nexport interface ConnectionContext {\n compressionPoint: { x: number; y: number; z: number };\n ghostTracker: GhostTrackerInterface;\n getDataBlockParser?: (classId: number) => DataBlockParserEntry | undefined;\n getDataBlockData?: (objectId: number) => ParsedData | undefined;\n getGhostParser?: (classId: number) => GhostParserEntry | undefined;\n}\n\n/** Minimal interface for ghost tracker used by parsers. */\nexport interface GhostTrackerInterface {\n getGhost(index: number): GhostEntry | undefined;\n}\n\nexport interface GhostEntry {\n classId: number;\n className: string;\n}\n\nexport interface GhostParserEntry {\n name: string;\n unpackUpdate: GhostUpdateParser;\n readPacketData?: GhostPacketDataParser;\n}\n\nexport interface EventParserEntry {\n name: string;\n unpack: EventParser;\n}\n\nexport interface DataBlockParserEntry {\n name: string;\n unpackData: DataBlockParser;\n}\n\ninterface Catalog<T extends { name: string }> {\n byName: Map<string, T>;\n byClassId: Map<number, T>;\n classIdByName: Map<string, number>;\n}\n\nfunction newCatalog<T extends { name: string }>(): Catalog<T> {\n return { byName: new Map(), byClassId: new Map(), classIdByName: new Map() };\n}\n\n/**\n * Bind every cataloged parser whose name appears in `classNames` to\n * classId = classFirst + index. Names without a parser are reported.\n */\nfunction bindCatalog<T extends { name: string }>(\n catalog: Catalog<T>,\n classNames: readonly string[],\n classFirst: number,\n): { bound: number; missing: string[] } {\n let bound = 0;\n const missing: string[] = [];\n for (let i = 0; i < classNames.length; i++) {\n const name = classNames[i];\n const entry = catalog.byName.get(name);\n if (entry) {\n catalog.byClassId.set(classFirst + i, entry);\n catalog.classIdByName.set(name, classFirst + i);\n bound++;\n } else {\n missing.push(name);\n }\n }\n return { bound, missing };\n}\n\nfunction bindingsOf<T extends { name: string }>(\n catalog: Catalog<T>,\n): Map<number, string> {\n const bindings = new Map<number, string>();\n for (const [id, entry] of catalog.byClassId) {\n bindings.set(id, entry.name);\n }\n return bindings;\n}\n\n/**\n * Registry mapping classIds to parser functions.\n * ClassIds are assigned deterministically by alphabetical sort (C strcmp)\n * at engine link time. Parsers are cataloged by name and bound to classIds\n * via bindDeterministicGhosts/Events/DataBlocks.\n */\nexport class ClassRegistry {\n private events = newCatalog<EventParserEntry>();\n private ghosts = newCatalog<GhostParserEntry>();\n private dataBlocks = newCatalog<DataBlockParserEntry>();\n\n // --- Catalog registration (name → parser, no classId yet) ---\n //\n // Parsers return precisely typed objects (PlayerGhostData, ...), which\n // are stored behind the generic ParsedData shape. The generic signatures\n // let each parser keep its own return type — so a misspelled field is a\n // compile error inside the parser — while the registry erases it.\n\n catalogEvent<T extends EventData>(entry: {\n name: string;\n unpack: (bs: BitStream, conn: ConnectionContext) => T;\n }): void {\n this.events.byName.set(entry.name, entry);\n }\n\n catalogGhost<T extends object, P extends object = ParsedData>(entry: {\n name: string;\n unpackUpdate: (bs: BitStream, isInitial: boolean, conn: ConnectionContext) => T;\n readPacketData?: (bs: BitStream, conn: ConnectionContext) => P;\n }): void {\n this.ghosts.byName.set(entry.name, entry as unknown as GhostParserEntry);\n }\n\n catalogDataBlock<T extends object>(entry: {\n name: string;\n unpackData: (bs: BitStream) => T;\n }): void {\n this.dataBlocks.byName.set(\n entry.name,\n entry as unknown as DataBlockParserEntry,\n );\n }\n\n // --- Deterministic binding (classId = classFirst + index in the sorted\n // class name list) ---\n\n bindDeterministicDataBlocks(\n classNames: readonly string[],\n classFirst: number,\n ): { bound: number; missing: string[] } {\n return bindCatalog(this.dataBlocks, classNames, classFirst);\n }\n\n bindDeterministicEvents(\n classNames: readonly string[],\n classFirst: number,\n ): { bound: number; missing: string[] } {\n return bindCatalog(this.events, classNames, classFirst);\n }\n\n bindDeterministicGhosts(\n classNames: readonly string[],\n classFirst: number,\n ): { bound: number; missing: string[] } {\n return bindCatalog(this.ghosts, classNames, classFirst);\n }\n\n // --- Lookup by classId ---\n\n getEventParser(classId: number): EventParserEntry | undefined {\n return this.events.byClassId.get(classId);\n }\n\n getGhostParser(classId: number): GhostParserEntry | undefined {\n return this.ghosts.byClassId.get(classId);\n }\n\n getDataBlockParser(classId: number): DataBlockParserEntry | undefined {\n return this.dataBlocks.byClassId.get(classId);\n }\n\n // --- Lookup by class name (bound classId) ---\n\n getEventClassId(name: string): number | undefined {\n return this.events.classIdByName.get(name);\n }\n\n getGhostClassId(name: string): number | undefined {\n return this.ghosts.classIdByName.get(name);\n }\n\n getDataBlockClassId(name: string): number | undefined {\n return this.dataBlocks.classIdByName.get(name);\n }\n\n // --- Catalog access (name → parser, independent of binding) ---\n\n getEventCatalog(): ReadonlyMap<string, EventParserEntry> {\n return this.events.byName;\n }\n\n getGhostCatalog(): ReadonlyMap<string, GhostParserEntry> {\n return this.ghosts.byName;\n }\n\n getDataBlockCatalog(): ReadonlyMap<string, DataBlockParserEntry> {\n return this.dataBlocks.byName;\n }\n\n // --- Debug: classId → parser name ---\n\n getEventBindings(): Map<number, string> {\n return bindingsOf(this.events);\n }\n\n getGhostBindings(): Map<number, string> {\n return bindingsOf(this.ghosts);\n }\n\n getDataBlockBindings(): Map<number, string> {\n return bindingsOf(this.dataBlocks);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ClassRegistry.js","sourceRoot":"","sources":["../src/ClassRegistry.ts"],"names":[],"mappings":"AAuEA,SAAS,UAAU;IACjB,OAAO,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;AAC/E,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAClB,OAAmB,EACnB,UAA6B,EAC7B,UAAkB;IAElB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;YAC7C,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;YAChD,KAAK,EAAE,CAAC;QACV,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,UAAU,CACjB,OAAmB;IAEnB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QAC5C,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IAChB,MAAM,GAAG,UAAU,EAAoB,CAAC;IACxC,MAAM,GAAG,UAAU,EAAoB,CAAC;IACxC,UAAU,GAAG,UAAU,EAAwB,CAAC;IAExD,+DAA+D;IAC/D,EAAE;IACF,uEAAuE;IACvE,yEAAyE;IACzE,wEAAwE;IACxE,kEAAkE;IAElE,YAAY,CAAsB,KAGjC;QACC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED,YAAY,CAAkD,KAQ7D;QACC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAoC,CAAC,CAAC;IAC3E,CAAC;IAED,gBAAgB,CAAmB,KAGlC;QACC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CACxB,KAAK,CAAC,IAAI,EACV,KAAwC,CACzC,CAAC;IACJ,CAAC;IAED,wEAAwE;IACxE,2BAA2B;IAE3B,2BAA2B,CACzB,UAA6B,EAC7B,UAAkB;QAElB,OAAO,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC9D,CAAC;IAED,uBAAuB,CACrB,UAA6B,EAC7B,UAAkB;QAElB,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC1D,CAAC;IAED,uBAAuB,CACrB,UAA6B,EAC7B,UAAkB;QAElB,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC1D,CAAC;IAED,4BAA4B;IAE5B,cAAc,CAAC,OAAe;QAC5B,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,cAAc,CAAC,OAAe;QAC5B,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,kBAAkB,CAAC,OAAe;QAChC,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,+CAA+C;IAE/C,eAAe,CAAC,IAAY;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,eAAe,CAAC,IAAY;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,mBAAmB,CAAC,IAAY;QAC9B,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC;IAED,iEAAiE;IAEjE,eAAe;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAChC,CAAC;IAED,uCAAuC;IAEvC,gBAAgB;QACd,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,gBAAgB;QACd,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,oBAAoB;QAClB,OAAO,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;CACF","sourcesContent":["import type { BitStream } from \"./BitStream.js\";\nimport type { EventData } from \"./eventDataTypes.js\";\n\n/**\n * Base type for all parsed data objects. Individual parsers return more\n * specific interfaces, but the registry stores them generically.\n */\nexport type ParsedData = { [key: string]: unknown };\n\n// --- Parser function signatures ---\n\nexport type EventParser = (bs: BitStream, conn: ConnectionContext) => EventData;\n\nexport type GhostUpdateParser = (\n bs: BitStream,\n isInitial: boolean,\n conn: ConnectionContext,\n) => ParsedData;\n\nexport type GhostPacketDataParser = (\n bs: BitStream,\n conn: ConnectionContext,\n) => ParsedData;\n\nexport type DataBlockParser = (bs: BitStream) => ParsedData;\n\n/** Shared context passed to parsers from the connection state. */\nexport interface ConnectionContext {\n /** Saved demo ghosts use the retail layout even on TribesNEXT clients. */\n isDemoStartBlock?: boolean;\n /** Negotiated wire protocol (51 retail, 52 QoL); absent/null for demos. */\n protocolVersion?: number | null;\n compressionPoint: { x: number; y: number; z: number };\n ghostTracker: GhostTrackerInterface;\n getDataBlockParser?: (classId: number) => DataBlockParserEntry | undefined;\n getDataBlockData?: (objectId: number) => ParsedData | undefined;\n getGhostParser?: (classId: number) => GhostParserEntry | undefined;\n}\n\n/** Minimal interface for ghost tracker used by parsers. */\nexport interface GhostTrackerInterface {\n getGhost(index: number): GhostEntry | undefined;\n}\n\nexport interface GhostEntry {\n classId: number;\n className: string;\n}\n\nexport interface GhostParserEntry {\n name: string;\n unpackUpdate: GhostUpdateParser;\n readPacketData?: GhostPacketDataParser;\n}\n\nexport interface EventParserEntry {\n name: string;\n unpack: EventParser;\n}\n\nexport interface DataBlockParserEntry {\n name: string;\n unpackData: DataBlockParser;\n}\n\ninterface Catalog<T extends { name: string }> {\n byName: Map<string, T>;\n byClassId: Map<number, T>;\n classIdByName: Map<string, number>;\n}\n\nfunction newCatalog<T extends { name: string }>(): Catalog<T> {\n return { byName: new Map(), byClassId: new Map(), classIdByName: new Map() };\n}\n\n/**\n * Bind every cataloged parser whose name appears in `classNames` to\n * classId = classFirst + index. Names without a parser are reported.\n */\nfunction bindCatalog<T extends { name: string }>(\n catalog: Catalog<T>,\n classNames: readonly string[],\n classFirst: number,\n): { bound: number; missing: string[] } {\n let bound = 0;\n const missing: string[] = [];\n for (let i = 0; i < classNames.length; i++) {\n const name = classNames[i];\n const entry = catalog.byName.get(name);\n if (entry) {\n catalog.byClassId.set(classFirst + i, entry);\n catalog.classIdByName.set(name, classFirst + i);\n bound++;\n } else {\n missing.push(name);\n }\n }\n return { bound, missing };\n}\n\nfunction bindingsOf<T extends { name: string }>(\n catalog: Catalog<T>,\n): Map<number, string> {\n const bindings = new Map<number, string>();\n for (const [id, entry] of catalog.byClassId) {\n bindings.set(id, entry.name);\n }\n return bindings;\n}\n\n/**\n * Registry mapping classIds to parser functions.\n * ClassIds are assigned deterministically by alphabetical sort (C strcmp)\n * at engine link time. Parsers are cataloged by name and bound to classIds\n * via bindDeterministicGhosts/Events/DataBlocks.\n */\nexport class ClassRegistry {\n private events = newCatalog<EventParserEntry>();\n private ghosts = newCatalog<GhostParserEntry>();\n private dataBlocks = newCatalog<DataBlockParserEntry>();\n\n // --- Catalog registration (name → parser, no classId yet) ---\n //\n // Parsers return precisely typed objects (PlayerGhostData, ...), which\n // are stored behind the generic ParsedData shape. The generic signatures\n // let each parser keep its own return type — so a misspelled field is a\n // compile error inside the parser — while the registry erases it.\n\n catalogEvent<T extends EventData>(entry: {\n name: string;\n unpack: (bs: BitStream, conn: ConnectionContext) => T;\n }): void {\n this.events.byName.set(entry.name, entry);\n }\n\n catalogGhost<T extends object, P extends object = ParsedData>(entry: {\n name: string;\n unpackUpdate: (\n bs: BitStream,\n isInitial: boolean,\n conn: ConnectionContext,\n ) => T;\n readPacketData?: (bs: BitStream, conn: ConnectionContext) => P;\n }): void {\n this.ghosts.byName.set(entry.name, entry as unknown as GhostParserEntry);\n }\n\n catalogDataBlock<T extends object>(entry: {\n name: string;\n unpackData: (bs: BitStream) => T;\n }): void {\n this.dataBlocks.byName.set(\n entry.name,\n entry as unknown as DataBlockParserEntry,\n );\n }\n\n // --- Deterministic binding (classId = classFirst + index in the sorted\n // class name list) ---\n\n bindDeterministicDataBlocks(\n classNames: readonly string[],\n classFirst: number,\n ): { bound: number; missing: string[] } {\n return bindCatalog(this.dataBlocks, classNames, classFirst);\n }\n\n bindDeterministicEvents(\n classNames: readonly string[],\n classFirst: number,\n ): { bound: number; missing: string[] } {\n return bindCatalog(this.events, classNames, classFirst);\n }\n\n bindDeterministicGhosts(\n classNames: readonly string[],\n classFirst: number,\n ): { bound: number; missing: string[] } {\n return bindCatalog(this.ghosts, classNames, classFirst);\n }\n\n // --- Lookup by classId ---\n\n getEventParser(classId: number): EventParserEntry | undefined {\n return this.events.byClassId.get(classId);\n }\n\n getGhostParser(classId: number): GhostParserEntry | undefined {\n return this.ghosts.byClassId.get(classId);\n }\n\n getDataBlockParser(classId: number): DataBlockParserEntry | undefined {\n return this.dataBlocks.byClassId.get(classId);\n }\n\n // --- Lookup by class name (bound classId) ---\n\n getEventClassId(name: string): number | undefined {\n return this.events.classIdByName.get(name);\n }\n\n getGhostClassId(name: string): number | undefined {\n return this.ghosts.classIdByName.get(name);\n }\n\n getDataBlockClassId(name: string): number | undefined {\n return this.dataBlocks.classIdByName.get(name);\n }\n\n // --- Catalog access (name → parser, independent of binding) ---\n\n getEventCatalog(): ReadonlyMap<string, EventParserEntry> {\n return this.events.byName;\n }\n\n getGhostCatalog(): ReadonlyMap<string, GhostParserEntry> {\n return this.ghosts.byName;\n }\n\n getDataBlockCatalog(): ReadonlyMap<string, DataBlockParserEntry> {\n return this.dataBlocks.byName;\n }\n\n // --- Debug: classId → parser name ---\n\n getEventBindings(): Map<number, string> {\n return bindingsOf(this.events);\n }\n\n getGhostBindings(): Map<number, string> {\n return bindingsOf(this.ghosts);\n }\n\n getDataBlockBindings(): Map<number, string> {\n return bindingsOf(this.dataBlocks);\n }\n}\n"]}
|
package/dist/DemoParser.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export declare class DemoParser {
|
|
|
31
31
|
private _decompressedLength;
|
|
32
32
|
private _scanOffset;
|
|
33
33
|
private _bufferedMoveTicks;
|
|
34
|
+
private readonly _packetProtocolVersion;
|
|
34
35
|
private readonly _ignoreProtocolVersion;
|
|
35
36
|
private readonly _haltOnFault;
|
|
36
37
|
constructor(buffer: Uint8Array, options?: {
|
|
@@ -42,6 +43,9 @@ export declare class DemoParser {
|
|
|
42
43
|
* formats are not guaranteed to match, so expect faults.
|
|
43
44
|
*/
|
|
44
45
|
ignoreProtocolVersion?: boolean;
|
|
46
|
+
/** Override the negotiated wire version, which .rec files do not save.
|
|
47
|
+
* Null/omitted detects terrain extensions independently per payload. */
|
|
48
|
+
packetProtocolVersion?: number | null;
|
|
45
49
|
/** Passed to PacketParser; see its `haltOnFault` option. */
|
|
46
50
|
haltOnFault?: boolean;
|
|
47
51
|
});
|
|
@@ -129,6 +133,7 @@ export declare class DemoParser {
|
|
|
129
133
|
ghosts: ReadonlyMap<number, import("./ClassRegistry.js").GhostEntry>;
|
|
130
134
|
packetState: {
|
|
131
135
|
dataBlockDataMap: Map<number, import("./ClassRegistry.js").ParsedData> | undefined;
|
|
136
|
+
protocolVersion: number | null;
|
|
132
137
|
compressionPoint: {
|
|
133
138
|
x: number;
|
|
134
139
|
y: number;
|
package/dist/DemoParser.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DemoParser.d.ts","sourceRoot":"","sources":["../src/DemoParser.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAoB,MAAM,oBAAoB,CAAC;AAE1E,OAAO,EAAE,YAAY,EAAY,MAAM,mBAAmB,CAAC;AAqB3D,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,gBAAgB,EAShB,YAAY,EACZ,UAAU,EACX,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"DemoParser.d.ts","sourceRoot":"","sources":["../src/DemoParser.ts"],"names":[],"mappings":"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"}
|
package/dist/DemoParser.js
CHANGED
|
@@ -6,12 +6,6 @@ import { createDefaultRegistry } from "./defaultRegistry.js";
|
|
|
6
6
|
import { GhostTracker, readMove } from "./GhostManager.js";
|
|
7
7
|
import { BlockTypePacket, BlockTypeSendPacket, BlockTypeMove, BlockTypeInfo, DemoIdentString, DemoProtocolVersion, MaxTriggerKeys, NetEventClassBitSize, NetEventClassFirst, NetObjectClassBitSize, NetObjectClassFirst, GhostIdBitSize, DataBlockClassFirst, DataBlockClassNames, SimDBEventObjectIdBits, SimDBEventClassIdBits, SimDBEventIndexBits, SimDBEventTotalBits, } from "./types.js";
|
|
8
8
|
const debug = createDebug("t2-demo-parser");
|
|
9
|
-
/**
|
|
10
|
-
* Sequence numbers assigned to ordered events carried in the demo start
|
|
11
|
-
* block: past every 32-bit sequence, so they stay queued without ever
|
|
12
|
-
* matching `nextRecvEventSeq` (see setupPacketParser).
|
|
13
|
-
*/
|
|
14
|
-
const START_BLOCK_EVENT_SEQ_BASE = 0x1_0000_0000;
|
|
15
9
|
const debugInitial = createDebug("t2-demo-parser:initial");
|
|
16
10
|
const debugBlocks = createDebug("t2-demo-parser:blocks");
|
|
17
11
|
/**
|
|
@@ -60,6 +54,7 @@ export class DemoParser {
|
|
|
60
54
|
// Buffered-time scan state (see bufferedMoveTicks).
|
|
61
55
|
_scanOffset = 0;
|
|
62
56
|
_bufferedMoveTicks = 0;
|
|
57
|
+
_packetProtocolVersion;
|
|
63
58
|
_ignoreProtocolVersion;
|
|
64
59
|
_haltOnFault;
|
|
65
60
|
constructor(buffer, options) {
|
|
@@ -69,11 +64,15 @@ export class DemoParser {
|
|
|
69
64
|
this._incremental = options?.incremental === true;
|
|
70
65
|
this._ignoreProtocolVersion = options?.ignoreProtocolVersion === true;
|
|
71
66
|
this._haltOnFault = options?.haltOnFault;
|
|
67
|
+
this._packetProtocolVersion = options?.packetProtocolVersion ?? null;
|
|
72
68
|
// Parser catalogs bound to their deterministic classIds (derived from
|
|
73
69
|
// binary analysis of the Tribes 2 executable).
|
|
74
70
|
this.registry = createDefaultRegistry();
|
|
75
71
|
this.ghostTracker = new GhostTracker();
|
|
76
|
-
this.packetParser = new PacketParser(this.registry, this.ghostTracker
|
|
72
|
+
this.packetParser = new PacketParser(this.registry, this.ghostTracker, {
|
|
73
|
+
protocolVersion: this._packetProtocolVersion,
|
|
74
|
+
haltOnFault: this._haltOnFault,
|
|
75
|
+
});
|
|
77
76
|
}
|
|
78
77
|
getRegistry() {
|
|
79
78
|
return this.registry;
|
|
@@ -476,21 +475,19 @@ export class DemoParser {
|
|
|
476
475
|
gt.createGhost(ghost.index, ghost.classId, parserEntry?.name ?? `unknown_${ghost.classId}`);
|
|
477
476
|
}
|
|
478
477
|
const pp = new PacketParser(this.registry, gt, {
|
|
478
|
+
protocolVersion: this._packetProtocolVersion,
|
|
479
479
|
dataBlockDataMap,
|
|
480
480
|
connectionProtocolState: initialBlock.connectionState,
|
|
481
481
|
nextRecvEventSeq: initialBlock.nextRecvEventSeq,
|
|
482
482
|
compressionPoint: initialBlock.initialCompressionPoint,
|
|
483
|
-
//
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
.filter((event) => !event.failed)
|
|
492
|
-
.map((event, i) => ({
|
|
493
|
-
absoluteSequenceNumber: START_BLOCK_EVENT_SEQ_BASE + i,
|
|
483
|
+
// Recording can start inside an ordered event's process callback:
|
|
484
|
+
// nextRecvEventSeq has advanced, but the remaining events in that
|
|
485
|
+
// packet are still in the wait queue. The demo saves their payloads
|
|
486
|
+
// in order, without sequence numbers. Restore that contiguous prefix
|
|
487
|
+
// at the saved receive sequence; parking it beyond the sequence range
|
|
488
|
+
// leaves a permanent hole and misinterprets later 7-bit wraps.
|
|
489
|
+
pendingGuaranteedEvents: initialBlock.initialEvents.map((event, i) => ({
|
|
490
|
+
absoluteSequenceNumber: (initialBlock.nextRecvEventSeq + i) >>> 0,
|
|
494
491
|
event,
|
|
495
492
|
})),
|
|
496
493
|
haltOnFault: this._haltOnFault,
|
|
@@ -934,6 +931,7 @@ export class DemoParser {
|
|
|
934
931
|
const conn = {
|
|
935
932
|
compressionPoint: { x: 0, y: 0, z: 0 },
|
|
936
933
|
ghostTracker: this.ghostTracker,
|
|
934
|
+
isDemoStartBlock: true,
|
|
937
935
|
getDataBlockParser: (cid) => this.registry.getDataBlockParser(cid),
|
|
938
936
|
};
|
|
939
937
|
parsedData = parserEntry.unpack(bs, conn);
|
|
@@ -1014,6 +1012,7 @@ export class DemoParser {
|
|
|
1014
1012
|
entry.unpackUpdate(bs, true, {
|
|
1015
1013
|
compressionPoint: { x: 0, y: 0, z: 0 },
|
|
1016
1014
|
ghostTracker: this.ghostTracker,
|
|
1015
|
+
isDemoStartBlock: true,
|
|
1017
1016
|
getDataBlockData: (objectId) => dataBlockDataMap.get(objectId),
|
|
1018
1017
|
getDataBlockParser: (cid) => this.registry.getDataBlockParser(cid),
|
|
1019
1018
|
}) ?? {};
|