t2-demo-parser 2.2.0 → 3.0.1
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 +170 -7
- package/dist/BitStream.d.ts +14 -3
- package/dist/BitStream.d.ts.map +1 -1
- package/dist/BitStream.js +28 -6
- package/dist/BitStream.js.map +1 -1
- package/dist/BitWriter.d.ts +29 -0
- package/dist/BitWriter.d.ts.map +1 -0
- package/dist/BitWriter.js +76 -0
- package/dist/BitWriter.js.map +1 -0
- package/dist/ClassRegistry.d.ts +23 -28
- package/dist/ClassRegistry.d.ts.map +1 -1
- package/dist/ClassRegistry.js +75 -84
- package/dist/ClassRegistry.js.map +1 -1
- package/dist/DataBlockParsers.d.ts.map +1 -1
- package/dist/DataBlockParsers.js +60 -85
- package/dist/DataBlockParsers.js.map +1 -1
- package/dist/DemoParser.d.ts +23 -22
- package/dist/DemoParser.d.ts.map +1 -1
- package/dist/DemoParser.js +218 -266
- package/dist/DemoParser.js.map +1 -1
- package/dist/EventParsers.d.ts.map +1 -1
- package/dist/EventParsers.js +87 -58
- package/dist/EventParsers.js.map +1 -1
- package/dist/GhostManager.d.ts +7 -1
- package/dist/GhostManager.d.ts.map +1 -1
- package/dist/GhostManager.js +231 -146
- package/dist/GhostManager.js.map +1 -1
- package/dist/HuffmanProcessor.d.ts +15 -0
- package/dist/HuffmanProcessor.d.ts.map +1 -1
- package/dist/HuffmanProcessor.js +45 -0
- package/dist/HuffmanProcessor.js.map +1 -1
- package/dist/LiveParser.d.ts +20 -1
- package/dist/LiveParser.d.ts.map +1 -1
- package/dist/LiveParser.js +31 -12
- package/dist/LiveParser.js.map +1 -1
- package/dist/PacketParser.d.ts +22 -2
- package/dist/PacketParser.d.ts.map +1 -1
- package/dist/PacketParser.js +111 -48
- package/dist/PacketParser.js.map +1 -1
- package/dist/Timeline.d.ts +5 -2
- package/dist/Timeline.d.ts.map +1 -1
- package/dist/Timeline.js +25 -12
- package/dist/Timeline.js.map +1 -1
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -1
- package/dist/dataBlockDataTypes.d.ts +118 -117
- package/dist/dataBlockDataTypes.d.ts.map +1 -1
- package/dist/dataBlockDataTypes.js.map +1 -1
- package/dist/defaultRegistry.d.ts +9 -0
- package/dist/defaultRegistry.d.ts.map +1 -0
- package/dist/defaultRegistry.js +43 -0
- package/dist/defaultRegistry.js.map +1 -0
- package/dist/eventDataTypes.d.ts +74 -72
- package/dist/eventDataTypes.d.ts.map +1 -1
- package/dist/eventDataTypes.js.map +1 -1
- package/dist/ghostDataTypes.d.ts +125 -131
- package/dist/ghostDataTypes.d.ts.map +1 -1
- package/dist/ghostDataTypes.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +51 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -1
- package/package.json +4 -1
- package/dist/BitStream.test.d.ts +0 -2
- package/dist/BitStream.test.d.ts.map +0 -1
- package/dist/BitStream.test.js +0 -419
- package/dist/BitStream.test.js.map +0 -1
- package/dist/ClassRegistry.test.d.ts +0 -2
- package/dist/ClassRegistry.test.d.ts.map +0 -1
- package/dist/ClassRegistry.test.js +0 -83
- package/dist/ClassRegistry.test.js.map +0 -1
- package/dist/DataBlockParsers.test.d.ts +0 -2
- package/dist/DataBlockParsers.test.d.ts.map +0 -1
- package/dist/DataBlockParsers.test.js +0 -294
- package/dist/DataBlockParsers.test.js.map +0 -1
- package/dist/DemoParser.test.d.ts +0 -2
- package/dist/DemoParser.test.d.ts.map +0 -1
- package/dist/DemoParser.test.js +0 -472
- package/dist/DemoParser.test.js.map +0 -1
- package/dist/GhostStateAccumulator.test.d.ts +0 -2
- package/dist/GhostStateAccumulator.test.d.ts.map +0 -1
- package/dist/GhostStateAccumulator.test.js +0 -201
- package/dist/GhostStateAccumulator.test.js.map +0 -1
- package/dist/GhostTracker.test.d.ts +0 -2
- package/dist/GhostTracker.test.d.ts.map +0 -1
- package/dist/GhostTracker.test.js +0 -64
- package/dist/GhostTracker.test.js.map +0 -1
- package/dist/IncrementalParser.test.d.ts +0 -2
- package/dist/IncrementalParser.test.d.ts.map +0 -1
- package/dist/IncrementalParser.test.js +0 -226
- package/dist/IncrementalParser.test.js.map +0 -1
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { BitStream } from "./BitStream.js";
|
|
2
|
+
import type { BitWriter } from "./BitWriter.js";
|
|
3
|
+
/** Strings longer than this cannot be encoded (8-bit length prefix). */
|
|
4
|
+
export declare const MaxHuffStringLength = 255;
|
|
5
|
+
/**
|
|
6
|
+
* Port of the engine's HuffmanProcessor (bitStream.cc). The tree is built
|
|
7
|
+
* once from the fixed frequency table, so decoding depends on nothing but
|
|
8
|
+
* the wire bits.
|
|
9
|
+
*/
|
|
2
10
|
export declare class HuffmanProcessor {
|
|
3
11
|
private nodes;
|
|
4
12
|
private leaves;
|
|
@@ -7,6 +15,13 @@ export declare class HuffmanProcessor {
|
|
|
7
15
|
private determineIndex;
|
|
8
16
|
private generateCodes;
|
|
9
17
|
readHuffBuffer(stream: BitStream): string;
|
|
18
|
+
/**
|
|
19
|
+
* Encode a string the way the engine's writeHuffBuffer does: a flag
|
|
20
|
+
* selecting compressed vs. raw bytes (compressed only when it is
|
|
21
|
+
* shorter), an 8-bit length, then either Huffman codes or raw bytes.
|
|
22
|
+
* Characters are written as Latin-1 bytes (code units above 255 throw).
|
|
23
|
+
*/
|
|
24
|
+
writeHuffBuffer(writer: BitWriter, value: string): void;
|
|
10
25
|
}
|
|
11
26
|
export declare const huffProcessor: HuffmanProcessor;
|
|
12
27
|
//# sourceMappingURL=HuffmanProcessor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HuffmanProcessor.d.ts","sourceRoot":"","sources":["../src/HuffmanProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAwDhD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,WAAW,CAAS;IAE5B,WAAW,IAAI,IAAI;IA0EnB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,aAAa;IAerB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"HuffmanProcessor.d.ts","sourceRoot":"","sources":["../src/HuffmanProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAwDhD,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,WAAW,CAAS;IAE5B,WAAW,IAAI,IAAI;IA0EnB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,aAAa;IAerB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM;IAiCzC;;;;;OAKG;IACH,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CAgCxD;AAGD,eAAO,MAAM,aAAa,kBAAyB,CAAC"}
|
package/dist/HuffmanProcessor.js
CHANGED
|
@@ -30,6 +30,13 @@ function wrapGetPop(w) {
|
|
|
30
30
|
return w.node.pop;
|
|
31
31
|
return w.leaf.pop;
|
|
32
32
|
}
|
|
33
|
+
/** Strings longer than this cannot be encoded (8-bit length prefix). */
|
|
34
|
+
export const MaxHuffStringLength = 255;
|
|
35
|
+
/**
|
|
36
|
+
* Port of the engine's HuffmanProcessor (bitStream.cc). The tree is built
|
|
37
|
+
* once from the fixed frequency table, so decoding depends on nothing but
|
|
38
|
+
* the wire bits.
|
|
39
|
+
*/
|
|
33
40
|
export class HuffmanProcessor {
|
|
34
41
|
nodes = [];
|
|
35
42
|
leaves = [];
|
|
@@ -157,6 +164,44 @@ export class HuffmanProcessor {
|
|
|
157
164
|
return String.fromCharCode(...bytes);
|
|
158
165
|
}
|
|
159
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Encode a string the way the engine's writeHuffBuffer does: a flag
|
|
169
|
+
* selecting compressed vs. raw bytes (compressed only when it is
|
|
170
|
+
* shorter), an 8-bit length, then either Huffman codes or raw bytes.
|
|
171
|
+
* Characters are written as Latin-1 bytes (code units above 255 throw).
|
|
172
|
+
*/
|
|
173
|
+
writeHuffBuffer(writer, value) {
|
|
174
|
+
if (!this.tablesBuilt) {
|
|
175
|
+
this.buildTables();
|
|
176
|
+
}
|
|
177
|
+
if (value.length > MaxHuffStringLength) {
|
|
178
|
+
throw new RangeError(`string too long for Huffman buffer: ${value.length} > ${MaxHuffStringLength}`);
|
|
179
|
+
}
|
|
180
|
+
const codes = new Array(value.length);
|
|
181
|
+
let numBits = 0;
|
|
182
|
+
for (let i = 0; i < value.length; i++) {
|
|
183
|
+
const c = value.charCodeAt(i);
|
|
184
|
+
if (c > 255) {
|
|
185
|
+
throw new RangeError(`non-Latin-1 character at index ${i}`);
|
|
186
|
+
}
|
|
187
|
+
codes[i] = c;
|
|
188
|
+
numBits += this.leaves[c].numBits;
|
|
189
|
+
}
|
|
190
|
+
if (numBits >= value.length * 8) {
|
|
191
|
+
writer.writeFlag(false);
|
|
192
|
+
writer.writeInt(value.length, 8);
|
|
193
|
+
for (const c of codes)
|
|
194
|
+
writer.writeInt(c, 8);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
writer.writeFlag(true);
|
|
198
|
+
writer.writeInt(value.length, 8);
|
|
199
|
+
for (const c of codes) {
|
|
200
|
+
const leaf = this.leaves[c];
|
|
201
|
+
writer.writeInt(leaf.code, leaf.numBits);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
160
205
|
}
|
|
161
206
|
// Singleton instance matching the C++ g_huffProcessor
|
|
162
207
|
export const huffProcessor = new HuffmanProcessor();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HuffmanProcessor.js","sourceRoot":"","sources":["../src/HuffmanProcessor.ts"],"names":[],"mappings":"AAEA,yEAAyE;AACzE,mEAAmE;AACnE,MAAM,cAAc,GAAa;IAC/B,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ;IACxD,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ;IACnE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ;IAC5E,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ;IAC/E,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ;IACxE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS;IAC7F,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,UAAU;IAChF,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,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","sourcesContent":["import type { BitStream } from \"./BitStream.js\";\n\n// Hardcoded character frequency table from the V12 engine (bitStream.cc)\n// These are used to build the Huffman tree for string compression.\nconst CSM_CHAR_FREQS: number[] = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 329, 21, 0, 0, 0, 0, 0, // 0-15\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31\n 2809, 68, 0, 27, 0, 58, 3, 62, 4, 7, 0, 0, 15, 65, 554, 3, // 32-47\n 394, 404, 189, 117, 30, 51, 27, 15, 34, 32, 80, 1, 142, 3, 142, 39, // 48-63\n 0, 144, 125, 44, 122, 275, 70, 135, 61, 127, 8, 12, 113, 246, 122, 36, // 64-79\n 185, 1, 149, 309, 335, 12, 11, 14, 54, 151, 0, 0, 2, 0, 0, 211, // 80-95\n 0, 2090, 344, 736, 993, 2872, 701, 605, 646, 1552, 328, 305, 1240, 735, 1533, 1713, // 96-111\n 562, 3, 1775, 1149, 1469, 979, 407, 553, 59, 279, 31, 0, 0, 0, 68, 0, // 112-127\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128-143\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144-159\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160-175\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176-191\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192-207\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208-223\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224-239\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240-255\n];\n\nconst PROB_BOOST = 1;\n\nfunction isAlphaNumeric(c: number): boolean {\n return (\n (c >= 48 && c <= 57) || // 0-9\n (c >= 65 && c <= 90) || // A-Z\n (c >= 97 && c <= 122) // a-z\n );\n}\n\ninterface HuffNode {\n pop: number;\n index0: number;\n index1: number;\n}\n\ninterface HuffLeaf {\n pop: number;\n symbol: number;\n numBits: number;\n code: number;\n}\n\ninterface HuffWrap {\n node: HuffNode | null;\n leaf: HuffLeaf | null;\n}\n\nfunction wrapGetPop(w: HuffWrap): number {\n if (w.node) return w.node.pop;\n return w.leaf!.pop;\n}\n\nexport class HuffmanProcessor {\n private nodes: HuffNode[] = [];\n private leaves: HuffLeaf[] = [];\n private tablesBuilt = false;\n\n buildTables(): void {\n if (this.tablesBuilt) return;\n this.tablesBuilt = true;\n\n // Initialize leaves from frequency table\n this.leaves = [];\n for (let i = 0; i < 256; i++) {\n this.leaves.push({\n pop:\n CSM_CHAR_FREQS[i] +\n (isAlphaNumeric(i) ? PROB_BOOST : 0) +\n PROB_BOOST,\n symbol: i,\n numBits: 0,\n code: 0,\n });\n }\n\n // Initialize nodes array with one placeholder at index 0\n this.nodes = [{ pop: 0, index0: 0, index1: 0 }];\n\n // Build wraps array\n let currWraps = 256;\n const wraps: HuffWrap[] = [];\n for (let i = 0; i < 256; i++) {\n wraps.push({ node: null, leaf: this.leaves[i] });\n }\n\n // Build the Huffman tree by repeatedly combining the two lowest-population wraps\n while (currWraps !== 1) {\n let min1 = 0xfffffffe;\n let min2 = 0xffffffff;\n let index1 = -1;\n let index2 = -1;\n\n for (let i = 0; i < currWraps; i++) {\n const pop = wrapGetPop(wraps[i]);\n if (pop < min1) {\n min2 = min1;\n index2 = index1;\n min1 = pop;\n index1 = i;\n } else if (pop < min2) {\n min2 = pop;\n index2 = i;\n }\n }\n\n // Create a new node combining the two smallest\n const newNode: HuffNode = {\n pop: wrapGetPop(wraps[index1]) + wrapGetPop(wraps[index2]),\n index0: this.determineIndex(wraps[index1]),\n index1: this.determineIndex(wraps[index2]),\n };\n this.nodes.push(newNode);\n\n // Replace the lower-indexed wrap with the new node, remove the higher-indexed one\n const mergeIndex = index1 < index2 ? index1 : index2;\n const nukeIndex = index1 > index2 ? index1 : index2;\n wraps[mergeIndex] = { node: newNode, leaf: null };\n\n if (nukeIndex !== currWraps - 1) {\n wraps[nukeIndex] = wraps[currWraps - 1];\n }\n currWraps--;\n }\n\n // The root node should be at nodes[0]\n this.nodes[0] = wraps[0].node!;\n\n // Generate Huffman codes by walking the tree\n this.generateCodes(0, 0, 0);\n }\n\n private determineIndex(wrap: HuffWrap): number {\n if (wrap.leaf !== null) {\n // Leaf index is encoded as -(leafArrayIndex + 1)\n const leafIdx = this.leaves.indexOf(wrap.leaf);\n return -(leafIdx + 1);\n } else {\n return this.nodes.indexOf(wrap.node!);\n }\n }\n\n private generateCodes(code: number, nodeIndex: number, depth: number): void {\n if (nodeIndex < 0) {\n // Leaf node\n const leaf = this.leaves[-(nodeIndex + 1)];\n leaf.code = code;\n leaf.numBits = depth;\n } else {\n const node = this.nodes[nodeIndex];\n // Go left (0 bit)\n this.generateCodes(code, node.index0, depth + 1);\n // Go right (1 bit)\n this.generateCodes(code | (1 << depth), node.index1, depth + 1);\n }\n }\n\n readHuffBuffer(stream: BitStream): string {\n if (!this.tablesBuilt) {\n this.buildTables();\n }\n\n if (stream.readFlag()) {\n // Huffman-compressed string\n const len = stream.readInt(8);\n const chars: number[] = [];\n for (let i = 0; i < len; i++) {\n let index = 0;\n while (true) {\n if (index >= 0) {\n if (stream.readFlag()) {\n index = this.nodes[index].index1;\n } else {\n index = this.nodes[index].index0;\n }\n } else {\n chars.push(this.leaves[-(index + 1)].symbol);\n break;\n }\n }\n }\n return String.fromCharCode(...chars);\n } else {\n // Uncompressed string\n const len = stream.readInt(8);\n const bytes = stream.readBytes(len);\n return String.fromCharCode(...bytes);\n }\n }\n}\n\n// Singleton instance matching the C++ g_huffProcessor\nexport const huffProcessor = new HuffmanProcessor();\n"]}
|
|
1
|
+
{"version":3,"file":"HuffmanProcessor.js","sourceRoot":"","sources":["../src/HuffmanProcessor.ts"],"names":[],"mappings":"AAGA,yEAAyE;AACzE,mEAAmE;AACnE,MAAM,cAAc,GAAa;IAC/B,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ;IACxD,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ;IACnE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ;IAC5E,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ;IAC/E,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ;IACxE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS;IAC7F,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,UAAU;IAChF,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU;IAC1D,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,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","sourcesContent":["import type { BitStream } from \"./BitStream.js\";\nimport type { BitWriter } from \"./BitWriter.js\";\n\n// Hardcoded character frequency table from the V12 engine (bitStream.cc)\n// These are used to build the Huffman tree for string compression.\nconst CSM_CHAR_FREQS: number[] = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 329, 21, 0, 0, 0, 0, 0, // 0-15\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31\n 2809, 68, 0, 27, 0, 58, 3, 62, 4, 7, 0, 0, 15, 65, 554, 3, // 32-47\n 394, 404, 189, 117, 30, 51, 27, 15, 34, 32, 80, 1, 142, 3, 142, 39, // 48-63\n 0, 144, 125, 44, 122, 275, 70, 135, 61, 127, 8, 12, 113, 246, 122, 36, // 64-79\n 185, 1, 149, 309, 335, 12, 11, 14, 54, 151, 0, 0, 2, 0, 0, 211, // 80-95\n 0, 2090, 344, 736, 993, 2872, 701, 605, 646, 1552, 328, 305, 1240, 735, 1533, 1713, // 96-111\n 562, 3, 1775, 1149, 1469, 979, 407, 553, 59, 279, 31, 0, 0, 0, 68, 0, // 112-127\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128-143\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144-159\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160-175\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176-191\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192-207\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208-223\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224-239\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240-255\n];\n\nconst PROB_BOOST = 1;\n\nfunction isAlphaNumeric(c: number): boolean {\n return (\n (c >= 48 && c <= 57) || // 0-9\n (c >= 65 && c <= 90) || // A-Z\n (c >= 97 && c <= 122) // a-z\n );\n}\n\ninterface HuffNode {\n pop: number;\n index0: number;\n index1: number;\n}\n\ninterface HuffLeaf {\n pop: number;\n symbol: number;\n numBits: number;\n code: number;\n}\n\ninterface HuffWrap {\n node: HuffNode | null;\n leaf: HuffLeaf | null;\n}\n\nfunction wrapGetPop(w: HuffWrap): number {\n if (w.node) return w.node.pop;\n return w.leaf!.pop;\n}\n\n/** Strings longer than this cannot be encoded (8-bit length prefix). */\nexport const MaxHuffStringLength = 255;\n\n/**\n * Port of the engine's HuffmanProcessor (bitStream.cc). The tree is built\n * once from the fixed frequency table, so decoding depends on nothing but\n * the wire bits.\n */\nexport class HuffmanProcessor {\n private nodes: HuffNode[] = [];\n private leaves: HuffLeaf[] = [];\n private tablesBuilt = false;\n\n buildTables(): void {\n if (this.tablesBuilt) return;\n this.tablesBuilt = true;\n\n // Initialize leaves from frequency table\n this.leaves = [];\n for (let i = 0; i < 256; i++) {\n this.leaves.push({\n pop:\n CSM_CHAR_FREQS[i] +\n (isAlphaNumeric(i) ? PROB_BOOST : 0) +\n PROB_BOOST,\n symbol: i,\n numBits: 0,\n code: 0,\n });\n }\n\n // Initialize nodes array with one placeholder at index 0\n this.nodes = [{ pop: 0, index0: 0, index1: 0 }];\n\n // Build wraps array\n let currWraps = 256;\n const wraps: HuffWrap[] = [];\n for (let i = 0; i < 256; i++) {\n wraps.push({ node: null, leaf: this.leaves[i] });\n }\n\n // Build the Huffman tree by repeatedly combining the two lowest-population wraps\n while (currWraps !== 1) {\n let min1 = 0xfffffffe;\n let min2 = 0xffffffff;\n let index1 = -1;\n let index2 = -1;\n\n for (let i = 0; i < currWraps; i++) {\n const pop = wrapGetPop(wraps[i]);\n if (pop < min1) {\n min2 = min1;\n index2 = index1;\n min1 = pop;\n index1 = i;\n } else if (pop < min2) {\n min2 = pop;\n index2 = i;\n }\n }\n\n // Create a new node combining the two smallest\n const newNode: HuffNode = {\n pop: wrapGetPop(wraps[index1]) + wrapGetPop(wraps[index2]),\n index0: this.determineIndex(wraps[index1]),\n index1: this.determineIndex(wraps[index2]),\n };\n this.nodes.push(newNode);\n\n // Replace the lower-indexed wrap with the new node, remove the higher-indexed one\n const mergeIndex = index1 < index2 ? index1 : index2;\n const nukeIndex = index1 > index2 ? index1 : index2;\n wraps[mergeIndex] = { node: newNode, leaf: null };\n\n if (nukeIndex !== currWraps - 1) {\n wraps[nukeIndex] = wraps[currWraps - 1];\n }\n currWraps--;\n }\n\n // The root node should be at nodes[0]\n this.nodes[0] = wraps[0].node!;\n\n // Generate Huffman codes by walking the tree\n this.generateCodes(0, 0, 0);\n }\n\n private determineIndex(wrap: HuffWrap): number {\n if (wrap.leaf !== null) {\n // Leaf index is encoded as -(leafArrayIndex + 1)\n const leafIdx = this.leaves.indexOf(wrap.leaf);\n return -(leafIdx + 1);\n } else {\n return this.nodes.indexOf(wrap.node!);\n }\n }\n\n private generateCodes(code: number, nodeIndex: number, depth: number): void {\n if (nodeIndex < 0) {\n // Leaf node\n const leaf = this.leaves[-(nodeIndex + 1)];\n leaf.code = code;\n leaf.numBits = depth;\n } else {\n const node = this.nodes[nodeIndex];\n // Go left (0 bit)\n this.generateCodes(code, node.index0, depth + 1);\n // Go right (1 bit)\n this.generateCodes(code | (1 << depth), node.index1, depth + 1);\n }\n }\n\n readHuffBuffer(stream: BitStream): string {\n if (!this.tablesBuilt) {\n this.buildTables();\n }\n\n if (stream.readFlag()) {\n // Huffman-compressed string\n const len = stream.readInt(8);\n const chars: number[] = [];\n for (let i = 0; i < len; i++) {\n let index = 0;\n while (true) {\n if (index >= 0) {\n if (stream.readFlag()) {\n index = this.nodes[index].index1;\n } else {\n index = this.nodes[index].index0;\n }\n } else {\n chars.push(this.leaves[-(index + 1)].symbol);\n break;\n }\n }\n }\n return String.fromCharCode(...chars);\n } else {\n // Uncompressed string\n const len = stream.readInt(8);\n const bytes = stream.readBytes(len);\n return String.fromCharCode(...bytes);\n }\n }\n\n /**\n * Encode a string the way the engine's writeHuffBuffer does: a flag\n * selecting compressed vs. raw bytes (compressed only when it is\n * shorter), an 8-bit length, then either Huffman codes or raw bytes.\n * Characters are written as Latin-1 bytes (code units above 255 throw).\n */\n writeHuffBuffer(writer: BitWriter, value: string): void {\n if (!this.tablesBuilt) {\n this.buildTables();\n }\n if (value.length > MaxHuffStringLength) {\n throw new RangeError(\n `string too long for Huffman buffer: ${value.length} > ${MaxHuffStringLength}`,\n );\n }\n const codes = new Array<number>(value.length);\n let numBits = 0;\n for (let i = 0; i < value.length; i++) {\n const c = value.charCodeAt(i);\n if (c > 255) {\n throw new RangeError(`non-Latin-1 character at index ${i}`);\n }\n codes[i] = c;\n numBits += this.leaves[c].numBits;\n }\n if (numBits >= value.length * 8) {\n writer.writeFlag(false);\n writer.writeInt(value.length, 8);\n for (const c of codes) writer.writeInt(c, 8);\n } else {\n writer.writeFlag(true);\n writer.writeInt(value.length, 8);\n for (const c of codes) {\n const leaf = this.leaves[c];\n writer.writeInt(leaf.code, leaf.numBits);\n }\n }\n }\n}\n\n// Singleton instance matching the C++ g_huffProcessor\nexport const huffProcessor = new HuffmanProcessor();\n"]}
|
package/dist/LiveParser.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ClassRegistry } from "./ClassRegistry.js";
|
|
1
|
+
import type { ClassRegistry } from "./ClassRegistry.js";
|
|
2
2
|
import { GhostTracker } from "./GhostManager.js";
|
|
3
3
|
import { PacketParser } from "./PacketParser.js";
|
|
4
4
|
import type { ConnectionProtocolState, NetEventInfo } from "./types.js";
|
|
@@ -27,6 +27,8 @@ export interface LiveParserSeed {
|
|
|
27
27
|
absoluteSequenceNumber: number;
|
|
28
28
|
event: NetEventInfo;
|
|
29
29
|
}>;
|
|
30
|
+
/** Passed to PacketParser; see its `haltOnFault` option (default true). */
|
|
31
|
+
haltOnFault?: boolean;
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
34
|
* Protocol state for a parser that passively observes the server→client
|
|
@@ -38,8 +40,25 @@ export interface LiveParserSeed {
|
|
|
38
40
|
* connection: `lastSeqRecvd` starts at 0, so the 9-bit sequence window
|
|
39
41
|
* check rejects packets attached mid-stream (seed
|
|
40
42
|
* `connectionProtocolState` from the exporter in that case).
|
|
43
|
+
*
|
|
44
|
+
* This is parser-only state. Never write it into a .rec initial block:
|
|
45
|
+
* Tribes2.exe requires `notifyCount === lastSendSeq - highestAckedSeq`
|
|
46
|
+
* and treats `lastSendSeq - highestAckedSeq > 0x1d` as a full send window
|
|
47
|
+
* (no notify is queued for a SendPacket marker), so a demo seeded with
|
|
48
|
+
* this value crashes on the first acknowledged packet. Use
|
|
49
|
+
* `freshConnectionProtocolState` for a recording that starts at connect
|
|
50
|
+
* time.
|
|
41
51
|
*/
|
|
42
52
|
export declare function passiveObserverProtocolState(firstPacketByte: number): ConnectionProtocolState;
|
|
53
|
+
/**
|
|
54
|
+
* The ConnectionProtocol state of a connection that has not yet exchanged
|
|
55
|
+
* a sequenced packet — what a demo whose stream starts at connect time
|
|
56
|
+
* must seed (with a notify count of 0, since nothing is in flight). The
|
|
57
|
+
* recorder must then write one SendPacket marker per packet it actually
|
|
58
|
+
* sends, before the received packet that acks it; Tribes2.exe replays
|
|
59
|
+
* those markers through checkPacketSend to rebuild the notify queue.
|
|
60
|
+
*/
|
|
61
|
+
export declare function freshConnectionProtocolState(connectSequence: number): ConnectionProtocolState;
|
|
43
62
|
/**
|
|
44
63
|
* Create a parser stack for live server connections. Sets up the same
|
|
45
64
|
* registry bindings as DemoParser but without requiring a demo file,
|
package/dist/LiveParser.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveParser.d.ts","sourceRoot":"","sources":["../src/LiveParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveParser.d.ts","sourceRoot":"","sources":["../src/LiveParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,uBAAuB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAC5C,wEAAwE;IACxE,MAAM,CAAC,EAAE,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;IAClD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD,uBAAuB,CAAC,EAAE,KAAK,CAAC;QAC9B,sBAAsB,EAAE,MAAM,CAAC;QAC/B,KAAK,EAAE,YAAY,CAAC;KACrB,CAAC,CAAC;IACH,2EAA2E;IAC3E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,4BAA4B,CAC1C,eAAe,EAAE,MAAM,GACtB,uBAAuB,CAWzB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,eAAe,EAAE,MAAM,GACtB,uBAAuB,CAWzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,aAAa,CAgCrE"}
|
package/dist/LiveParser.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createDefaultRegistry } from "./defaultRegistry.js";
|
|
2
2
|
import { GhostTracker } from "./GhostManager.js";
|
|
3
3
|
import { PacketParser } from "./PacketParser.js";
|
|
4
|
-
import { registerEventParsers } from "./EventParsers.js";
|
|
5
|
-
import { registerGhostParsers } from "./GhostManager.js";
|
|
6
|
-
import { registerDataBlockParsers } from "./DataBlockParsers.js";
|
|
7
|
-
import { DataBlockClassFirst, DataBlockClassNames, NetObjectClassFirst, NetObjectClassNames, NetEventClassFirst, NetEventClassNames, } from "./types.js";
|
|
8
4
|
/**
|
|
9
5
|
* Protocol state for a parser that passively observes the server→client
|
|
10
6
|
* stream while something else (e.g. a relay) owns the client→server side.
|
|
@@ -15,6 +11,14 @@ import { DataBlockClassFirst, DataBlockClassNames, NetObjectClassFirst, NetObjec
|
|
|
15
11
|
* connection: `lastSeqRecvd` starts at 0, so the 9-bit sequence window
|
|
16
12
|
* check rejects packets attached mid-stream (seed
|
|
17
13
|
* `connectionProtocolState` from the exporter in that case).
|
|
14
|
+
*
|
|
15
|
+
* This is parser-only state. Never write it into a .rec initial block:
|
|
16
|
+
* Tribes2.exe requires `notifyCount === lastSendSeq - highestAckedSeq`
|
|
17
|
+
* and treats `lastSendSeq - highestAckedSeq > 0x1d` as a full send window
|
|
18
|
+
* (no notify is queued for a SendPacket marker), so a demo seeded with
|
|
19
|
+
* this value crashes on the first acknowledged packet. Use
|
|
20
|
+
* `freshConnectionProtocolState` for a recording that starts at connect
|
|
21
|
+
* time.
|
|
18
22
|
*/
|
|
19
23
|
export function passiveObserverProtocolState(firstPacketByte) {
|
|
20
24
|
return {
|
|
@@ -28,6 +32,26 @@ export function passiveObserverProtocolState(firstPacketByte) {
|
|
|
28
32
|
connectionEstablished: true,
|
|
29
33
|
};
|
|
30
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* The ConnectionProtocol state of a connection that has not yet exchanged
|
|
37
|
+
* a sequenced packet — what a demo whose stream starts at connect time
|
|
38
|
+
* must seed (with a notify count of 0, since nothing is in flight). The
|
|
39
|
+
* recorder must then write one SendPacket marker per packet it actually
|
|
40
|
+
* sends, before the received packet that acks it; Tribes2.exe replays
|
|
41
|
+
* those markers through checkPacketSend to rebuild the notify queue.
|
|
42
|
+
*/
|
|
43
|
+
export function freshConnectionProtocolState(connectSequence) {
|
|
44
|
+
return {
|
|
45
|
+
lastSeqRecvdAtSend: new Array(32).fill(0),
|
|
46
|
+
lastSeqRecvd: 0,
|
|
47
|
+
highestAckedSeq: 0,
|
|
48
|
+
lastSendSeq: 0,
|
|
49
|
+
ackMask: 0,
|
|
50
|
+
connectSequence: connectSequence >>> 0,
|
|
51
|
+
lastRecvAckAck: 0,
|
|
52
|
+
connectionEstablished: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
31
55
|
/**
|
|
32
56
|
* Create a parser stack for live server connections. Sets up the same
|
|
33
57
|
* registry bindings as DemoParser but without requiring a demo file,
|
|
@@ -39,14 +63,8 @@ export function passiveObserverProtocolState(firstPacketByte) {
|
|
|
39
63
|
* continue parsing at a packet boundary in lockstep with the exporter.
|
|
40
64
|
*/
|
|
41
65
|
export function createLiveParser(seed) {
|
|
42
|
-
const registry =
|
|
66
|
+
const registry = createDefaultRegistry();
|
|
43
67
|
const ghostTracker = new GhostTracker();
|
|
44
|
-
registerEventParsers(registry);
|
|
45
|
-
registerGhostParsers(registry);
|
|
46
|
-
registerDataBlockParsers(registry);
|
|
47
|
-
registry.bindDeterministicDataBlocks(DataBlockClassNames, DataBlockClassFirst);
|
|
48
|
-
registry.bindDeterministicGhosts(NetObjectClassNames, NetObjectClassFirst);
|
|
49
|
-
registry.bindDeterministicEvents(NetEventClassNames, NetEventClassFirst);
|
|
50
68
|
const dataBlockDataMap = new Map();
|
|
51
69
|
if (seed?.dataBlocks) {
|
|
52
70
|
for (const [objectId, data] of seed.dataBlocks) {
|
|
@@ -65,6 +83,7 @@ export function createLiveParser(seed) {
|
|
|
65
83
|
nextRecvEventSeq: seed?.nextRecvEventSeq,
|
|
66
84
|
compressionPoint: seed?.compressionPoint,
|
|
67
85
|
pendingGuaranteedEvents: seed?.pendingGuaranteedEvents,
|
|
86
|
+
haltOnFault: seed?.haltOnFault,
|
|
68
87
|
});
|
|
69
88
|
return { registry, ghostTracker, packetParser };
|
|
70
89
|
}
|
package/dist/LiveParser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveParser.js","sourceRoot":"","sources":["../src/LiveParser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LiveParser.js","sourceRoot":"","sources":["../src/LiveParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA0BjD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,4BAA4B,CAC1C,eAAuB;IAEvB,OAAO;QACL,kBAAkB,EAAE,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,YAAY,EAAE,CAAC;QACf,eAAe,EAAE,CAAC;QAClB,WAAW,EAAE,UAAU;QACvB,OAAO,EAAE,CAAC;QACV,eAAe,EAAE,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC;QAC3C,cAAc,EAAE,CAAC;QACjB,qBAAqB,EAAE,IAAI;KAC5B,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,4BAA4B,CAC1C,eAAuB;IAEvB,OAAO;QACL,kBAAkB,EAAE,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,YAAY,EAAE,CAAC;QACf,eAAe,EAAE,CAAC;QAClB,WAAW,EAAE,CAAC;QACd,OAAO,EAAE,CAAC;QACV,eAAe,EAAE,eAAe,KAAK,CAAC;QACtC,cAAc,EAAE,CAAC;QACjB,qBAAqB,EAAE,IAAI;KAC5B,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAqB;IACpD,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;IACzC,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;IAExC,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAsB,CAAC;IACvD,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC;QACrB,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC/C,gBAAgB,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;QACjB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC3D,YAAY,CAAC,WAAW,CACtB,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,OAAO,EACb,WAAW,EAAE,IAAI,IAAI,WAAW,KAAK,CAAC,OAAO,EAAE,CAChD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE;QAC5D,gBAAgB;QAChB,uBAAuB,EAAE,IAAI,EAAE,uBAAuB;QACtD,gBAAgB,EAAE,IAAI,EAAE,gBAAgB;QACxC,gBAAgB,EAAE,IAAI,EAAE,gBAAgB;QACxC,uBAAuB,EAAE,IAAI,EAAE,uBAAuB;QACtD,WAAW,EAAE,IAAI,EAAE,WAAW;KAC/B,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;AAClD,CAAC","sourcesContent":["import type { ClassRegistry } from \"./ClassRegistry.js\";\nimport { createDefaultRegistry } from \"./defaultRegistry.js\";\nimport { GhostTracker } from \"./GhostManager.js\";\nimport { PacketParser } from \"./PacketParser.js\";\nimport type { ConnectionProtocolState, NetEventInfo } from \"./types.js\";\nimport type { ParsedData } from \"./ClassRegistry.js\";\n\nexport interface LiveParserKit {\n registry: ClassRegistry;\n ghostTracker: GhostTracker;\n packetParser: PacketParser;\n}\n\nexport interface LiveParserSeed {\n /** objectId → parsed datablock data, copied into the parser's map. */\n dataBlocks?: Iterable<[number, ParsedData]>;\n /** Existing ghosts, so mid-stream updates aren't misread as creates. */\n ghosts?: Iterable<{ index: number; classId: number }>;\n connectionProtocolState?: ConnectionProtocolState;\n nextRecvEventSeq?: number;\n compressionPoint?: { x: number; y: number; z: number };\n pendingGuaranteedEvents?: Array<{\n absoluteSequenceNumber: number;\n event: NetEventInfo;\n }>;\n /** Passed to PacketParser; see its `haltOnFault` option (default true). */\n haltOnFault?: boolean;\n}\n\n/**\n * Protocol state for a parser that passively observes the server→client\n * stream while something else (e.g. a relay) owns the client→server side.\n * `lastSendSeq` is set very high so ack validation (lastSendSeq <\n * highestAck → reject) never fires when the server acks sequences the\n * observer didn't send. The connect-sequence bit is taken from the first\n * observed packet's header byte. Intended for the first packets of a\n * connection: `lastSeqRecvd` starts at 0, so the 9-bit sequence window\n * check rejects packets attached mid-stream (seed\n * `connectionProtocolState` from the exporter in that case).\n *\n * This is parser-only state. Never write it into a .rec initial block:\n * Tribes2.exe requires `notifyCount === lastSendSeq - highestAckedSeq`\n * and treats `lastSendSeq - highestAckedSeq > 0x1d` as a full send window\n * (no notify is queued for a SendPacket marker), so a demo seeded with\n * this value crashes on the first acknowledged packet. Use\n * `freshConnectionProtocolState` for a recording that starts at connect\n * time.\n */\nexport function passiveObserverProtocolState(\n firstPacketByte: number,\n): ConnectionProtocolState {\n return {\n lastSeqRecvdAtSend: new Array(32).fill(0),\n lastSeqRecvd: 0,\n highestAckedSeq: 0,\n lastSendSeq: 0x1fffffff,\n ackMask: 0,\n connectSequence: (firstPacketByte >> 1) & 1,\n lastRecvAckAck: 0,\n connectionEstablished: true,\n };\n}\n\n/**\n * The ConnectionProtocol state of a connection that has not yet exchanged\n * a sequenced packet — what a demo whose stream starts at connect time\n * must seed (with a notify count of 0, since nothing is in flight). The\n * recorder must then write one SendPacket marker per packet it actually\n * sends, before the received packet that acks it; Tribes2.exe replays\n * those markers through checkPacketSend to rebuild the notify queue.\n */\nexport function freshConnectionProtocolState(\n connectSequence: number,\n): ConnectionProtocolState {\n return {\n lastSeqRecvdAtSend: new Array(32).fill(0),\n lastSeqRecvd: 0,\n highestAckedSeq: 0,\n lastSendSeq: 0,\n ackMask: 0,\n connectSequence: connectSequence >>> 0,\n lastRecvAckAck: 0,\n connectionEstablished: true,\n };\n}\n\n/**\n * Create a parser stack for live server connections. Sets up the same\n * registry bindings as DemoParser but without requiring a demo file,\n * and includes a dataBlockDataMap for incremental datablock accumulation\n * via SimDataBlockEvent.\n *\n * With a seed, the stack resumes an in-progress stream from exported\n * state (mirroring DemoParser.setupPacketParser), so a late joiner can\n * continue parsing at a packet boundary in lockstep with the exporter.\n */\nexport function createLiveParser(seed?: LiveParserSeed): LiveParserKit {\n const registry = createDefaultRegistry();\n const ghostTracker = new GhostTracker();\n\n const dataBlockDataMap = new Map<number, ParsedData>();\n if (seed?.dataBlocks) {\n for (const [objectId, data] of seed.dataBlocks) {\n dataBlockDataMap.set(objectId, data);\n }\n }\n\n if (seed?.ghosts) {\n for (const ghost of seed.ghosts) {\n const parserEntry = registry.getGhostParser(ghost.classId);\n ghostTracker.createGhost(\n ghost.index,\n ghost.classId,\n parserEntry?.name ?? `unknown_${ghost.classId}`,\n );\n }\n }\n\n const packetParser = new PacketParser(registry, ghostTracker, {\n dataBlockDataMap,\n connectionProtocolState: seed?.connectionProtocolState,\n nextRecvEventSeq: seed?.nextRecvEventSeq,\n compressionPoint: seed?.compressionPoint,\n pendingGuaranteedEvents: seed?.pendingGuaranteedEvents,\n haltOnFault: seed?.haltOnFault,\n });\n\n return { registry, ghostTracker, packetParser };\n}\n"]}
|
package/dist/PacketParser.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ConnectionProtocolState, PacketData, NetEventInfo } from "./types.js";
|
|
1
|
+
import type { ConnectionProtocolState, PacketData, ParseFault, NetEventInfo } from "./types.js";
|
|
2
2
|
import type { ClassRegistry, ParsedData } from "./ClassRegistry.js";
|
|
3
3
|
import type { GhostTracker } from "./GhostManager.js";
|
|
4
4
|
/**
|
|
@@ -25,6 +25,8 @@ export declare class PacketParser {
|
|
|
25
25
|
private _connectionEstablished;
|
|
26
26
|
private nextRecvEventSeq;
|
|
27
27
|
private pendingGuaranteedEvents;
|
|
28
|
+
private readonly haltOnFault;
|
|
29
|
+
private _fault?;
|
|
28
30
|
controlObjectParsed: number;
|
|
29
31
|
controlObjectFailed: number;
|
|
30
32
|
eventsParsed: number;
|
|
@@ -41,6 +43,8 @@ export declare class PacketParser {
|
|
|
41
43
|
packetsParsed: number;
|
|
42
44
|
protocolRejected: number;
|
|
43
45
|
protocolNoDispatch: number;
|
|
46
|
+
/** Packets received after the parser faulted and halted. */
|
|
47
|
+
packetsDroppedAfterFault: number;
|
|
44
48
|
constructor(registry: ClassRegistry, ghostTracker: GhostTracker, options?: {
|
|
45
49
|
dataBlockDataMap?: Map<number, ParsedData>;
|
|
46
50
|
connectionProtocolState?: ConnectionProtocolState;
|
|
@@ -54,13 +58,29 @@ export declare class PacketParser {
|
|
|
54
58
|
absoluteSequenceNumber: number;
|
|
55
59
|
event: NetEventInfo;
|
|
56
60
|
}>;
|
|
61
|
+
/**
|
|
62
|
+
* Stop parsing after the first packet that faults (default true).
|
|
63
|
+
* The engine drops the connection on an unreadable packet, and every
|
|
64
|
+
* later packet would be parsed against ghost/event state that no
|
|
65
|
+
* longer mirrors the server. Set false to keep going regardless.
|
|
66
|
+
*/
|
|
67
|
+
haltOnFault?: boolean;
|
|
57
68
|
});
|
|
58
69
|
getCompressionPoint(): {
|
|
59
70
|
x: number;
|
|
60
71
|
y: number;
|
|
61
72
|
z: number;
|
|
62
73
|
};
|
|
63
|
-
|
|
74
|
+
/** Live datablock map (grows as SimDataBlockEvents arrive). */
|
|
75
|
+
getDataBlockDataMap(): ReadonlyMap<number, ParsedData> | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* The first parse fault, if any. Once set (and `haltOnFault` is on),
|
|
78
|
+
* later packets are returned empty with this fault attached; build a
|
|
79
|
+
* fresh parser (DemoParser.reset(), or a new createLiveParser seeded
|
|
80
|
+
* from a known-good state) to continue.
|
|
81
|
+
*/
|
|
82
|
+
get fault(): ParseFault | undefined;
|
|
83
|
+
get faulted(): boolean;
|
|
64
84
|
private getConnectionContext;
|
|
65
85
|
private _setNextRecvEventSeq;
|
|
66
86
|
setConnectionProtocolState(state: ConnectionProtocolState): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PacketParser.d.ts","sourceRoot":"","sources":["../src/PacketParser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PacketParser.d.ts","sourceRoot":"","sources":["../src/PacketParser.ts"],"names":[],"mappings":"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"}
|