t2-demo-parser 1.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -87
- package/dist/DataBlockParsers.d.ts.map +1 -1
- package/dist/DataBlockParsers.js +51 -42
- package/dist/DataBlockParsers.js.map +1 -1
- package/dist/DataBlockParsers.test.js +32 -0
- package/dist/DataBlockParsers.test.js.map +1 -1
- package/dist/DemoParser.d.ts.map +1 -1
- package/dist/DemoParser.js +43 -8
- package/dist/DemoParser.js.map +1 -1
- package/dist/GhostManager.d.ts.map +1 -1
- package/dist/GhostManager.js +36 -68
- package/dist/GhostManager.js.map +1 -1
- package/dist/GhostStateAccumulator.d.ts +36 -0
- package/dist/GhostStateAccumulator.d.ts.map +1 -0
- package/dist/GhostStateAccumulator.js +124 -0
- package/dist/GhostStateAccumulator.js.map +1 -0
- package/dist/GhostStateAccumulator.test.d.ts +2 -0
- package/dist/GhostStateAccumulator.test.d.ts.map +1 -0
- package/dist/GhostStateAccumulator.test.js +201 -0
- package/dist/GhostStateAccumulator.test.js.map +1 -0
- package/dist/LiveParser.d.ts +39 -1
- package/dist/LiveParser.d.ts.map +1 -1
- package/dist/LiveParser.js +43 -1
- package/dist/LiveParser.js.map +1 -1
- package/dist/PacketParser.d.ts +23 -2
- package/dist/PacketParser.d.ts.map +1 -1
- package/dist/PacketParser.js +62 -19
- package/dist/PacketParser.js.map +1 -1
- package/dist/dataBlockDataTypes.d.ts +22 -21
- package/dist/dataBlockDataTypes.d.ts.map +1 -1
- package/dist/dataBlockDataTypes.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PacketParser.d.ts","sourceRoot":"","sources":["../src/PacketParser.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,uBAAuB,EAIvB,UAAU,
|
|
1
|
+
{"version":3,"file":"PacketParser.d.ts","sourceRoot":"","sources":["../src/PacketParser.ts"],"names":[],"mappings":"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"}
|
package/dist/PacketParser.js
CHANGED
|
@@ -15,7 +15,6 @@ export class PacketParser {
|
|
|
15
15
|
registry;
|
|
16
16
|
ghostTracker;
|
|
17
17
|
compressionPoint = { x: 0, y: 0, z: 0 };
|
|
18
|
-
controlParserByGhostIndex = new Map();
|
|
19
18
|
dataBlockDataMap;
|
|
20
19
|
lastSeqRecvdAtSend = new Array(32).fill(0);
|
|
21
20
|
lastSeqRecvd = 0;
|
|
@@ -54,6 +53,14 @@ export class PacketParser {
|
|
|
54
53
|
if (typeof options?.nextRecvEventSeq === "number") {
|
|
55
54
|
this.nextRecvEventSeq = options.nextRecvEventSeq >>> 0;
|
|
56
55
|
}
|
|
56
|
+
if (options?.compressionPoint) {
|
|
57
|
+
this.compressionPoint = { ...options.compressionPoint };
|
|
58
|
+
}
|
|
59
|
+
if (options?.pendingGuaranteedEvents) {
|
|
60
|
+
this.pendingGuaranteedEvents = options.pendingGuaranteedEvents
|
|
61
|
+
.map((entry) => ({ ...entry }))
|
|
62
|
+
.sort((a, b) => a.absoluteSequenceNumber - b.absoluteSequenceNumber);
|
|
63
|
+
}
|
|
57
64
|
}
|
|
58
65
|
getCompressionPoint() {
|
|
59
66
|
return this.compressionPoint;
|
|
@@ -89,6 +96,31 @@ export class PacketParser {
|
|
|
89
96
|
this.lastRecvAckAck = state.lastRecvAckAck >>> 0;
|
|
90
97
|
this._connectionEstablished = state.connectionEstablished;
|
|
91
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Export the current protocol window state. Together with
|
|
101
|
+
* `getNextRecvEventSeq`, `getPendingGuaranteedEvents`,
|
|
102
|
+
* `getCompressionPoint`, `getDataBlockDataMap`, and the ghost tracker
|
|
103
|
+
* contents, this captures all cross-packet parser state, so an
|
|
104
|
+
* identically seeded parser continues the stream in lockstep.
|
|
105
|
+
*/
|
|
106
|
+
getConnectionProtocolState() {
|
|
107
|
+
return {
|
|
108
|
+
lastSeqRecvdAtSend: this.lastSeqRecvdAtSend.slice(),
|
|
109
|
+
lastSeqRecvd: this.lastSeqRecvd,
|
|
110
|
+
highestAckedSeq: this.highestAckedSeq,
|
|
111
|
+
lastSendSeq: this.lastSendSeq,
|
|
112
|
+
ackMask: this.recvAckMask,
|
|
113
|
+
connectSequence: this.connectSequence,
|
|
114
|
+
lastRecvAckAck: this.lastRecvAckAck,
|
|
115
|
+
connectionEstablished: this._connectionEstablished,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
getNextRecvEventSeq() {
|
|
119
|
+
return this.nextRecvEventSeq;
|
|
120
|
+
}
|
|
121
|
+
getPendingGuaranteedEvents() {
|
|
122
|
+
return this.pendingGuaranteedEvents.map((entry) => ({ ...entry }));
|
|
123
|
+
}
|
|
92
124
|
/**
|
|
93
125
|
* Emulate ConnectionProtocol::buildSendPacketHeader (FUN_0043d2d0, data path).
|
|
94
126
|
* Demo block type 1 indicates a local send-packet trigger.
|
|
@@ -186,16 +218,21 @@ export class PacketParser {
|
|
|
186
218
|
// When an event can't be parsed, readEvents returns early and the
|
|
187
219
|
// stream position is wrong — reading ghosts would produce garbage.
|
|
188
220
|
const lastEvent = events[events.length - 1];
|
|
189
|
-
const eventsComplete = !lastEvent
|
|
221
|
+
const eventsComplete = !lastEvent?.failed;
|
|
190
222
|
// 5. Ghosts (NetConnection::readPacket -> ghostReadPacket)
|
|
191
|
-
const ghostSectionStart = gameStateComplete && eventsComplete
|
|
192
|
-
? bs.getCurPos()
|
|
193
|
-
: undefined;
|
|
223
|
+
const ghostSectionStart = gameStateComplete && eventsComplete ? bs.getCurPos() : undefined;
|
|
194
224
|
const ghosts = gameStateComplete && eventsComplete
|
|
195
225
|
? this.readGhosts(bs, dnetHeader.seqNumber)
|
|
196
226
|
: [];
|
|
197
227
|
bs.setStringBuffer(false);
|
|
198
|
-
return {
|
|
228
|
+
return {
|
|
229
|
+
dnetHeader,
|
|
230
|
+
rateInfo,
|
|
231
|
+
gameState,
|
|
232
|
+
events,
|
|
233
|
+
ghosts,
|
|
234
|
+
ghostSectionStart,
|
|
235
|
+
};
|
|
199
236
|
}
|
|
200
237
|
/**
|
|
201
238
|
* Parse the dnet packet header (from processRawPacket in dnet.cc).
|
|
@@ -303,9 +340,12 @@ export class PacketParser {
|
|
|
303
340
|
// writePacketData/readPacketData, so the control object is
|
|
304
341
|
// always one of these two classes. We try candidates in order:
|
|
305
342
|
// 1. Tracker classId (may be stale due to ghost index recycling)
|
|
306
|
-
// 2.
|
|
307
|
-
// 3.
|
|
308
|
-
//
|
|
343
|
+
// 2. Player (classId 25) — the normal control object
|
|
344
|
+
// 3. Camera (classId 4) — spectator mode
|
|
345
|
+
// The candidate order must be a pure function of seeded state
|
|
346
|
+
// (the tracker) so that a parser seeded mid-stream makes the same
|
|
347
|
+
// choice as one that has followed the stream from the start —
|
|
348
|
+
// no history-derived caches here.
|
|
309
349
|
const gIndex = bs.readInt(10);
|
|
310
350
|
controlObjectGhostIndex = gIndex;
|
|
311
351
|
controlObjectDataStart = bs.getCurPos();
|
|
@@ -314,7 +354,6 @@ export class PacketParser {
|
|
|
314
354
|
const preferredEntry = ghost
|
|
315
355
|
? this.registry.getGhostParser(ghost.classId)
|
|
316
356
|
: undefined;
|
|
317
|
-
const cachedEntry = this.controlParserByGhostIndex.get(gIndex);
|
|
318
357
|
const playerEntry = this.registry.getGhostParser(25); // Player
|
|
319
358
|
const cameraEntry = this.registry.getGhostParser(4); // Camera
|
|
320
359
|
// Build candidate list (deduplicated, only those with readPacketData)
|
|
@@ -329,7 +368,6 @@ export class PacketParser {
|
|
|
329
368
|
candidates.push(entry);
|
|
330
369
|
};
|
|
331
370
|
addCandidate(preferredEntry);
|
|
332
|
-
addCandidate(cachedEntry);
|
|
333
371
|
addCandidate(playerEntry);
|
|
334
372
|
addCandidate(cameraEntry);
|
|
335
373
|
let parsed = false;
|
|
@@ -344,7 +382,6 @@ export class PacketParser {
|
|
|
344
382
|
}
|
|
345
383
|
controlObjectData = data;
|
|
346
384
|
controlObjectDataEnd = bs.getCurPos();
|
|
347
|
-
this.controlParserByGhostIndex.set(gIndex, entry);
|
|
348
385
|
if (conn.compressionPoint !== this.compressionPoint) {
|
|
349
386
|
this.compressionPoint = conn.compressionPoint;
|
|
350
387
|
compressionPoint = this.compressionPoint;
|
|
@@ -493,6 +530,7 @@ export class PacketParser {
|
|
|
493
530
|
absoluteSequenceNumber,
|
|
494
531
|
dataBitsStart,
|
|
495
532
|
dataBitsEnd: dataBitsStart,
|
|
533
|
+
failed: true,
|
|
496
534
|
});
|
|
497
535
|
return dispatchedEvents;
|
|
498
536
|
}
|
|
@@ -506,6 +544,7 @@ export class PacketParser {
|
|
|
506
544
|
absoluteSequenceNumber,
|
|
507
545
|
dataBitsStart,
|
|
508
546
|
dataBitsEnd: dataBitsStart,
|
|
547
|
+
failed: true,
|
|
509
548
|
});
|
|
510
549
|
return dispatchedEvents;
|
|
511
550
|
}
|
|
@@ -564,11 +603,16 @@ export class PacketParser {
|
|
|
564
603
|
const eventType = parsedData.type;
|
|
565
604
|
if (eventType === "GhostingMessageEvent") {
|
|
566
605
|
const message = parsedData.message;
|
|
567
|
-
// Tribes 2 handleGhostMessage
|
|
568
|
-
//
|
|
606
|
+
// Tribes 2 handleGhostMessage EndGhosting (netGhost.cc:706) deletes
|
|
607
|
+
// ONLY local ghosts. Datablocks are connection-lifetime state and
|
|
608
|
+
// must be retained: the server's transmitDataBlocks skips datablocks
|
|
609
|
+
// already sent on this connection (gameConnection.cc
|
|
610
|
+
// cTransmitDataBlocks: only modifiedKey > mDataBlockModifiedKey is
|
|
611
|
+
// re-sent), so on a mission change most datablocks are NOT re-sent
|
|
612
|
+
// and clearing the map here leaves the new mission's ghosts
|
|
613
|
+
// unresolvable.
|
|
569
614
|
if (typeof message === "number" && message === GhostMsgEndGhosting) {
|
|
570
615
|
this.ghostTracker.clear();
|
|
571
|
-
this.dataBlockDataMap?.clear();
|
|
572
616
|
}
|
|
573
617
|
return;
|
|
574
618
|
}
|
|
@@ -580,12 +624,11 @@ export class PacketParser {
|
|
|
580
624
|
this.ghostTracker.createGhost(ghostIndex, classId, parserEntry?.name ?? `unknown_${classId}`);
|
|
581
625
|
}
|
|
582
626
|
}
|
|
583
|
-
// SimDataBlockEvent:
|
|
584
|
-
// (
|
|
627
|
+
// SimDataBlockEvent: accumulate parsed DataBlock data by objectId
|
|
628
|
+
// (exported for seeding and consumed by downstream renderers).
|
|
585
629
|
if (eventType === "SimDataBlockEvent" && this.dataBlockDataMap) {
|
|
586
630
|
const dbEvent = parsedData;
|
|
587
|
-
if (dbEvent.dataBlockData &&
|
|
588
|
-
typeof dbEvent.objectId === "number") {
|
|
631
|
+
if (dbEvent.dataBlockData && typeof dbEvent.objectId === "number") {
|
|
589
632
|
this.dataBlockDataMap.set(dbEvent.objectId, dbEvent.dataBlockData);
|
|
590
633
|
}
|
|
591
634
|
}
|
package/dist/PacketParser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PacketParser.js","sourceRoot":"","sources":["../src/PacketParser.ts"],"names":[],"mappings":"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","sourcesContent":["import createDebug from \"debug\";\nimport { BitStream } from \"./BitStream.js\";\nimport {\n DataPacket,\n MaxGhostCount,\n GhostMsgEndGhosting,\n NetEventClassBitSize,\n NetEventClassFirst,\n NetObjectClassBitSize,\n NetObjectClassFirst,\n} from \"./types.js\";\n\nconst debugGhosts = createDebug(\"t2-demo-parser:ghosts\");\nimport type {\n ConnectionProtocolState,\n DnetHeader,\n RateInfo,\n GameState,\n PacketData,\n NetEventInfo,\n GhostUpdate,\n} from \"./types.js\";\nimport type {\n ClassRegistry,\n ConnectionContext,\n GhostParserEntry,\n ParsedData,\n} from \"./ClassRegistry.js\";\nimport type { EventData, SimDataBlockEventData } from \"./eventDataTypes.js\";\nimport type { GhostTracker } from \"./GhostManager.js\";\n\n/**\n * Parses individual network packets from demo recording blocks.\n *\n * Packet layout (from the server connection perspective):\n * 1. dnet header (processRawPacket)\n * 2. Rate info (handlePacket)\n * 3. GameConnection::readPacket — game state, moves, etc.\n * 4. NetConnection::readPacket — events, then ghosts\n */\nexport class PacketParser {\n private registry: ClassRegistry;\n private ghostTracker: GhostTracker;\n private compressionPoint = { x: 0, y: 0, z: 0 };\n private controlParserByGhostIndex = new Map<number, GhostParserEntry>();\n private dataBlockDataMap?: Map<number, ParsedData>;\n private lastSeqRecvdAtSend = new Array<number>(32).fill(0);\n private lastSeqRecvd = 0;\n private highestAckedSeq = 0;\n private lastSendSeq = 0;\n private recvAckMask = 0;\n private connectSequence = 0;\n private lastRecvAckAck = 0;\n private _connectionEstablished = false;\n private nextRecvEventSeq = 0;\n private pendingGuaranteedEvents: Array<{\n absoluteSequenceNumber: number;\n event: NetEventInfo;\n }> = [];\n\n // Stats\n controlObjectParsed = 0;\n controlObjectFailed = 0;\n eventsParsed = 0;\n eventsFailed = 0;\n ghostCreatesParsed = 0;\n ghostUpdatesParsed = 0;\n ghostDeletes = 0;\n ghostsFailed = 0;\n /** Ghosts where our tracker says \"new\" but the classId is unregistered.\n * This indicates a tracker divergence: the server sent UPDATE data\n * (no classId prefix) for a ghost we don't have, so we misread the\n * first 7 bits of update data as a classId. */\n ghostsTrackerDiverged = 0;\n packetsParsed = 0;\n protocolRejected = 0;\n protocolNoDispatch = 0;\n\n constructor(\n registry: ClassRegistry,\n ghostTracker: GhostTracker,\n options?: {\n dataBlockDataMap?: Map<number, ParsedData>;\n connectionProtocolState?: ConnectionProtocolState;\n nextRecvEventSeq?: number;\n }\n ) {\n this.registry = registry;\n this.ghostTracker = ghostTracker;\n this.dataBlockDataMap = options?.dataBlockDataMap;\n if (options?.connectionProtocolState) {\n this.setConnectionProtocolState(options.connectionProtocolState);\n }\n if (typeof options?.nextRecvEventSeq === \"number\") {\n this.nextRecvEventSeq = options.nextRecvEventSeq >>> 0;\n }\n }\n\n getCompressionPoint(): { x: number; y: number; z: number } {\n return this.compressionPoint;\n }\n\n getDataBlockDataMap(): Map<number, ParsedData> | undefined {\n return this.dataBlockDataMap;\n }\n\n private getConnectionContext(): ConnectionContext {\n const dbMap = this.dataBlockDataMap;\n return {\n compressionPoint: this.compressionPoint,\n ghostTracker: this.ghostTracker,\n getDataBlockParser: (classId: number) =>\n this.registry.getDataBlockParser(classId),\n getDataBlockData: dbMap\n ? (objectId: number) => dbMap.get(objectId)\n : undefined,\n getGhostParser: (classId: number) => this.registry.getGhostParser(classId),\n };\n }\n\n private _setNextRecvEventSeq(nextRecvEventSeq: number): void {\n this.nextRecvEventSeq = nextRecvEventSeq >>> 0;\n }\n\n setConnectionProtocolState(state: ConnectionProtocolState): void {\n this.lastSeqRecvdAtSend = state.lastSeqRecvdAtSend.slice(0, 32);\n while (this.lastSeqRecvdAtSend.length < 32) {\n this.lastSeqRecvdAtSend.push(0);\n }\n this.lastSeqRecvd = state.lastSeqRecvd >>> 0;\n this.highestAckedSeq = state.highestAckedSeq >>> 0;\n this.lastSendSeq = state.lastSendSeq >>> 0;\n this.recvAckMask = state.ackMask >>> 0;\n this.connectSequence = state.connectSequence >>> 0;\n this.lastRecvAckAck = state.lastRecvAckAck >>> 0;\n this._connectionEstablished = state.connectionEstablished;\n }\n\n /**\n * Emulate ConnectionProtocol::buildSendPacketHeader (FUN_0043d2d0, data path).\n * Demo block type 1 indicates a local send-packet trigger.\n */\n onSendPacketTrigger(): void {\n this.lastSendSeq = (this.lastSendSeq + 1) >>> 0;\n this.lastSeqRecvdAtSend[this.lastSendSeq & 0x1f] = this.lastSeqRecvd >>> 0;\n }\n\n /**\n * Emulates ConnectionProtocol::processRawPacket (FUN_0043d4d0).\n * A packet may be syntactically valid but still ignored for game payload\n * dispatch due to sequence/connect-window checks or duplicate seq numbers.\n */\n private applyProtocolHeader(dnetHeader: DnetHeader): {\n accepted: boolean;\n dispatchData: boolean;\n } {\n if (dnetHeader.connectSeqBit !== (this.connectSequence & 1)) {\n return { accepted: false, dispatchData: false };\n }\n if (dnetHeader.ackByteCount > 4 || dnetHeader.packetType > 2) {\n return { accepted: false, dispatchData: false };\n }\n\n let seqNumber = (\n dnetHeader.seqNumber | (this.lastSeqRecvd & 0xffff_fe00)\n ) >>> 0;\n if (seqNumber < this.lastSeqRecvd) {\n seqNumber = (seqNumber + 0x200) >>> 0;\n }\n if (this.lastSeqRecvd + 0x1f < seqNumber) {\n return { accepted: false, dispatchData: false };\n }\n\n let highestAck = (\n dnetHeader.highestAck | (this.highestAckedSeq & 0xffff_fe00)\n ) >>> 0;\n if (highestAck < this.highestAckedSeq) {\n highestAck = (highestAck + 0x200) >>> 0;\n }\n if (this.lastSendSeq < highestAck) {\n return { accepted: false, dispatchData: false };\n }\n\n const seqShift = (seqNumber - this.lastSeqRecvd) & 0x1f;\n this.recvAckMask = (this.recvAckMask << seqShift) >>> 0;\n if (dnetHeader.packetType === DataPacket) {\n this.recvAckMask = (this.recvAckMask | 1) >>> 0;\n }\n\n for (let ackSeq = this.highestAckedSeq + 1; ackSeq <= highestAck; ackSeq++) {\n const isAcked = (\n dnetHeader.ackMask & (1 << ((highestAck - ackSeq) & 0x1f))\n ) !== 0;\n if (isAcked) {\n this.lastRecvAckAck = this.lastSeqRecvdAtSend[ackSeq & 0x1f] >>> 0;\n }\n }\n if (seqNumber - this.lastRecvAckAck > 0x20) {\n this.lastRecvAckAck = seqNumber - 0x20;\n }\n this.highestAckedSeq = highestAck;\n\n const dispatchData =\n this.lastSeqRecvd !== seqNumber && dnetHeader.packetType === DataPacket;\n this.lastSeqRecvd = seqNumber;\n\n return { accepted: true, dispatchData };\n }\n\n parsePacket(data: Uint8Array): PacketData {\n const bs = new BitStream(data);\n\n // 1. Parse dnet header\n const dnetHeader = this.readDnetHeader(bs);\n const protocol = this.applyProtocolHeader(dnetHeader);\n\n this.packetsParsed++;\n\n // ConnectionProtocol may reject this packet entirely (window/connect checks),\n // or accept it but suppress game dispatch (duplicate seq / non-data packet).\n if (!protocol.accepted) {\n this.protocolRejected++;\n return {\n dnetHeader,\n rateInfo: {},\n gameState: this.emptyGameState(),\n events: [],\n ghosts: [],\n };\n }\n if (!protocol.dispatchData) {\n this.protocolNoDispatch++;\n return {\n dnetHeader,\n rateInfo: {},\n gameState: this.emptyGameState(),\n events: [],\n ghosts: [],\n };\n }\n\n // 2. Rate info (NetConnection::handlePacket)\n const rateInfo = this.readRateInfo(bs);\n\n // 3. Game state (GameConnection::readPacket — server connection path)\n bs.setStringBuffer(true);\n const gameState = this.readGameState(bs);\n\n // Only read events/ghosts if game state completed successfully.\n // When game state bails (control object dirty with no parser), the\n // stream position is wrong and we'd read garbage data.\n const gameStateComplete =\n gameState.controlObjectDataStart === undefined ||\n gameState.controlObjectData !== undefined;\n\n // 4. Events (NetConnection::readPacket -> eventReadPacket)\n const events = gameStateComplete ? this.readEvents(bs) : [];\n\n // Only read ghosts if all events were successfully parsed.\n // When an event can't be parsed, readEvents returns early and the\n // stream position is wrong — reading ghosts would produce garbage.\n const lastEvent = events[events.length - 1];\n const eventsComplete =\n !lastEvent || lastEvent.dataBitsEnd !== lastEvent.dataBitsStart;\n\n // 5. Ghosts (NetConnection::readPacket -> ghostReadPacket)\n const ghostSectionStart = gameStateComplete && eventsComplete\n ? bs.getCurPos()\n : undefined;\n const ghosts =\n gameStateComplete && eventsComplete\n ? this.readGhosts(bs, dnetHeader.seqNumber)\n : [];\n\n bs.setStringBuffer(false);\n\n return { dnetHeader, rateInfo, gameState, events, ghosts, ghostSectionStart };\n }\n\n /**\n * Parse the dnet packet header (from processRawPacket in dnet.cc).\n */\n private readDnetHeader(bs: BitStream): DnetHeader {\n const gameFlag = bs.readFlag();\n const connectSeqBit = bs.readInt(1);\n const seqNumber = bs.readInt(9);\n const highestAck = bs.readInt(9);\n const packetType = bs.readInt(2);\n const ackByteCount = bs.readInt(3);\n const ackMask = ackByteCount > 0 ? bs.readInt(8 * ackByteCount) : 0;\n\n return {\n gameFlag,\n connectSeqBit,\n seqNumber,\n highestAck,\n packetType,\n ackByteCount,\n ackMask,\n };\n }\n\n /**\n * Parse rate info from handlePacket in netConnection.cc.\n */\n private readRateInfo(bs: BitStream): RateInfo {\n const info: RateInfo = {};\n if (bs.readFlag()) {\n info.updateDelay = bs.readInt(10);\n info.packetSize = bs.readInt(10);\n }\n if (bs.readFlag()) {\n info.maxUpdateDelay = bs.readInt(10);\n info.maxPacketSize = bs.readInt(10);\n }\n return info;\n }\n\n /**\n * Parse game state from GameConnection::readPacket (server connection path).\n */\n private readGameState(bs: BitStream): GameState {\n const lastMoveAck = bs.readInt(32);\n\n // Damage flash / whiteout\n let damageFlash: number | undefined;\n let whiteOut: number | undefined;\n if (bs.readFlag()) {\n if (bs.readFlag()) {\n damageFlash = bs.readFloat(7);\n }\n if (bs.readFlag()) {\n whiteOut = bs.readFloat(7) * 1.5;\n }\n }\n\n // Lock/homing state\n let selfLocked: boolean | undefined;\n let selfHomed: boolean | undefined;\n if (bs.readFlag()) {\n selfLocked = bs.readFlag();\n selfHomed = bs.readFlag();\n }\n\n // Seeker tracking state\n let seekerTracking: boolean | undefined;\n let seekerTrackingPos: { x: number; y: number; z: number } | undefined;\n let seekerMode: number | undefined;\n let seekerObjectGhostIndex: number | undefined;\n let targetPos: { x: number; y: number; z: number } | undefined;\n if (bs.readFlag()) {\n seekerTracking = bs.readFlag();\n // Binary 0x005fc020: when seekerTracking is true, reads 3×F32 (Point3F)\n // for the seeker target position (stored at connection+0x8454)\n if (seekerTracking) {\n seekerTrackingPos = {\n x: bs.readF32(),\n y: bs.readF32(),\n z: bs.readF32(),\n };\n }\n seekerMode = bs.readRangedU32(0, 2);\n if (seekerMode === 1) {\n if (bs.readFlag()) {\n seekerObjectGhostIndex = bs.readRangedU32(0, MaxGhostCount - 1);\n }\n } else if (seekerMode === 2) {\n targetPos = {\n x: bs.readF32(),\n y: bs.readF32(),\n z: bs.readF32(),\n };\n }\n }\n\n // Sensor ping/jam flags\n const pinged = bs.readFlag();\n const jammed = bs.readFlag();\n\n // Control object state\n let controlObjectGhostIndex: number | undefined;\n let controlObjectDataStart: number | undefined;\n let controlObjectDataEnd: number | undefined;\n let controlObjectData: ParsedData | undefined;\n let compressionPoint: { x: number; y: number; z: number } | undefined;\n\n if (bs.readFlag()) {\n if (bs.readFlag()) {\n // Control object is dirty — full update via readPacketData.\n // In Tribes 2 (build 25034), only Player and Camera override\n // writePacketData/readPacketData, so the control object is\n // always one of these two classes. We try candidates in order:\n // 1. Tracker classId (may be stale due to ghost index recycling)\n // 2. Cached parser from previous successful parse of this index\n // 3. Player (classId 25) — the normal control object\n // 4. Camera (classId 4) — spectator mode\n const gIndex = bs.readInt(10);\n controlObjectGhostIndex = gIndex;\n controlObjectDataStart = bs.getCurPos();\n const start = bs.savePos();\n const ghost = this.ghostTracker.getGhost(gIndex);\n\n const preferredEntry = ghost\n ? this.registry.getGhostParser(ghost.classId)\n : undefined;\n const cachedEntry = this.controlParserByGhostIndex.get(gIndex);\n const playerEntry = this.registry.getGhostParser(25); // Player\n const cameraEntry = this.registry.getGhostParser(4); // Camera\n\n // Build candidate list (deduplicated, only those with readPacketData)\n const candidates: GhostParserEntry[] = [];\n const seen = new Set<string>();\n const addCandidate = (entry: GhostParserEntry | undefined): void => {\n if (!entry?.readPacketData) return;\n if (seen.has(entry.name)) return;\n seen.add(entry.name);\n candidates.push(entry);\n };\n addCandidate(preferredEntry);\n addCandidate(cachedEntry);\n addCandidate(playerEntry);\n addCandidate(cameraEntry);\n\n let parsed = false;\n for (const entry of candidates) {\n bs.restorePos(start);\n try {\n const conn = this.getConnectionContext();\n const data = entry.readPacketData!(bs, conn);\n const bitsConsumed = bs.getCurPos() - controlObjectDataStart!;\n if (bitsConsumed <= 0 || bs.isError()) {\n continue;\n }\n\n controlObjectData = data;\n controlObjectDataEnd = bs.getCurPos();\n this.controlParserByGhostIndex.set(gIndex, entry);\n if (conn.compressionPoint !== this.compressionPoint) {\n this.compressionPoint = conn.compressionPoint;\n compressionPoint = this.compressionPoint;\n }\n this.controlObjectParsed++;\n parsed = true;\n break;\n } catch {\n // Try next candidate.\n }\n }\n\n if (!parsed) {\n bs.restorePos(start);\n // No parser — bail from game state\n controlObjectDataEnd = controlObjectDataStart;\n this.controlObjectFailed++;\n return {\n lastMoveAck,\n damageFlash,\n whiteOut,\n selfLocked,\n selfHomed,\n seekerTracking,\n seekerTrackingPos,\n seekerMode,\n seekerObjectGhostIndex,\n targetPos,\n pinged,\n jammed,\n controlObjectGhostIndex,\n controlObjectDataStart,\n controlObjectDataEnd,\n controlObjectData,\n targetVisibility: [],\n };\n }\n } else {\n // Compression point update — always accept (engine doesn't validate)\n compressionPoint = {\n x: bs.readF32(),\n y: bs.readF32(),\n z: bs.readF32(),\n };\n this.compressionPoint = compressionPoint;\n }\n }\n\n // Target visibility masks\n const targetVisibility: { index: number; mask: number }[] = [];\n while (bs.readFlag()) {\n targetVisibility.push({\n index: bs.readInt(4),\n mask: bs.readInt(32),\n });\n }\n\n // Camera FOV\n let cameraFov: number | undefined;\n if (bs.readFlag()) {\n cameraFov = bs.readInt(8);\n }\n\n return {\n lastMoveAck,\n damageFlash,\n whiteOut,\n selfLocked,\n selfHomed,\n seekerTracking,\n seekerTrackingPos,\n seekerMode,\n seekerObjectGhostIndex,\n targetPos,\n pinged,\n jammed,\n controlObjectGhostIndex,\n controlObjectDataStart,\n controlObjectDataEnd,\n controlObjectData,\n compressionPoint,\n targetVisibility: targetVisibility.length > 0 ? targetVisibility : undefined,\n cameraFov,\n };\n }\n\n /**\n * Parse events from eventReadPacket in netEvent.cc.\n *\n * Two phases:\n * 1. Unguaranteed events: while(readFlag) { classId(6b) + unpack }\n * 2. Guaranteed events: while(readFlag) { seqFlag(1b), [seq(7b)], classId(6b) + unpack }\n */\n private readEvents(bs: BitStream): NetEventInfo[] {\n const dispatchedEvents: NetEventInfo[] = [];\n let unguaranteedPhase = true;\n let prevGuaranteedSeq = -2;\n\n while (true) {\n const bit = bs.readFlag();\n if (unguaranteedPhase && !bit) {\n // Transition to guaranteed phase. Binary immediately reads one more\n // continuation bit for that phase.\n unguaranteedPhase = false;\n const guaranteedBit = bs.readFlag();\n if (!guaranteedBit) {\n this.dispatchGuaranteedEvents(dispatchedEvents);\n break;\n }\n } else if (!unguaranteedPhase && !bit) {\n this.dispatchGuaranteedEvents(dispatchedEvents);\n break;\n } else if (!bit) {\n break;\n }\n\n let sequenceNumber: number | undefined;\n let absoluteSequenceNumber: number | undefined;\n if (!unguaranteedPhase) {\n if (bs.readFlag()) {\n sequenceNumber = (prevGuaranteedSeq + 1) & 0x7f;\n } else {\n sequenceNumber = bs.readInt(7);\n }\n prevGuaranteedSeq = sequenceNumber;\n absoluteSequenceNumber =\n sequenceNumber | (this.nextRecvEventSeq & 0xffffff80);\n if (absoluteSequenceNumber < this.nextRecvEventSeq) {\n absoluteSequenceNumber += 0x80;\n }\n }\n\n const classId = bs.readInt(NetEventClassBitSize) + NetEventClassFirst;\n const dataBitsStart = bs.getCurPos();\n\n const parserEntry = this.registry.getEventParser(classId);\n let parsedData: ParsedData | undefined;\n\n if (parserEntry) {\n try {\n const conn = this.getConnectionContext();\n parsedData = parserEntry.unpack(bs, conn);\n this.eventsParsed++;\n } catch {\n this.eventsFailed++;\n dispatchedEvents.push({\n classId,\n guaranteed: !unguaranteedPhase,\n sequenceNumber,\n absoluteSequenceNumber,\n dataBitsStart,\n dataBitsEnd: dataBitsStart,\n });\n return dispatchedEvents;\n }\n } else {\n // No parser — cannot advance safely.\n dispatchedEvents.push({\n classId,\n guaranteed: !unguaranteedPhase,\n sequenceNumber,\n absoluteSequenceNumber,\n dataBitsStart,\n dataBitsEnd: dataBitsStart,\n });\n return dispatchedEvents;\n }\n\n const event: NetEventInfo = {\n classId,\n guaranteed: !unguaranteedPhase,\n sequenceNumber,\n absoluteSequenceNumber,\n dataBitsStart,\n dataBitsEnd: bs.getCurPos(),\n parsedData,\n };\n\n if (unguaranteedPhase) {\n dispatchedEvents.push(event);\n if (parsedData) {\n this.applyEventSideEffects(parsedData);\n }\n } else if (absoluteSequenceNumber !== undefined) {\n this.enqueueGuaranteedEvent(absoluteSequenceNumber, event);\n }\n }\n\n return dispatchedEvents;\n }\n\n private enqueueGuaranteedEvent(\n absoluteSequenceNumber: number,\n event: NetEventInfo\n ): void {\n let insertAt = 0;\n while (\n insertAt < this.pendingGuaranteedEvents.length &&\n this.pendingGuaranteedEvents[insertAt].absoluteSequenceNumber <\n absoluteSequenceNumber\n ) {\n insertAt++;\n }\n this.pendingGuaranteedEvents.splice(insertAt, 0, {\n absoluteSequenceNumber,\n event,\n });\n }\n\n private dispatchGuaranteedEvents(dispatchedEvents: NetEventInfo[]): void {\n while (\n this.pendingGuaranteedEvents.length > 0 &&\n this.pendingGuaranteedEvents[0].absoluteSequenceNumber ===\n this.nextRecvEventSeq\n ) {\n const queued = this.pendingGuaranteedEvents.shift();\n if (!queued) break;\n this.nextRecvEventSeq = (this.nextRecvEventSeq + 1) >>> 0;\n dispatchedEvents.push(queued.event);\n if (queued.event.parsedData) {\n this.applyEventSideEffects(queued.event.parsedData);\n }\n }\n }\n\n /**\n * Apply event side effects that alter ghost index state.\n * These effects occur before ghostReadPacket on the same packet.\n */\n private applyEventSideEffects(parsedData: ParsedData): void {\n const eventType = parsedData.type;\n\n if (eventType === \"GhostingMessageEvent\") {\n const message = parsedData.message;\n // Tribes 2 handleGhostMessage: EndGhosting clears all local ghosts\n // and invalidates all datablocks (they get re-sent for the new mission).\n if (typeof message === \"number\" && message === GhostMsgEndGhosting) {\n this.ghostTracker.clear();\n this.dataBlockDataMap?.clear();\n }\n return;\n }\n\n if (eventType === \"GhostAlwaysObjectEvent\") {\n const ghostIndex = parsedData.ghostIndex;\n const classId = parsedData.classId;\n if (typeof ghostIndex === \"number\" && typeof classId === \"number\") {\n const parserEntry = this.registry.getGhostParser(classId);\n this.ghostTracker.createGhost(\n ghostIndex,\n classId,\n parserEntry?.name ?? `unknown_${classId}`\n );\n }\n }\n\n // SimDataBlockEvent: store parsed DataBlock data so ghost parsers\n // (e.g., WheeledVehicle wheel count) can look it up by objectId.\n if (eventType === \"SimDataBlockEvent\" && this.dataBlockDataMap) {\n const dbEvent = parsedData as SimDataBlockEventData;\n if (\n dbEvent.dataBlockData &&\n typeof dbEvent.objectId === \"number\"\n ) {\n this.dataBlockDataMap.set(dbEvent.objectId, dbEvent.dataBlockData);\n }\n }\n }\n\n /**\n * Parse ghosts from ghostReadPacket in netGhost.cc.\n */\n private readGhosts(bs: BitStream, seqNumber: number): GhostUpdate[] {\n const ghosts: GhostUpdate[] = [];\n\n if (!bs.readFlag()) {\n return ghosts;\n }\n\n const idSize = bs.readInt(3) + 3;\n\n while (bs.readFlag()) {\n // If the stream ran out of data during the moreFlag read, the\n // readFlag returned false (terminating the loop) with error set.\n // Check here for the case where readFlag returned true but the\n // subsequent header reads exhaust the stream.\n if (bs.isError()) break;\n\n const index = bs.readInt(idSize);\n\n // If the stream ran out of data during header reads, stop processing.\n // Without this check, exhausted reads return 0 (defaulting index to 0,\n // classId to 0) and the ghost parser runs on empty data, producing\n // a \"successful\" parse that consumed 0 bits.\n if (bs.isError()) break;\n\n if (bs.readFlag()) {\n // Ghost is being deleted\n this.ghostTracker.deleteGhost(index);\n this.ghostDeletes++;\n ghosts.push({\n index,\n type: \"delete\",\n updateBitsStart: bs.getCurPos(),\n updateBitsEnd: bs.getCurPos(),\n });\n continue;\n }\n\n const isNew = !this.ghostTracker.hasGhost(index);\n let classId: number | undefined;\n\n if (isNew) {\n classId = bs.readInt(NetObjectClassBitSize) + NetObjectClassFirst;\n } else {\n classId = this.ghostTracker.getGhost(index)?.classId;\n }\n\n const updateBitsStart = bs.getCurPos();\n const parserEntry = classId !== undefined\n ? this.registry.getGhostParser(classId)\n : undefined;\n\n // Detect tracker divergence: we think this is a new ghost (not in our\n // tracker) but the classId is unregistered. This almost certainly means\n // the server sent UPDATE data (no classId prefix) for a ghost our tracker\n // lost, and we misread the first 7 bits of update data as a classId.\n // This is engine-consistent — the real client would also fail here\n // because classId lookup would return NULL, triggering packet drop.\n if (isNew && !parserEntry) {\n this.ghostsTrackerDiverged++;\n debugGhosts(\n \"DIVERGED pkt=%d seq=%d idx=%d classId=%d bit=%d/%d trackerSize=%d \" +\n \"(server sent UPDATE for ghost not in our tracker; 7-bit classId is actually update data)\",\n this.packetsParsed, seqNumber, index, classId,\n updateBitsStart, bs.getMaxPos(), this.ghostTracker.size()\n );\n ghosts.push({\n index,\n type: \"create\",\n classId,\n updateBitsStart,\n updateBitsEnd: updateBitsStart,\n });\n return ghosts;\n }\n\n let parsed = false;\n\n if (parserEntry) {\n try {\n const conn = this.getConnectionContext();\n conn.currentGhostIndex = index;\n const parsedData = parserEntry.unpackUpdate(bs, isNew, conn);\n const endPos = bs.getCurPos();\n\n if (isNew && classId !== undefined) {\n this.ghostTracker.createGhost(index, classId, parserEntry.name);\n this.ghostCreatesParsed++;\n } else {\n this.ghostUpdatesParsed++;\n }\n\n ghosts.push({\n index,\n type: isNew ? \"create\" : \"update\",\n classId,\n updateBitsStart,\n updateBitsEnd: endPos,\n parsedData,\n });\n parsed = true;\n } catch (e) {\n this.ghostsFailed++;\n const op = isNew ? \"create\" : \"update\";\n const message = e instanceof Error ? e.message : String(e);\n debugGhosts(\n \"FAIL pkt=%d seq=%d #%d idx=%d op=%s classId=%d parser=%s bit=%d/%d trackerSize=%d err=%s\",\n this.packetsParsed, seqNumber, ghosts.length, index, op, classId,\n parserEntry.name, updateBitsStart, bs.getMaxPos(),\n this.ghostTracker.size(), message\n );\n }\n }\n\n if (parsed) continue;\n\n debugGhosts(\n \"STOP pkt=%d seq=%d idx=%d op=%s classId=%d parser=%s bit=%d/%d\",\n this.packetsParsed, seqNumber, index, isNew ? \"create\" : \"update\",\n classId, parserEntry?.name ?? \"NONE\", updateBitsStart, bs.getMaxPos()\n );\n\n // Record and stop — can't parse this ghost's data.\n ghosts.push({\n index,\n type: isNew ? \"create\" : \"update\",\n classId,\n updateBitsStart,\n updateBitsEnd: updateBitsStart,\n });\n return ghosts;\n }\n\n return ghosts;\n }\n\n private emptyGameState(): GameState {\n return {\n lastMoveAck: 0,\n pinged: false,\n jammed: false,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"PacketParser.js","sourceRoot":"","sources":["../src/PacketParser.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EACL,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,GAAG,WAAW,CAAC,uBAAuB,CAAC,CAAC;AAmBzD;;;;;;;;GAQG;AACH,MAAM,OAAO,YAAY;IACf,QAAQ,CAAgB;IACxB,YAAY,CAAe;IAC3B,gBAAgB,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACxC,gBAAgB,CAA2B;IAC3C,kBAAkB,GAAG,IAAI,KAAK,CAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnD,YAAY,GAAG,CAAC,CAAC;IACjB,eAAe,GAAG,CAAC,CAAC;IACpB,WAAW,GAAG,CAAC,CAAC;IAChB,WAAW,GAAG,CAAC,CAAC;IAChB,eAAe,GAAG,CAAC,CAAC;IACpB,cAAc,GAAG,CAAC,CAAC;IACnB,sBAAsB,GAAG,KAAK,CAAC;IAC/B,gBAAgB,GAAG,CAAC,CAAC;IACrB,uBAAuB,GAG1B,EAAE,CAAC;IAER,QAAQ;IACR,mBAAmB,GAAG,CAAC,CAAC;IACxB,mBAAmB,GAAG,CAAC,CAAC;IACxB,YAAY,GAAG,CAAC,CAAC;IACjB,YAAY,GAAG,CAAC,CAAC;IACjB,kBAAkB,GAAG,CAAC,CAAC;IACvB,kBAAkB,GAAG,CAAC,CAAC;IACvB,YAAY,GAAG,CAAC,CAAC;IACjB,YAAY,GAAG,CAAC,CAAC;IACjB;;;oDAGgD;IAChD,qBAAqB,GAAG,CAAC,CAAC;IAC1B,aAAa,GAAG,CAAC,CAAC;IAClB,gBAAgB,GAAG,CAAC,CAAC;IACrB,kBAAkB,GAAG,CAAC,CAAC;IAEvB,YACE,QAAuB,EACvB,YAA0B,EAC1B,OASC;QAED,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,gBAAgB,GAAG,OAAO,EAAE,gBAAgB,CAAC;QAClD,IAAI,OAAO,EAAE,uBAAuB,EAAE,CAAC;YACrC,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,OAAO,OAAO,EAAE,gBAAgB,KAAK,QAAQ,EAAE,CAAC;YAClD,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,KAAK,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,OAAO,EAAE,gBAAgB,EAAE,CAAC;YAC9B,IAAI,CAAC,gBAAgB,GAAG,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAC1D,CAAC;QACD,IAAI,OAAO,EAAE,uBAAuB,EAAE,CAAC;YACrC,IAAI,CAAC,uBAAuB,GAAG,OAAO,CAAC,uBAAuB;iBAC3D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;iBAC9B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB,GAAG,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAEO,oBAAoB;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC;QACpC,OAAO;YACL,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,kBAAkB,EAAE,CAAC,OAAe,EAAE,EAAE,CACtC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,OAAO,CAAC;YAC3C,gBAAgB,EAAE,KAAK;gBACrB,CAAC,CAAC,CAAC,QAAgB,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAC3C,CAAC,CAAC,SAAS;YACb,cAAc,EAAE,CAAC,OAAe,EAAE,EAAE,CAClC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC;SACxC,CAAC;IACJ,CAAC;IAEO,oBAAoB,CAAC,gBAAwB;QACnD,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,KAAK,CAAC,CAAC;IACjD,CAAC;IAED,0BAA0B,CAAC,KAA8B;QACvD,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC,kBAAkB,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC;QAC7C,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,KAAK,CAAC,CAAC;QACjD,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC,qBAAqB,CAAC;IAC5D,CAAC;IAED;;;;;;OAMG;IACH,0BAA0B;QACxB,OAAO;YACL,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE;YACnD,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,OAAO,EAAE,IAAI,CAAC,WAAW;YACzB,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,qBAAqB,EAAE,IAAI,CAAC,sBAAsB;SACnD,CAAC;IACJ,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED,0BAA0B;QAIxB,OAAO,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;IAED;;;OAGG;IACH,mBAAmB;QACjB,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,KAAK,CAAC,CAAC;IAC7E,CAAC;IAED;;;;OAIG;IACK,mBAAmB,CAAC,UAAsB;QAIhD,IAAI,UAAU,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,EAAE,CAAC;YAC5D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QAClD,CAAC;QACD,IAAI,UAAU,CAAC,YAAY,GAAG,CAAC,IAAI,UAAU,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;YAC7D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QAClD,CAAC;QAED,IAAI,SAAS,GACX,CAAC,UAAU,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC;QACnE,IAAI,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YAClC,SAAS,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC;YACzC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QAClD,CAAC;QAED,IAAI,UAAU,GACZ,CAAC,UAAU,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC;QACvE,IAAI,UAAU,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;YACtC,UAAU,GAAG,CAAC,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,GAAG,UAAU,EAAE,CAAC;YAClC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QAClD,CAAC;QAED,MAAM,QAAQ,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;QACxD,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC;QACxD,IAAI,UAAU,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;YACzC,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAClD,CAAC;QAED,KACE,IAAI,MAAM,GAAG,IAAI,CAAC,eAAe,GAAG,CAAC,EACrC,MAAM,IAAI,UAAU,EACpB,MAAM,EAAE,EACR,CAAC;YACD,MAAM,OAAO,GACX,CAAC,UAAU,CAAC,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACrE,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;YACrE,CAAC;QACH,CAAC;QACD,IAAI,SAAS,GAAG,IAAI,CAAC,cAAc,GAAG,IAAI,EAAE,CAAC;YAC3C,IAAI,CAAC,cAAc,GAAG,SAAS,GAAG,IAAI,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC;QAElC,MAAM,YAAY,GAChB,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,UAAU,CAAC,UAAU,KAAK,UAAU,CAAC;QAC1E,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAE9B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAC1C,CAAC;IAED,WAAW,CAAC,IAAgB;QAC1B,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;QAE/B,uBAAuB;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;QAEtD,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,8EAA8E;QAC9E,6EAA6E;QAC7E,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACvB,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,OAAO;gBACL,UAAU;gBACV,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE;gBAChC,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,EAAE;aACX,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;YAC3B,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC1B,OAAO;gBACL,UAAU;gBACV,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE;gBAChC,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,EAAE;aACX,CAAC;QACJ,CAAC;QAED,6CAA6C;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QAEvC,sEAAsE;QACtE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QAEzC,gEAAgE;QAChE,mEAAmE;QACnE,uDAAuD;QACvD,MAAM,iBAAiB,GACrB,SAAS,CAAC,sBAAsB,KAAK,SAAS;YAC9C,SAAS,CAAC,iBAAiB,KAAK,SAAS,CAAC;QAE5C,2DAA2D;QAC3D,MAAM,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAE5D,2DAA2D;QAC3D,kEAAkE;QAClE,mEAAmE;QACnE,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC;QAE1C,2DAA2D;QAC3D,MAAM,iBAAiB,GACrB,iBAAiB,IAAI,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,MAAM,MAAM,GACV,iBAAiB,IAAI,cAAc;YACjC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,SAAS,CAAC;YAC3C,CAAC,CAAC,EAAE,CAAC;QAET,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAE1B,OAAO;YACL,UAAU;YACV,QAAQ;YACR,SAAS;YACT,MAAM;YACN,MAAM;YACN,iBAAiB;SAClB,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,EAAa;QAClC,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QAC/B,MAAM,aAAa,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,YAAY,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEpE,OAAO;YACL,QAAQ;YACR,aAAa;YACb,SAAS;YACT,UAAU;YACV,UAAU;YACV,YAAY;YACZ,OAAO;SACR,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,YAAY,CAAC,EAAa;QAChC,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YAClB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAClC,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YAClB,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACrC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,EAAa;QACjC,MAAM,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEnC,0BAA0B;QAC1B,IAAI,WAA+B,CAAC;QACpC,IAAI,QAA4B,CAAC;QACjC,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YAClB,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAClB,WAAW,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAChC,CAAC;YACD,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAClB,QAAQ,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;YACnC,CAAC;QACH,CAAC;QAED,oBAAoB;QACpB,IAAI,UAA+B,CAAC;QACpC,IAAI,SAA8B,CAAC;QACnC,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YAClB,UAAU,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;YAC3B,SAAS,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC;QAED,wBAAwB;QACxB,IAAI,cAAmC,CAAC;QACxC,IAAI,iBAAkE,CAAC;QACvE,IAAI,UAA8B,CAAC;QACnC,IAAI,sBAA0C,CAAC;QAC/C,IAAI,SAA0D,CAAC;QAC/D,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YAClB,cAAc,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;YAC/B,wEAAwE;YACxE,+DAA+D;YAC/D,IAAI,cAAc,EAAE,CAAC;gBACnB,iBAAiB,GAAG;oBAClB,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE;oBACf,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE;oBACf,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE;iBAChB,CAAC;YACJ,CAAC;YACD,UAAU,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpC,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;gBACrB,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;oBAClB,sBAAsB,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,aAAa,GAAG,CAAC,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;iBAAM,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG;oBACV,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE;oBACf,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE;oBACf,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE;iBAChB,CAAC;YACJ,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,MAAM,MAAM,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QAE7B,uBAAuB;QACvB,IAAI,uBAA2C,CAAC;QAChD,IAAI,sBAA0C,CAAC;QAC/C,IAAI,oBAAwC,CAAC;QAC7C,IAAI,iBAAyC,CAAC;QAC9C,IAAI,gBAAiE,CAAC;QAEtE,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YAClB,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAClB,4DAA4D;gBAC5D,6DAA6D;gBAC7D,2DAA2D;gBAC3D,+DAA+D;gBAC/D,mEAAmE;gBACnE,uDAAuD;gBACvD,2CAA2C;gBAC3C,8DAA8D;gBAC9D,kEAAkE;gBAClE,8DAA8D;gBAC9D,kCAAkC;gBAClC,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC9B,uBAAuB,GAAG,MAAM,CAAC;gBACjC,sBAAsB,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;gBACxC,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;gBAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBAEjD,MAAM,cAAc,GAAG,KAAK;oBAC1B,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC;oBAC7C,CAAC,CAAC,SAAS,CAAC;gBACd,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;gBAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;gBAE9D,sEAAsE;gBACtE,MAAM,UAAU,GAAuB,EAAE,CAAC;gBAC1C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;gBAC/B,MAAM,YAAY,GAAG,CAAC,KAAmC,EAAQ,EAAE;oBACjE,IAAI,CAAC,KAAK,EAAE,cAAc;wBAAE,OAAO;oBACnC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;wBAAE,OAAO;oBACjC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACrB,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACzB,CAAC,CAAC;gBACF,YAAY,CAAC,cAAc,CAAC,CAAC;gBAC7B,YAAY,CAAC,WAAW,CAAC,CAAC;gBAC1B,YAAY,CAAC,WAAW,CAAC,CAAC;gBAE1B,IAAI,MAAM,GAAG,KAAK,CAAC;gBACnB,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;oBAC/B,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;oBACrB,IAAI,CAAC;wBACH,MAAM,IAAI,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;wBACzC,MAAM,IAAI,GAAG,KAAK,CAAC,cAAe,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;wBAC7C,MAAM,YAAY,GAAG,EAAE,CAAC,SAAS,EAAE,GAAG,sBAAuB,CAAC;wBAC9D,IAAI,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;4BACtC,SAAS;wBACX,CAAC;wBAED,iBAAiB,GAAG,IAAI,CAAC;wBACzB,oBAAoB,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;wBACtC,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC;4BACpD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;4BAC9C,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;wBAC3C,CAAC;wBACD,IAAI,CAAC,mBAAmB,EAAE,CAAC;wBAC3B,MAAM,GAAG,IAAI,CAAC;wBACd,MAAM;oBACR,CAAC;oBAAC,MAAM,CAAC;wBACP,sBAAsB;oBACxB,CAAC;gBACH,CAAC;gBAED,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;oBACrB,mCAAmC;oBACnC,oBAAoB,GAAG,sBAAsB,CAAC;oBAC9C,IAAI,CAAC,mBAAmB,EAAE,CAAC;oBAC3B,OAAO;wBACL,WAAW;wBACX,WAAW;wBACX,QAAQ;wBACR,UAAU;wBACV,SAAS;wBACT,cAAc;wBACd,iBAAiB;wBACjB,UAAU;wBACV,sBAAsB;wBACtB,SAAS;wBACT,MAAM;wBACN,MAAM;wBACN,uBAAuB;wBACvB,sBAAsB;wBACtB,oBAAoB;wBACpB,iBAAiB;wBACjB,gBAAgB,EAAE,EAAE;qBACrB,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,qEAAqE;gBACrE,gBAAgB,GAAG;oBACjB,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE;oBACf,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE;oBACf,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE;iBAChB,CAAC;gBACF,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;YAC3C,CAAC;QACH,CAAC;QAED,0BAA0B;QAC1B,MAAM,gBAAgB,GAAsC,EAAE,CAAC;QAC/D,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YACrB,gBAAgB,CAAC,IAAI,CAAC;gBACpB,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;gBACpB,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;aACrB,CAAC,CAAC;QACL,CAAC;QAED,aAAa;QACb,IAAI,SAA6B,CAAC;QAClC,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YAClB,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO;YACL,WAAW;YACX,WAAW;YACX,QAAQ;YACR,UAAU;YACV,SAAS;YACT,cAAc;YACd,iBAAiB;YACjB,UAAU;YACV,sBAAsB;YACtB,SAAS;YACT,MAAM;YACN,MAAM;YACN,uBAAuB;YACvB,sBAAsB;YACtB,oBAAoB;YACpB,iBAAiB;YACjB,gBAAgB;YAChB,gBAAgB,EACd,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS;YAC5D,SAAS;SACV,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACK,UAAU,CAAC,EAAa;QAC9B,MAAM,gBAAgB,GAAmB,EAAE,CAAC;QAC5C,IAAI,iBAAiB,GAAG,IAAI,CAAC;QAC7B,IAAI,iBAAiB,GAAG,CAAC,CAAC,CAAC;QAE3B,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;YAC1B,IAAI,iBAAiB,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC9B,oEAAoE;gBACpE,mCAAmC;gBACnC,iBAAiB,GAAG,KAAK,CAAC;gBAC1B,MAAM,aAAa,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;gBACpC,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,IAAI,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;oBAChD,MAAM;gBACR,CAAC;YACH,CAAC;iBAAM,IAAI,CAAC,iBAAiB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACtC,IAAI,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;gBAChD,MAAM;YACR,CAAC;iBAAM,IAAI,CAAC,GAAG,EAAE,CAAC;gBAChB,MAAM;YACR,CAAC;YAED,IAAI,cAAkC,CAAC;YACvC,IAAI,sBAA0C,CAAC;YAC/C,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACvB,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;oBAClB,cAAc,GAAG,CAAC,iBAAiB,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;gBAClD,CAAC;qBAAM,CAAC;oBACN,cAAc,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACjC,CAAC;gBACD,iBAAiB,GAAG,cAAc,CAAC;gBACnC,sBAAsB;oBACpB,cAAc,GAAG,CAAC,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,CAAC;gBACxD,IAAI,sBAAsB,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACnD,sBAAsB,IAAI,IAAI,CAAC;gBACjC,CAAC;YACH,CAAC;YAED,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG,kBAAkB,CAAC;YACtE,MAAM,aAAa,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;YAErC,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAC1D,IAAI,UAAkC,CAAC;YAEvC,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;oBACzC,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;oBAC1C,IAAI,CAAC,YAAY,EAAE,CAAC;gBACtB,CAAC;gBAAC,MAAM,CAAC;oBACP,IAAI,CAAC,YAAY,EAAE,CAAC;oBACpB,gBAAgB,CAAC,IAAI,CAAC;wBACpB,OAAO;wBACP,UAAU,EAAE,CAAC,iBAAiB;wBAC9B,cAAc;wBACd,sBAAsB;wBACtB,aAAa;wBACb,WAAW,EAAE,aAAa;wBAC1B,MAAM,EAAE,IAAI;qBACb,CAAC,CAAC;oBACH,OAAO,gBAAgB,CAAC;gBAC1B,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,qCAAqC;gBACrC,gBAAgB,CAAC,IAAI,CAAC;oBACpB,OAAO;oBACP,UAAU,EAAE,CAAC,iBAAiB;oBAC9B,cAAc;oBACd,sBAAsB;oBACtB,aAAa;oBACb,WAAW,EAAE,aAAa;oBAC1B,MAAM,EAAE,IAAI;iBACb,CAAC,CAAC;gBACH,OAAO,gBAAgB,CAAC;YAC1B,CAAC;YAED,MAAM,KAAK,GAAiB;gBAC1B,OAAO;gBACP,UAAU,EAAE,CAAC,iBAAiB;gBAC9B,cAAc;gBACd,sBAAsB;gBACtB,aAAa;gBACb,WAAW,EAAE,EAAE,CAAC,SAAS,EAAE;gBAC3B,UAAU;aACX,CAAC;YAEF,IAAI,iBAAiB,EAAE,CAAC;gBACtB,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC7B,IAAI,UAAU,EAAE,CAAC;oBACf,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC;iBAAM,IAAI,sBAAsB,KAAK,SAAS,EAAE,CAAC;gBAChD,IAAI,CAAC,sBAAsB,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAED,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAEO,sBAAsB,CAC5B,sBAA8B,EAC9B,KAAmB;QAEnB,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,OACE,QAAQ,GAAG,IAAI,CAAC,uBAAuB,CAAC,MAAM;YAC9C,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,sBAAsB;gBAC3D,sBAAsB,EACxB,CAAC;YACD,QAAQ,EAAE,CAAC;QACb,CAAC;QACD,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE;YAC/C,sBAAsB;YACtB,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IAEO,wBAAwB,CAAC,gBAAgC;QAC/D,OACE,IAAI,CAAC,uBAAuB,CAAC,MAAM,GAAG,CAAC;YACvC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,sBAAsB;gBACpD,IAAI,CAAC,gBAAgB,EACvB,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,uBAAuB,CAAC,KAAK,EAAE,CAAC;YACpD,IAAI,CAAC,MAAM;gBAAE,MAAM;YACnB,IAAI,CAAC,gBAAgB,GAAG,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;YAC1D,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACpC,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;gBAC5B,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,qBAAqB,CAAC,UAAsB;QAClD,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC;QAElC,IAAI,SAAS,KAAK,sBAAsB,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;YACnC,oEAAoE;YACpE,kEAAkE;YAClE,qEAAqE;YACrE,qDAAqD;YACrD,mEAAmE;YACnE,mEAAmE;YACnE,4DAA4D;YAC5D,gBAAgB;YAChB,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,mBAAmB,EAAE,CAAC;gBACnE,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YAC5B,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,SAAS,KAAK,wBAAwB,EAAE,CAAC;YAC3C,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;YACzC,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;YACnC,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAClE,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBAC1D,IAAI,CAAC,YAAY,CAAC,WAAW,CAC3B,UAAU,EACV,OAAO,EACP,WAAW,EAAE,IAAI,IAAI,WAAW,OAAO,EAAE,CAC1C,CAAC;YACJ,CAAC;QACH,CAAC;QAED,kEAAkE;QAClE,+DAA+D;QAC/D,IAAI,SAAS,KAAK,mBAAmB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC/D,MAAM,OAAO,GAAG,UAAmC,CAAC;YACpD,IAAI,OAAO,CAAC,aAAa,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAClE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;YACrE,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,UAAU,CAAC,EAAa,EAAE,SAAiB;QACjD,MAAM,MAAM,GAAkB,EAAE,CAAC;QAEjC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAEjC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YACrB,8DAA8D;YAC9D,iEAAiE;YACjE,+DAA+D;YAC/D,8CAA8C;YAC9C,IAAI,EAAE,CAAC,OAAO,EAAE;gBAAE,MAAM;YAExB,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAEjC,sEAAsE;YACtE,uEAAuE;YACvE,mEAAmE;YACnE,6CAA6C;YAC7C,IAAI,EAAE,CAAC,OAAO,EAAE;gBAAE,MAAM;YAExB,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAClB,yBAAyB;gBACzB,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;gBACrC,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,MAAM,CAAC,IAAI,CAAC;oBACV,KAAK;oBACL,IAAI,EAAE,QAAQ;oBACd,eAAe,EAAE,EAAE,CAAC,SAAS,EAAE;oBAC/B,aAAa,EAAE,EAAE,CAAC,SAAS,EAAE;iBAC9B,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACjD,IAAI,OAA2B,CAAC;YAEhC,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,qBAAqB,CAAC,GAAG,mBAAmB,CAAC;YACpE,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;YACvD,CAAC;YAED,MAAM,eAAe,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;YACvC,MAAM,WAAW,GACf,OAAO,KAAK,SAAS;gBACnB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC;gBACvC,CAAC,CAAC,SAAS,CAAC;YAEhB,sEAAsE;YACtE,wEAAwE;YACxE,0EAA0E;YAC1E,qEAAqE;YACrE,mEAAmE;YACnE,oEAAoE;YACpE,IAAI,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC1B,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC7B,WAAW,CACT,oEAAoE;oBAClE,0FAA0F,EAC5F,IAAI,CAAC,aAAa,EAClB,SAAS,EACT,KAAK,EACL,OAAO,EACP,eAAe,EACf,EAAE,CAAC,SAAS,EAAE,EACd,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CACzB,CAAC;gBACF,MAAM,CAAC,IAAI,CAAC;oBACV,KAAK;oBACL,IAAI,EAAE,QAAQ;oBACd,OAAO;oBACP,eAAe;oBACf,aAAa,EAAE,eAAe;iBAC/B,CAAC,CAAC;gBACH,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,IAAI,MAAM,GAAG,KAAK,CAAC;YAEnB,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;oBACzC,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;oBAC/B,MAAM,UAAU,GAAG,WAAW,CAAC,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;oBAC7D,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;oBAE9B,IAAI,KAAK,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;wBACnC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;wBAChE,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBAC5B,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBAC5B,CAAC;oBAED,MAAM,CAAC,IAAI,CAAC;wBACV,KAAK;wBACL,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;wBACjC,OAAO;wBACP,eAAe;wBACf,aAAa,EAAE,MAAM;wBACrB,UAAU;qBACX,CAAC,CAAC;oBACH,MAAM,GAAG,IAAI,CAAC;gBAChB,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,IAAI,CAAC,YAAY,EAAE,CAAC;oBACpB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;oBACvC,MAAM,OAAO,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;oBAC3D,WAAW,CACT,0FAA0F,EAC1F,IAAI,CAAC,aAAa,EAClB,SAAS,EACT,MAAM,CAAC,MAAM,EACb,KAAK,EACL,EAAE,EACF,OAAO,EACP,WAAW,CAAC,IAAI,EAChB,eAAe,EACf,EAAE,CAAC,SAAS,EAAE,EACd,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,EACxB,OAAO,CACR,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,IAAI,MAAM;gBAAE,SAAS;YAErB,WAAW,CACT,gEAAgE,EAChE,IAAI,CAAC,aAAa,EAClB,SAAS,EACT,KAAK,EACL,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAC3B,OAAO,EACP,WAAW,EAAE,IAAI,IAAI,MAAM,EAC3B,eAAe,EACf,EAAE,CAAC,SAAS,EAAE,CACf,CAAC;YAEF,mDAAmD;YACnD,MAAM,CAAC,IAAI,CAAC;gBACV,KAAK;gBACL,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;gBACjC,OAAO;gBACP,eAAe;gBACf,aAAa,EAAE,eAAe;aAC/B,CAAC,CAAC;YACH,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,cAAc;QACpB,OAAO;YACL,WAAW,EAAE,CAAC;YACd,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,KAAK;SACd,CAAC;IACJ,CAAC;CACF","sourcesContent":["import createDebug from \"debug\";\nimport { BitStream } from \"./BitStream.js\";\nimport {\n DataPacket,\n MaxGhostCount,\n GhostMsgEndGhosting,\n NetEventClassBitSize,\n NetEventClassFirst,\n NetObjectClassBitSize,\n NetObjectClassFirst,\n} from \"./types.js\";\n\nconst debugGhosts = createDebug(\"t2-demo-parser:ghosts\");\nimport type {\n ConnectionProtocolState,\n DnetHeader,\n RateInfo,\n GameState,\n PacketData,\n NetEventInfo,\n GhostUpdate,\n} from \"./types.js\";\nimport type {\n ClassRegistry,\n ConnectionContext,\n GhostParserEntry,\n ParsedData,\n} from \"./ClassRegistry.js\";\nimport type { EventData, SimDataBlockEventData } from \"./eventDataTypes.js\";\nimport type { GhostTracker } from \"./GhostManager.js\";\n\n/**\n * Parses individual network packets from demo recording blocks.\n *\n * Packet layout (from the server connection perspective):\n * 1. dnet header (processRawPacket)\n * 2. Rate info (handlePacket)\n * 3. GameConnection::readPacket — game state, moves, etc.\n * 4. NetConnection::readPacket — events, then ghosts\n */\nexport class PacketParser {\n private registry: ClassRegistry;\n private ghostTracker: GhostTracker;\n private compressionPoint = { x: 0, y: 0, z: 0 };\n private dataBlockDataMap?: Map<number, ParsedData>;\n private lastSeqRecvdAtSend = new Array<number>(32).fill(0);\n private lastSeqRecvd = 0;\n private highestAckedSeq = 0;\n private lastSendSeq = 0;\n private recvAckMask = 0;\n private connectSequence = 0;\n private lastRecvAckAck = 0;\n private _connectionEstablished = false;\n private nextRecvEventSeq = 0;\n private pendingGuaranteedEvents: Array<{\n absoluteSequenceNumber: number;\n event: NetEventInfo;\n }> = [];\n\n // Stats\n controlObjectParsed = 0;\n controlObjectFailed = 0;\n eventsParsed = 0;\n eventsFailed = 0;\n ghostCreatesParsed = 0;\n ghostUpdatesParsed = 0;\n ghostDeletes = 0;\n ghostsFailed = 0;\n /** Ghosts where our tracker says \"new\" but the classId is unregistered.\n * This indicates a tracker divergence: the server sent UPDATE data\n * (no classId prefix) for a ghost we don't have, so we misread the\n * first 7 bits of update data as a classId. */\n ghostsTrackerDiverged = 0;\n packetsParsed = 0;\n protocolRejected = 0;\n protocolNoDispatch = 0;\n\n constructor(\n registry: ClassRegistry,\n ghostTracker: GhostTracker,\n options?: {\n dataBlockDataMap?: Map<number, ParsedData>;\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 },\n ) {\n this.registry = registry;\n this.ghostTracker = ghostTracker;\n this.dataBlockDataMap = options?.dataBlockDataMap;\n if (options?.connectionProtocolState) {\n this.setConnectionProtocolState(options.connectionProtocolState);\n }\n if (typeof options?.nextRecvEventSeq === \"number\") {\n this.nextRecvEventSeq = options.nextRecvEventSeq >>> 0;\n }\n if (options?.compressionPoint) {\n this.compressionPoint = { ...options.compressionPoint };\n }\n if (options?.pendingGuaranteedEvents) {\n this.pendingGuaranteedEvents = options.pendingGuaranteedEvents\n .map((entry) => ({ ...entry }))\n .sort((a, b) => a.absoluteSequenceNumber - b.absoluteSequenceNumber);\n }\n }\n\n getCompressionPoint(): { x: number; y: number; z: number } {\n return this.compressionPoint;\n }\n\n getDataBlockDataMap(): Map<number, ParsedData> | undefined {\n return this.dataBlockDataMap;\n }\n\n private getConnectionContext(): ConnectionContext {\n const dbMap = this.dataBlockDataMap;\n return {\n compressionPoint: this.compressionPoint,\n ghostTracker: this.ghostTracker,\n getDataBlockParser: (classId: number) =>\n this.registry.getDataBlockParser(classId),\n getDataBlockData: dbMap\n ? (objectId: number) => dbMap.get(objectId)\n : undefined,\n getGhostParser: (classId: number) =>\n this.registry.getGhostParser(classId),\n };\n }\n\n private _setNextRecvEventSeq(nextRecvEventSeq: number): void {\n this.nextRecvEventSeq = nextRecvEventSeq >>> 0;\n }\n\n setConnectionProtocolState(state: ConnectionProtocolState): void {\n this.lastSeqRecvdAtSend = state.lastSeqRecvdAtSend.slice(0, 32);\n while (this.lastSeqRecvdAtSend.length < 32) {\n this.lastSeqRecvdAtSend.push(0);\n }\n this.lastSeqRecvd = state.lastSeqRecvd >>> 0;\n this.highestAckedSeq = state.highestAckedSeq >>> 0;\n this.lastSendSeq = state.lastSendSeq >>> 0;\n this.recvAckMask = state.ackMask >>> 0;\n this.connectSequence = state.connectSequence >>> 0;\n this.lastRecvAckAck = state.lastRecvAckAck >>> 0;\n this._connectionEstablished = state.connectionEstablished;\n }\n\n /**\n * Export the current protocol window state. Together with\n * `getNextRecvEventSeq`, `getPendingGuaranteedEvents`,\n * `getCompressionPoint`, `getDataBlockDataMap`, and the ghost tracker\n * contents, this captures all cross-packet parser state, so an\n * identically seeded parser continues the stream in lockstep.\n */\n getConnectionProtocolState(): ConnectionProtocolState {\n return {\n lastSeqRecvdAtSend: this.lastSeqRecvdAtSend.slice(),\n lastSeqRecvd: this.lastSeqRecvd,\n highestAckedSeq: this.highestAckedSeq,\n lastSendSeq: this.lastSendSeq,\n ackMask: this.recvAckMask,\n connectSequence: this.connectSequence,\n lastRecvAckAck: this.lastRecvAckAck,\n connectionEstablished: this._connectionEstablished,\n };\n }\n\n getNextRecvEventSeq(): number {\n return this.nextRecvEventSeq;\n }\n\n getPendingGuaranteedEvents(): Array<{\n absoluteSequenceNumber: number;\n event: NetEventInfo;\n }> {\n return this.pendingGuaranteedEvents.map((entry) => ({ ...entry }));\n }\n\n /**\n * Emulate ConnectionProtocol::buildSendPacketHeader (FUN_0043d2d0, data path).\n * Demo block type 1 indicates a local send-packet trigger.\n */\n onSendPacketTrigger(): void {\n this.lastSendSeq = (this.lastSendSeq + 1) >>> 0;\n this.lastSeqRecvdAtSend[this.lastSendSeq & 0x1f] = this.lastSeqRecvd >>> 0;\n }\n\n /**\n * Emulates ConnectionProtocol::processRawPacket (FUN_0043d4d0).\n * A packet may be syntactically valid but still ignored for game payload\n * dispatch due to sequence/connect-window checks or duplicate seq numbers.\n */\n private applyProtocolHeader(dnetHeader: DnetHeader): {\n accepted: boolean;\n dispatchData: boolean;\n } {\n if (dnetHeader.connectSeqBit !== (this.connectSequence & 1)) {\n return { accepted: false, dispatchData: false };\n }\n if (dnetHeader.ackByteCount > 4 || dnetHeader.packetType > 2) {\n return { accepted: false, dispatchData: false };\n }\n\n let seqNumber =\n (dnetHeader.seqNumber | (this.lastSeqRecvd & 0xffff_fe00)) >>> 0;\n if (seqNumber < this.lastSeqRecvd) {\n seqNumber = (seqNumber + 0x200) >>> 0;\n }\n if (this.lastSeqRecvd + 0x1f < seqNumber) {\n return { accepted: false, dispatchData: false };\n }\n\n let highestAck =\n (dnetHeader.highestAck | (this.highestAckedSeq & 0xffff_fe00)) >>> 0;\n if (highestAck < this.highestAckedSeq) {\n highestAck = (highestAck + 0x200) >>> 0;\n }\n if (this.lastSendSeq < highestAck) {\n return { accepted: false, dispatchData: false };\n }\n\n const seqShift = (seqNumber - this.lastSeqRecvd) & 0x1f;\n this.recvAckMask = (this.recvAckMask << seqShift) >>> 0;\n if (dnetHeader.packetType === DataPacket) {\n this.recvAckMask = (this.recvAckMask | 1) >>> 0;\n }\n\n for (\n let ackSeq = this.highestAckedSeq + 1;\n ackSeq <= highestAck;\n ackSeq++\n ) {\n const isAcked =\n (dnetHeader.ackMask & (1 << ((highestAck - ackSeq) & 0x1f))) !== 0;\n if (isAcked) {\n this.lastRecvAckAck = this.lastSeqRecvdAtSend[ackSeq & 0x1f] >>> 0;\n }\n }\n if (seqNumber - this.lastRecvAckAck > 0x20) {\n this.lastRecvAckAck = seqNumber - 0x20;\n }\n this.highestAckedSeq = highestAck;\n\n const dispatchData =\n this.lastSeqRecvd !== seqNumber && dnetHeader.packetType === DataPacket;\n this.lastSeqRecvd = seqNumber;\n\n return { accepted: true, dispatchData };\n }\n\n parsePacket(data: Uint8Array): PacketData {\n const bs = new BitStream(data);\n\n // 1. Parse dnet header\n const dnetHeader = this.readDnetHeader(bs);\n const protocol = this.applyProtocolHeader(dnetHeader);\n\n this.packetsParsed++;\n\n // ConnectionProtocol may reject this packet entirely (window/connect checks),\n // or accept it but suppress game dispatch (duplicate seq / non-data packet).\n if (!protocol.accepted) {\n this.protocolRejected++;\n return {\n dnetHeader,\n rateInfo: {},\n gameState: this.emptyGameState(),\n events: [],\n ghosts: [],\n };\n }\n if (!protocol.dispatchData) {\n this.protocolNoDispatch++;\n return {\n dnetHeader,\n rateInfo: {},\n gameState: this.emptyGameState(),\n events: [],\n ghosts: [],\n };\n }\n\n // 2. Rate info (NetConnection::handlePacket)\n const rateInfo = this.readRateInfo(bs);\n\n // 3. Game state (GameConnection::readPacket — server connection path)\n bs.setStringBuffer(true);\n const gameState = this.readGameState(bs);\n\n // Only read events/ghosts if game state completed successfully.\n // When game state bails (control object dirty with no parser), the\n // stream position is wrong and we'd read garbage data.\n const gameStateComplete =\n gameState.controlObjectDataStart === undefined ||\n gameState.controlObjectData !== undefined;\n\n // 4. Events (NetConnection::readPacket -> eventReadPacket)\n const events = gameStateComplete ? this.readEvents(bs) : [];\n\n // Only read ghosts if all events were successfully parsed.\n // When an event can't be parsed, readEvents returns early and the\n // stream position is wrong — reading ghosts would produce garbage.\n const lastEvent = events[events.length - 1];\n const eventsComplete = !lastEvent?.failed;\n\n // 5. Ghosts (NetConnection::readPacket -> ghostReadPacket)\n const ghostSectionStart =\n gameStateComplete && eventsComplete ? bs.getCurPos() : undefined;\n const ghosts =\n gameStateComplete && eventsComplete\n ? this.readGhosts(bs, dnetHeader.seqNumber)\n : [];\n\n bs.setStringBuffer(false);\n\n return {\n dnetHeader,\n rateInfo,\n gameState,\n events,\n ghosts,\n ghostSectionStart,\n };\n }\n\n /**\n * Parse the dnet packet header (from processRawPacket in dnet.cc).\n */\n private readDnetHeader(bs: BitStream): DnetHeader {\n const gameFlag = bs.readFlag();\n const connectSeqBit = bs.readInt(1);\n const seqNumber = bs.readInt(9);\n const highestAck = bs.readInt(9);\n const packetType = bs.readInt(2);\n const ackByteCount = bs.readInt(3);\n const ackMask = ackByteCount > 0 ? bs.readInt(8 * ackByteCount) : 0;\n\n return {\n gameFlag,\n connectSeqBit,\n seqNumber,\n highestAck,\n packetType,\n ackByteCount,\n ackMask,\n };\n }\n\n /**\n * Parse rate info from handlePacket in netConnection.cc.\n */\n private readRateInfo(bs: BitStream): RateInfo {\n const info: RateInfo = {};\n if (bs.readFlag()) {\n info.updateDelay = bs.readInt(10);\n info.packetSize = bs.readInt(10);\n }\n if (bs.readFlag()) {\n info.maxUpdateDelay = bs.readInt(10);\n info.maxPacketSize = bs.readInt(10);\n }\n return info;\n }\n\n /**\n * Parse game state from GameConnection::readPacket (server connection path).\n */\n private readGameState(bs: BitStream): GameState {\n const lastMoveAck = bs.readInt(32);\n\n // Damage flash / whiteout\n let damageFlash: number | undefined;\n let whiteOut: number | undefined;\n if (bs.readFlag()) {\n if (bs.readFlag()) {\n damageFlash = bs.readFloat(7);\n }\n if (bs.readFlag()) {\n whiteOut = bs.readFloat(7) * 1.5;\n }\n }\n\n // Lock/homing state\n let selfLocked: boolean | undefined;\n let selfHomed: boolean | undefined;\n if (bs.readFlag()) {\n selfLocked = bs.readFlag();\n selfHomed = bs.readFlag();\n }\n\n // Seeker tracking state\n let seekerTracking: boolean | undefined;\n let seekerTrackingPos: { x: number; y: number; z: number } | undefined;\n let seekerMode: number | undefined;\n let seekerObjectGhostIndex: number | undefined;\n let targetPos: { x: number; y: number; z: number } | undefined;\n if (bs.readFlag()) {\n seekerTracking = bs.readFlag();\n // Binary 0x005fc020: when seekerTracking is true, reads 3×F32 (Point3F)\n // for the seeker target position (stored at connection+0x8454)\n if (seekerTracking) {\n seekerTrackingPos = {\n x: bs.readF32(),\n y: bs.readF32(),\n z: bs.readF32(),\n };\n }\n seekerMode = bs.readRangedU32(0, 2);\n if (seekerMode === 1) {\n if (bs.readFlag()) {\n seekerObjectGhostIndex = bs.readRangedU32(0, MaxGhostCount - 1);\n }\n } else if (seekerMode === 2) {\n targetPos = {\n x: bs.readF32(),\n y: bs.readF32(),\n z: bs.readF32(),\n };\n }\n }\n\n // Sensor ping/jam flags\n const pinged = bs.readFlag();\n const jammed = bs.readFlag();\n\n // Control object state\n let controlObjectGhostIndex: number | undefined;\n let controlObjectDataStart: number | undefined;\n let controlObjectDataEnd: number | undefined;\n let controlObjectData: ParsedData | undefined;\n let compressionPoint: { x: number; y: number; z: number } | undefined;\n\n if (bs.readFlag()) {\n if (bs.readFlag()) {\n // Control object is dirty — full update via readPacketData.\n // In Tribes 2 (build 25034), only Player and Camera override\n // writePacketData/readPacketData, so the control object is\n // always one of these two classes. We try candidates in order:\n // 1. Tracker classId (may be stale due to ghost index recycling)\n // 2. Player (classId 25) — the normal control object\n // 3. Camera (classId 4) — spectator mode\n // The candidate order must be a pure function of seeded state\n // (the tracker) so that a parser seeded mid-stream makes the same\n // choice as one that has followed the stream from the start —\n // no history-derived caches here.\n const gIndex = bs.readInt(10);\n controlObjectGhostIndex = gIndex;\n controlObjectDataStart = bs.getCurPos();\n const start = bs.savePos();\n const ghost = this.ghostTracker.getGhost(gIndex);\n\n const preferredEntry = ghost\n ? this.registry.getGhostParser(ghost.classId)\n : undefined;\n const playerEntry = this.registry.getGhostParser(25); // Player\n const cameraEntry = this.registry.getGhostParser(4); // Camera\n\n // Build candidate list (deduplicated, only those with readPacketData)\n const candidates: GhostParserEntry[] = [];\n const seen = new Set<string>();\n const addCandidate = (entry: GhostParserEntry | undefined): void => {\n if (!entry?.readPacketData) return;\n if (seen.has(entry.name)) return;\n seen.add(entry.name);\n candidates.push(entry);\n };\n addCandidate(preferredEntry);\n addCandidate(playerEntry);\n addCandidate(cameraEntry);\n\n let parsed = false;\n for (const entry of candidates) {\n bs.restorePos(start);\n try {\n const conn = this.getConnectionContext();\n const data = entry.readPacketData!(bs, conn);\n const bitsConsumed = bs.getCurPos() - controlObjectDataStart!;\n if (bitsConsumed <= 0 || bs.isError()) {\n continue;\n }\n\n controlObjectData = data;\n controlObjectDataEnd = bs.getCurPos();\n if (conn.compressionPoint !== this.compressionPoint) {\n this.compressionPoint = conn.compressionPoint;\n compressionPoint = this.compressionPoint;\n }\n this.controlObjectParsed++;\n parsed = true;\n break;\n } catch {\n // Try next candidate.\n }\n }\n\n if (!parsed) {\n bs.restorePos(start);\n // No parser — bail from game state\n controlObjectDataEnd = controlObjectDataStart;\n this.controlObjectFailed++;\n return {\n lastMoveAck,\n damageFlash,\n whiteOut,\n selfLocked,\n selfHomed,\n seekerTracking,\n seekerTrackingPos,\n seekerMode,\n seekerObjectGhostIndex,\n targetPos,\n pinged,\n jammed,\n controlObjectGhostIndex,\n controlObjectDataStart,\n controlObjectDataEnd,\n controlObjectData,\n targetVisibility: [],\n };\n }\n } else {\n // Compression point update — always accept (engine doesn't validate)\n compressionPoint = {\n x: bs.readF32(),\n y: bs.readF32(),\n z: bs.readF32(),\n };\n this.compressionPoint = compressionPoint;\n }\n }\n\n // Target visibility masks\n const targetVisibility: { index: number; mask: number }[] = [];\n while (bs.readFlag()) {\n targetVisibility.push({\n index: bs.readInt(4),\n mask: bs.readInt(32),\n });\n }\n\n // Camera FOV\n let cameraFov: number | undefined;\n if (bs.readFlag()) {\n cameraFov = bs.readInt(8);\n }\n\n return {\n lastMoveAck,\n damageFlash,\n whiteOut,\n selfLocked,\n selfHomed,\n seekerTracking,\n seekerTrackingPos,\n seekerMode,\n seekerObjectGhostIndex,\n targetPos,\n pinged,\n jammed,\n controlObjectGhostIndex,\n controlObjectDataStart,\n controlObjectDataEnd,\n controlObjectData,\n compressionPoint,\n targetVisibility:\n targetVisibility.length > 0 ? targetVisibility : undefined,\n cameraFov,\n };\n }\n\n /**\n * Parse events from eventReadPacket in netEvent.cc.\n *\n * Two phases:\n * 1. Unguaranteed events: while(readFlag) { classId(6b) + unpack }\n * 2. Guaranteed events: while(readFlag) { seqFlag(1b), [seq(7b)], classId(6b) + unpack }\n */\n private readEvents(bs: BitStream): NetEventInfo[] {\n const dispatchedEvents: NetEventInfo[] = [];\n let unguaranteedPhase = true;\n let prevGuaranteedSeq = -2;\n\n while (true) {\n const bit = bs.readFlag();\n if (unguaranteedPhase && !bit) {\n // Transition to guaranteed phase. Binary immediately reads one more\n // continuation bit for that phase.\n unguaranteedPhase = false;\n const guaranteedBit = bs.readFlag();\n if (!guaranteedBit) {\n this.dispatchGuaranteedEvents(dispatchedEvents);\n break;\n }\n } else if (!unguaranteedPhase && !bit) {\n this.dispatchGuaranteedEvents(dispatchedEvents);\n break;\n } else if (!bit) {\n break;\n }\n\n let sequenceNumber: number | undefined;\n let absoluteSequenceNumber: number | undefined;\n if (!unguaranteedPhase) {\n if (bs.readFlag()) {\n sequenceNumber = (prevGuaranteedSeq + 1) & 0x7f;\n } else {\n sequenceNumber = bs.readInt(7);\n }\n prevGuaranteedSeq = sequenceNumber;\n absoluteSequenceNumber =\n sequenceNumber | (this.nextRecvEventSeq & 0xffffff80);\n if (absoluteSequenceNumber < this.nextRecvEventSeq) {\n absoluteSequenceNumber += 0x80;\n }\n }\n\n const classId = bs.readInt(NetEventClassBitSize) + NetEventClassFirst;\n const dataBitsStart = bs.getCurPos();\n\n const parserEntry = this.registry.getEventParser(classId);\n let parsedData: ParsedData | undefined;\n\n if (parserEntry) {\n try {\n const conn = this.getConnectionContext();\n parsedData = parserEntry.unpack(bs, conn);\n this.eventsParsed++;\n } catch {\n this.eventsFailed++;\n dispatchedEvents.push({\n classId,\n guaranteed: !unguaranteedPhase,\n sequenceNumber,\n absoluteSequenceNumber,\n dataBitsStart,\n dataBitsEnd: dataBitsStart,\n failed: true,\n });\n return dispatchedEvents;\n }\n } else {\n // No parser — cannot advance safely.\n dispatchedEvents.push({\n classId,\n guaranteed: !unguaranteedPhase,\n sequenceNumber,\n absoluteSequenceNumber,\n dataBitsStart,\n dataBitsEnd: dataBitsStart,\n failed: true,\n });\n return dispatchedEvents;\n }\n\n const event: NetEventInfo = {\n classId,\n guaranteed: !unguaranteedPhase,\n sequenceNumber,\n absoluteSequenceNumber,\n dataBitsStart,\n dataBitsEnd: bs.getCurPos(),\n parsedData,\n };\n\n if (unguaranteedPhase) {\n dispatchedEvents.push(event);\n if (parsedData) {\n this.applyEventSideEffects(parsedData);\n }\n } else if (absoluteSequenceNumber !== undefined) {\n this.enqueueGuaranteedEvent(absoluteSequenceNumber, event);\n }\n }\n\n return dispatchedEvents;\n }\n\n private enqueueGuaranteedEvent(\n absoluteSequenceNumber: number,\n event: NetEventInfo,\n ): void {\n let insertAt = 0;\n while (\n insertAt < this.pendingGuaranteedEvents.length &&\n this.pendingGuaranteedEvents[insertAt].absoluteSequenceNumber <\n absoluteSequenceNumber\n ) {\n insertAt++;\n }\n this.pendingGuaranteedEvents.splice(insertAt, 0, {\n absoluteSequenceNumber,\n event,\n });\n }\n\n private dispatchGuaranteedEvents(dispatchedEvents: NetEventInfo[]): void {\n while (\n this.pendingGuaranteedEvents.length > 0 &&\n this.pendingGuaranteedEvents[0].absoluteSequenceNumber ===\n this.nextRecvEventSeq\n ) {\n const queued = this.pendingGuaranteedEvents.shift();\n if (!queued) break;\n this.nextRecvEventSeq = (this.nextRecvEventSeq + 1) >>> 0;\n dispatchedEvents.push(queued.event);\n if (queued.event.parsedData) {\n this.applyEventSideEffects(queued.event.parsedData);\n }\n }\n }\n\n /**\n * Apply event side effects that alter ghost index state.\n * These effects occur before ghostReadPacket on the same packet.\n */\n private applyEventSideEffects(parsedData: ParsedData): void {\n const eventType = parsedData.type;\n\n if (eventType === \"GhostingMessageEvent\") {\n const message = parsedData.message;\n // Tribes 2 handleGhostMessage EndGhosting (netGhost.cc:706) deletes\n // ONLY local ghosts. Datablocks are connection-lifetime state and\n // must be retained: the server's transmitDataBlocks skips datablocks\n // already sent on this connection (gameConnection.cc\n // cTransmitDataBlocks: only modifiedKey > mDataBlockModifiedKey is\n // re-sent), so on a mission change most datablocks are NOT re-sent\n // and clearing the map here leaves the new mission's ghosts\n // unresolvable.\n if (typeof message === \"number\" && message === GhostMsgEndGhosting) {\n this.ghostTracker.clear();\n }\n return;\n }\n\n if (eventType === \"GhostAlwaysObjectEvent\") {\n const ghostIndex = parsedData.ghostIndex;\n const classId = parsedData.classId;\n if (typeof ghostIndex === \"number\" && typeof classId === \"number\") {\n const parserEntry = this.registry.getGhostParser(classId);\n this.ghostTracker.createGhost(\n ghostIndex,\n classId,\n parserEntry?.name ?? `unknown_${classId}`,\n );\n }\n }\n\n // SimDataBlockEvent: accumulate parsed DataBlock data by objectId\n // (exported for seeding and consumed by downstream renderers).\n if (eventType === \"SimDataBlockEvent\" && this.dataBlockDataMap) {\n const dbEvent = parsedData as SimDataBlockEventData;\n if (dbEvent.dataBlockData && typeof dbEvent.objectId === \"number\") {\n this.dataBlockDataMap.set(dbEvent.objectId, dbEvent.dataBlockData);\n }\n }\n }\n\n /**\n * Parse ghosts from ghostReadPacket in netGhost.cc.\n */\n private readGhosts(bs: BitStream, seqNumber: number): GhostUpdate[] {\n const ghosts: GhostUpdate[] = [];\n\n if (!bs.readFlag()) {\n return ghosts;\n }\n\n const idSize = bs.readInt(3) + 3;\n\n while (bs.readFlag()) {\n // If the stream ran out of data during the moreFlag read, the\n // readFlag returned false (terminating the loop) with error set.\n // Check here for the case where readFlag returned true but the\n // subsequent header reads exhaust the stream.\n if (bs.isError()) break;\n\n const index = bs.readInt(idSize);\n\n // If the stream ran out of data during header reads, stop processing.\n // Without this check, exhausted reads return 0 (defaulting index to 0,\n // classId to 0) and the ghost parser runs on empty data, producing\n // a \"successful\" parse that consumed 0 bits.\n if (bs.isError()) break;\n\n if (bs.readFlag()) {\n // Ghost is being deleted\n this.ghostTracker.deleteGhost(index);\n this.ghostDeletes++;\n ghosts.push({\n index,\n type: \"delete\",\n updateBitsStart: bs.getCurPos(),\n updateBitsEnd: bs.getCurPos(),\n });\n continue;\n }\n\n const isNew = !this.ghostTracker.hasGhost(index);\n let classId: number | undefined;\n\n if (isNew) {\n classId = bs.readInt(NetObjectClassBitSize) + NetObjectClassFirst;\n } else {\n classId = this.ghostTracker.getGhost(index)?.classId;\n }\n\n const updateBitsStart = bs.getCurPos();\n const parserEntry =\n classId !== undefined\n ? this.registry.getGhostParser(classId)\n : undefined;\n\n // Detect tracker divergence: we think this is a new ghost (not in our\n // tracker) but the classId is unregistered. This almost certainly means\n // the server sent UPDATE data (no classId prefix) for a ghost our tracker\n // lost, and we misread the first 7 bits of update data as a classId.\n // This is engine-consistent — the real client would also fail here\n // because classId lookup would return NULL, triggering packet drop.\n if (isNew && !parserEntry) {\n this.ghostsTrackerDiverged++;\n debugGhosts(\n \"DIVERGED pkt=%d seq=%d idx=%d classId=%d bit=%d/%d trackerSize=%d \" +\n \"(server sent UPDATE for ghost not in our tracker; 7-bit classId is actually update data)\",\n this.packetsParsed,\n seqNumber,\n index,\n classId,\n updateBitsStart,\n bs.getMaxPos(),\n this.ghostTracker.size(),\n );\n ghosts.push({\n index,\n type: \"create\",\n classId,\n updateBitsStart,\n updateBitsEnd: updateBitsStart,\n });\n return ghosts;\n }\n\n let parsed = false;\n\n if (parserEntry) {\n try {\n const conn = this.getConnectionContext();\n conn.currentGhostIndex = index;\n const parsedData = parserEntry.unpackUpdate(bs, isNew, conn);\n const endPos = bs.getCurPos();\n\n if (isNew && classId !== undefined) {\n this.ghostTracker.createGhost(index, classId, parserEntry.name);\n this.ghostCreatesParsed++;\n } else {\n this.ghostUpdatesParsed++;\n }\n\n ghosts.push({\n index,\n type: isNew ? \"create\" : \"update\",\n classId,\n updateBitsStart,\n updateBitsEnd: endPos,\n parsedData,\n });\n parsed = true;\n } catch (e) {\n this.ghostsFailed++;\n const op = isNew ? \"create\" : \"update\";\n const message = e instanceof Error ? e.message : String(e);\n debugGhosts(\n \"FAIL pkt=%d seq=%d #%d idx=%d op=%s classId=%d parser=%s bit=%d/%d trackerSize=%d err=%s\",\n this.packetsParsed,\n seqNumber,\n ghosts.length,\n index,\n op,\n classId,\n parserEntry.name,\n updateBitsStart,\n bs.getMaxPos(),\n this.ghostTracker.size(),\n message,\n );\n }\n }\n\n if (parsed) continue;\n\n debugGhosts(\n \"STOP pkt=%d seq=%d idx=%d op=%s classId=%d parser=%s bit=%d/%d\",\n this.packetsParsed,\n seqNumber,\n index,\n isNew ? \"create\" : \"update\",\n classId,\n parserEntry?.name ?? \"NONE\",\n updateBitsStart,\n bs.getMaxPos(),\n );\n\n // Record and stop — can't parse this ghost's data.\n ghosts.push({\n index,\n type: isNew ? \"create\" : \"update\",\n classId,\n updateBitsStart,\n updateBitsEnd: updateBitsStart,\n });\n return ghosts;\n }\n\n return ghosts;\n }\n\n private emptyGameState(): GameState {\n return {\n lastMoveAck: 0,\n pinged: false,\n jammed: false,\n };\n }\n}\n"]}
|
|
@@ -194,8 +194,9 @@ export interface PlayerDataBlock extends ShapeBaseDataBlock {
|
|
|
194
194
|
groundImpactShakeAmp?: Vec3;
|
|
195
195
|
groundImpactShakeDuration?: number;
|
|
196
196
|
groundImpactShakeFalloff?: number;
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
/** Heat signature rates (Tribes 2; retail player.cs: 1/4 and 1/3). */
|
|
198
|
+
heatDecayPerSec?: number;
|
|
199
|
+
heatIncreasePerSec?: number;
|
|
199
200
|
}
|
|
200
201
|
export interface VehicleDataBlock extends ShapeBaseDataBlock {
|
|
201
202
|
bodyRestitution?: number;
|
|
@@ -599,8 +600,8 @@ export interface DebrisDataBlock extends GameBaseDataBlock {
|
|
|
599
600
|
gravModifier?: number;
|
|
600
601
|
terminalVelocity?: number;
|
|
601
602
|
ignoreWater?: boolean;
|
|
602
|
-
|
|
603
|
-
|
|
603
|
+
texture?: string;
|
|
604
|
+
shapeName?: string;
|
|
604
605
|
emitter0?: number | null;
|
|
605
606
|
emitter1?: number | null;
|
|
606
607
|
explosion?: number | null;
|
|
@@ -722,12 +723,12 @@ export interface AudioEnvironmentDataBlock extends SimDataBlock {
|
|
|
722
723
|
reflectionsDelay?: number;
|
|
723
724
|
reverbDelay?: number;
|
|
724
725
|
roomVolume?: number;
|
|
725
|
-
effectVolume?: number;
|
|
726
726
|
damping?: number;
|
|
727
727
|
environmentSize?: number;
|
|
728
728
|
environmentDiffusion?: number;
|
|
729
|
+
airAbsorption?: number;
|
|
730
|
+
effectVolume?: number;
|
|
729
731
|
flags?: number;
|
|
730
|
-
effectVolumeHF?: number;
|
|
731
732
|
}
|
|
732
733
|
export interface AudioSampleEnvironmentDataBlock extends SimDataBlock {
|
|
733
734
|
direct?: number;
|
|
@@ -829,17 +830,17 @@ export interface StationFXVehicleDataBlock extends SimDataBlock {
|
|
|
829
830
|
sphereThetaSegments?: number;
|
|
830
831
|
sphereRadius?: number;
|
|
831
832
|
scale?: Vec3;
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
833
|
+
glowNodeName?: string;
|
|
834
|
+
leftNodeName0?: string;
|
|
835
|
+
rightNodeName0?: string;
|
|
836
|
+
leftNodeName1?: string;
|
|
837
|
+
rightNodeName1?: string;
|
|
838
|
+
leftNodeName2?: string;
|
|
839
|
+
rightNodeName2?: string;
|
|
840
|
+
leftNodeName3?: string;
|
|
841
|
+
rightNodeName3?: string;
|
|
842
|
+
texture0?: string;
|
|
843
|
+
texture1?: string;
|
|
843
844
|
}
|
|
844
845
|
export interface StationFXPersonalDataBlock extends SimDataBlock {
|
|
845
846
|
glowTopRadius?: number;
|
|
@@ -852,10 +853,10 @@ export interface StationFXPersonalDataBlock extends SimDataBlock {
|
|
|
852
853
|
bottomAlpha?: number;
|
|
853
854
|
glowSpeed?: number;
|
|
854
855
|
scrollSpeed?: number;
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
856
|
+
leftNodeName?: string;
|
|
857
|
+
rightNodeName?: string;
|
|
858
|
+
texture0?: string;
|
|
859
|
+
texture1?: string;
|
|
859
860
|
}
|
|
860
861
|
export interface CannedChatItemDataBlock extends SimDataBlock {
|
|
861
862
|
chatText?: string;
|