quake2ts 0.0.402 → 0.0.405
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/package.json +1 -1
- package/packages/client/dist/browser/index.global.js +16 -16
- package/packages/client/dist/browser/index.global.js.map +1 -1
- package/packages/client/dist/cjs/index.cjs +383 -11
- package/packages/client/dist/cjs/index.cjs.map +1 -1
- package/packages/client/dist/esm/index.js +382 -11
- package/packages/client/dist/esm/index.js.map +1 -1
- package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/client/dist/types/demo/camera.d.ts +16 -0
- package/packages/client/dist/types/demo/camera.d.ts.map +1 -0
- package/packages/client/dist/types/index.d.ts +7 -1
- package/packages/client/dist/types/index.d.ts.map +1 -1
- package/packages/engine/dist/browser/index.global.js +16 -16
- package/packages/engine/dist/browser/index.global.js.map +1 -1
- package/packages/engine/dist/cjs/index.cjs +274 -2
- package/packages/engine/dist/cjs/index.cjs.map +1 -1
- package/packages/engine/dist/esm/index.js +274 -2
- package/packages/engine/dist/esm/index.js.map +1 -1
- package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/engine/dist/types/commands.d.ts +3 -0
- package/packages/engine/dist/types/commands.d.ts.map +1 -1
- package/packages/engine/dist/types/cvars.d.ts +11 -0
- package/packages/engine/dist/types/cvars.d.ts.map +1 -1
- package/packages/engine/dist/types/demo/analysis.d.ts +33 -0
- package/packages/engine/dist/types/demo/analysis.d.ts.map +1 -1
- package/packages/engine/dist/types/demo/analyzer.d.ts +28 -0
- package/packages/engine/dist/types/demo/analyzer.d.ts.map +1 -0
- package/packages/engine/dist/types/demo/playback.d.ts +16 -1
- package/packages/engine/dist/types/demo/playback.d.ts.map +1 -1
- package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
|
@@ -94,6 +94,9 @@ var CommandRegistry = class {
|
|
|
94
94
|
this.commands.set(name, command);
|
|
95
95
|
return command;
|
|
96
96
|
}
|
|
97
|
+
registerCommand(name, callback) {
|
|
98
|
+
this.register(name, callback);
|
|
99
|
+
}
|
|
97
100
|
get(name) {
|
|
98
101
|
return this.commands.get(name);
|
|
99
102
|
}
|
|
@@ -109,10 +112,33 @@ var CommandRegistry = class {
|
|
|
109
112
|
command.execute(args);
|
|
110
113
|
return true;
|
|
111
114
|
}
|
|
115
|
+
this.onConsoleOutput?.(`Unknown command "${name}"`);
|
|
112
116
|
return false;
|
|
113
117
|
}
|
|
118
|
+
executeCommand(cmd) {
|
|
119
|
+
this.execute(cmd);
|
|
120
|
+
}
|
|
114
121
|
tokenize(text) {
|
|
115
|
-
|
|
122
|
+
const args = [];
|
|
123
|
+
let currentArg = "";
|
|
124
|
+
let inQuote = false;
|
|
125
|
+
for (let i = 0; i < text.length; i++) {
|
|
126
|
+
const char = text[i];
|
|
127
|
+
if (char === '"') {
|
|
128
|
+
inQuote = !inQuote;
|
|
129
|
+
} else if (char === " " && !inQuote) {
|
|
130
|
+
if (currentArg.length > 0) {
|
|
131
|
+
args.push(currentArg);
|
|
132
|
+
currentArg = "";
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
currentArg += char;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (currentArg.length > 0) {
|
|
139
|
+
args.push(currentArg);
|
|
140
|
+
}
|
|
141
|
+
return args;
|
|
116
142
|
}
|
|
117
143
|
list() {
|
|
118
144
|
return [...this.commands.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -1307,13 +1333,21 @@ var CvarRegistry = class {
|
|
|
1307
1333
|
if (existing) {
|
|
1308
1334
|
return existing;
|
|
1309
1335
|
}
|
|
1310
|
-
const
|
|
1336
|
+
const originalOnChange = def.onChange;
|
|
1337
|
+
const wrappedOnChange = (cvar2, prev) => {
|
|
1338
|
+
originalOnChange?.(cvar2, prev);
|
|
1339
|
+
this.onCvarChange?.(cvar2.name, cvar2.string);
|
|
1340
|
+
};
|
|
1341
|
+
const cvar = new Cvar({ ...def, onChange: wrappedOnChange });
|
|
1311
1342
|
this.cvars.set(def.name, cvar);
|
|
1312
1343
|
return cvar;
|
|
1313
1344
|
}
|
|
1314
1345
|
get(name) {
|
|
1315
1346
|
return this.cvars.get(name);
|
|
1316
1347
|
}
|
|
1348
|
+
getCvar(name) {
|
|
1349
|
+
return this.get(name);
|
|
1350
|
+
}
|
|
1317
1351
|
setValue(name, value) {
|
|
1318
1352
|
const cvar = this.get(name);
|
|
1319
1353
|
if (!cvar) {
|
|
@@ -1322,6 +1356,9 @@ var CvarRegistry = class {
|
|
|
1322
1356
|
cvar.set(value);
|
|
1323
1357
|
return cvar;
|
|
1324
1358
|
}
|
|
1359
|
+
setCvar(name, value) {
|
|
1360
|
+
this.setValue(name, value);
|
|
1361
|
+
}
|
|
1325
1362
|
resetAll() {
|
|
1326
1363
|
for (const cvar of this.cvars.values()) {
|
|
1327
1364
|
cvar.reset();
|
|
@@ -1337,6 +1374,15 @@ var CvarRegistry = class {
|
|
|
1337
1374
|
list() {
|
|
1338
1375
|
return [...this.cvars.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
1339
1376
|
}
|
|
1377
|
+
listCvars() {
|
|
1378
|
+
return this.list().map((cvar) => ({
|
|
1379
|
+
name: cvar.name,
|
|
1380
|
+
value: cvar.string,
|
|
1381
|
+
defaultValue: cvar.defaultValue,
|
|
1382
|
+
flags: cvar.flags,
|
|
1383
|
+
description: cvar.description
|
|
1384
|
+
}));
|
|
1385
|
+
}
|
|
1340
1386
|
};
|
|
1341
1387
|
|
|
1342
1388
|
// src/host.ts
|
|
@@ -12426,6 +12472,165 @@ var NetworkMessageParser = class _NetworkMessageParser {
|
|
|
12426
12472
|
}
|
|
12427
12473
|
};
|
|
12428
12474
|
|
|
12475
|
+
// src/demo/analyzer.ts
|
|
12476
|
+
var DemoAnalyzer = class {
|
|
12477
|
+
constructor(buffer) {
|
|
12478
|
+
this.events = [];
|
|
12479
|
+
this.summary = {
|
|
12480
|
+
totalKills: 0,
|
|
12481
|
+
totalDeaths: 0,
|
|
12482
|
+
damageDealt: 0,
|
|
12483
|
+
damageReceived: 0,
|
|
12484
|
+
weaponUsage: /* @__PURE__ */ new Map()
|
|
12485
|
+
};
|
|
12486
|
+
this.header = null;
|
|
12487
|
+
this.configStrings = /* @__PURE__ */ new Map();
|
|
12488
|
+
this.serverInfo = {};
|
|
12489
|
+
this.statistics = null;
|
|
12490
|
+
this.playerStats = /* @__PURE__ */ new Map();
|
|
12491
|
+
// By playerNum
|
|
12492
|
+
this.weaponStats = /* @__PURE__ */ new Map();
|
|
12493
|
+
this.buffer = buffer;
|
|
12494
|
+
}
|
|
12495
|
+
analyze() {
|
|
12496
|
+
const reader = new DemoReader(this.buffer);
|
|
12497
|
+
let currentFrameIndex = -1;
|
|
12498
|
+
let currentTime = 0;
|
|
12499
|
+
let frameDuration = 0.1;
|
|
12500
|
+
let protocolVersion = 0;
|
|
12501
|
+
const handler = {
|
|
12502
|
+
onServerData: (protocol, serverCount, attractLoop, gameDir, playerNum, levelName, tickRate, demoType) => {
|
|
12503
|
+
protocolVersion = protocol;
|
|
12504
|
+
this.header = {
|
|
12505
|
+
protocolVersion: protocol,
|
|
12506
|
+
gameDir,
|
|
12507
|
+
levelName,
|
|
12508
|
+
playerNum,
|
|
12509
|
+
serverCount,
|
|
12510
|
+
spawnCount: serverCount,
|
|
12511
|
+
// Mapping generic arg
|
|
12512
|
+
tickRate,
|
|
12513
|
+
demoType
|
|
12514
|
+
};
|
|
12515
|
+
if (tickRate && tickRate > 0) {
|
|
12516
|
+
frameDuration = 1 / tickRate;
|
|
12517
|
+
}
|
|
12518
|
+
},
|
|
12519
|
+
onConfigString: (index, str) => {
|
|
12520
|
+
this.configStrings.set(index, str);
|
|
12521
|
+
if (index === 0) {
|
|
12522
|
+
this.parseServerInfo(str);
|
|
12523
|
+
}
|
|
12524
|
+
},
|
|
12525
|
+
onSpawnBaseline: (entity) => {
|
|
12526
|
+
},
|
|
12527
|
+
onFrame: (frame) => {
|
|
12528
|
+
},
|
|
12529
|
+
onPrint: (level, msg) => {
|
|
12530
|
+
if (msg.includes("died") || msg.includes("killed")) {
|
|
12531
|
+
this.summary.totalDeaths++;
|
|
12532
|
+
this.recordEvent({
|
|
12533
|
+
type: 4 /* Death */,
|
|
12534
|
+
frame: currentFrameIndex,
|
|
12535
|
+
time: currentTime,
|
|
12536
|
+
description: msg.trim()
|
|
12537
|
+
});
|
|
12538
|
+
}
|
|
12539
|
+
},
|
|
12540
|
+
onCenterPrint: () => {
|
|
12541
|
+
},
|
|
12542
|
+
onStuffText: () => {
|
|
12543
|
+
},
|
|
12544
|
+
onSound: () => {
|
|
12545
|
+
},
|
|
12546
|
+
onTempEntity: () => {
|
|
12547
|
+
},
|
|
12548
|
+
onLayout: () => {
|
|
12549
|
+
},
|
|
12550
|
+
onInventory: () => {
|
|
12551
|
+
},
|
|
12552
|
+
onMuzzleFlash: (ent, weapon) => {
|
|
12553
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
12554
|
+
},
|
|
12555
|
+
onMuzzleFlash2: (ent, weapon) => {
|
|
12556
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
12557
|
+
},
|
|
12558
|
+
onMuzzleFlash3: (ent, weapon) => {
|
|
12559
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
12560
|
+
},
|
|
12561
|
+
onDisconnect: () => {
|
|
12562
|
+
},
|
|
12563
|
+
onReconnect: () => {
|
|
12564
|
+
},
|
|
12565
|
+
onDownload: () => {
|
|
12566
|
+
},
|
|
12567
|
+
// Rerelease specific
|
|
12568
|
+
onDamage: (indicators) => {
|
|
12569
|
+
for (const ind of indicators) {
|
|
12570
|
+
this.recordEvent({
|
|
12571
|
+
type: 2 /* DamageReceived */,
|
|
12572
|
+
frame: currentFrameIndex,
|
|
12573
|
+
time: currentTime,
|
|
12574
|
+
value: ind.damage,
|
|
12575
|
+
position: ind.dir,
|
|
12576
|
+
description: `Took ${ind.damage} damage`
|
|
12577
|
+
});
|
|
12578
|
+
this.summary.damageReceived += ind.damage;
|
|
12579
|
+
}
|
|
12580
|
+
}
|
|
12581
|
+
};
|
|
12582
|
+
while (reader.hasMore()) {
|
|
12583
|
+
const block = reader.readNextBlock();
|
|
12584
|
+
if (!block) break;
|
|
12585
|
+
currentFrameIndex++;
|
|
12586
|
+
currentTime = currentFrameIndex * frameDuration;
|
|
12587
|
+
const parser = new NetworkMessageParser(block.data, handler);
|
|
12588
|
+
parser.setProtocolVersion(protocolVersion);
|
|
12589
|
+
parser.parseMessage();
|
|
12590
|
+
protocolVersion = parser.getProtocolVersion();
|
|
12591
|
+
}
|
|
12592
|
+
this.statistics = {
|
|
12593
|
+
duration: currentTime,
|
|
12594
|
+
frameCount: currentFrameIndex + 1,
|
|
12595
|
+
averageFps: (currentFrameIndex + 1) / (currentTime || 1),
|
|
12596
|
+
mapName: this.header?.levelName || "unknown",
|
|
12597
|
+
playerCount: 1
|
|
12598
|
+
// Default to 1 for SP/client demo
|
|
12599
|
+
};
|
|
12600
|
+
return {
|
|
12601
|
+
events: this.events,
|
|
12602
|
+
summary: this.summary,
|
|
12603
|
+
header: this.header,
|
|
12604
|
+
configStrings: this.configStrings,
|
|
12605
|
+
serverInfo: this.serverInfo,
|
|
12606
|
+
statistics: this.statistics
|
|
12607
|
+
};
|
|
12608
|
+
}
|
|
12609
|
+
handleWeaponFire(ent, weapon, frame, time) {
|
|
12610
|
+
this.recordEvent({
|
|
12611
|
+
type: 0 /* WeaponFire */,
|
|
12612
|
+
frame,
|
|
12613
|
+
time,
|
|
12614
|
+
entityId: ent,
|
|
12615
|
+
value: weapon,
|
|
12616
|
+
description: `Weapon ${weapon} fired by ${ent}`
|
|
12617
|
+
});
|
|
12618
|
+
const count = this.summary.weaponUsage.get(weapon) || 0;
|
|
12619
|
+
this.summary.weaponUsage.set(weapon, count + 1);
|
|
12620
|
+
}
|
|
12621
|
+
recordEvent(event) {
|
|
12622
|
+
this.events.push(event);
|
|
12623
|
+
}
|
|
12624
|
+
parseServerInfo(str) {
|
|
12625
|
+
const parts = str.split("\\");
|
|
12626
|
+
for (let i = 1; i < parts.length; i += 2) {
|
|
12627
|
+
if (i + 1 < parts.length) {
|
|
12628
|
+
this.serverInfo[parts[i]] = parts[i + 1];
|
|
12629
|
+
}
|
|
12630
|
+
}
|
|
12631
|
+
}
|
|
12632
|
+
};
|
|
12633
|
+
|
|
12429
12634
|
// src/demo/playback.ts
|
|
12430
12635
|
var PlaybackState = /* @__PURE__ */ ((PlaybackState2) => {
|
|
12431
12636
|
PlaybackState2[PlaybackState2["Stopped"] = 0] = "Stopped";
|
|
@@ -12437,6 +12642,8 @@ var PlaybackState = /* @__PURE__ */ ((PlaybackState2) => {
|
|
|
12437
12642
|
var DemoPlaybackController = class {
|
|
12438
12643
|
constructor() {
|
|
12439
12644
|
this.reader = null;
|
|
12645
|
+
this.buffer = null;
|
|
12646
|
+
// Keep reference for analysis
|
|
12440
12647
|
this.state = 0 /* Stopped */;
|
|
12441
12648
|
this.playbackSpeed = 1;
|
|
12442
12649
|
this.currentProtocolVersion = 0;
|
|
@@ -12452,6 +12659,13 @@ var DemoPlaybackController = class {
|
|
|
12452
12659
|
this.snapshotInterval = 100;
|
|
12453
12660
|
// frames
|
|
12454
12661
|
this.snapshots = /* @__PURE__ */ new Map();
|
|
12662
|
+
// Analysis Cache
|
|
12663
|
+
this.cachedEvents = null;
|
|
12664
|
+
this.cachedSummary = null;
|
|
12665
|
+
this.cachedHeader = null;
|
|
12666
|
+
this.cachedConfigStrings = null;
|
|
12667
|
+
this.cachedServerInfo = null;
|
|
12668
|
+
this.cachedStatistics = null;
|
|
12455
12669
|
}
|
|
12456
12670
|
setHandler(handler) {
|
|
12457
12671
|
this.handler = handler;
|
|
@@ -12460,6 +12674,7 @@ var DemoPlaybackController = class {
|
|
|
12460
12674
|
this.callbacks = callbacks;
|
|
12461
12675
|
}
|
|
12462
12676
|
loadDemo(buffer) {
|
|
12677
|
+
this.buffer = buffer;
|
|
12463
12678
|
this.reader = new DemoReader(buffer);
|
|
12464
12679
|
this.transitionState(0 /* Stopped */);
|
|
12465
12680
|
this.accumulatedTime = 0;
|
|
@@ -12467,6 +12682,12 @@ var DemoPlaybackController = class {
|
|
|
12467
12682
|
this.currentFrameIndex = -1;
|
|
12468
12683
|
this.snapshots.clear();
|
|
12469
12684
|
this.lastFrameData = null;
|
|
12685
|
+
this.cachedEvents = null;
|
|
12686
|
+
this.cachedSummary = null;
|
|
12687
|
+
this.cachedHeader = null;
|
|
12688
|
+
this.cachedConfigStrings = null;
|
|
12689
|
+
this.cachedServerInfo = null;
|
|
12690
|
+
this.cachedStatistics = null;
|
|
12470
12691
|
}
|
|
12471
12692
|
play() {
|
|
12472
12693
|
if (this.reader && this.state !== 1 /* Playing */) {
|
|
@@ -12779,6 +13000,57 @@ var DemoPlaybackController = class {
|
|
|
12779
13000
|
this.seek(originalFrame);
|
|
12780
13001
|
return trajectory;
|
|
12781
13002
|
}
|
|
13003
|
+
// 3.2.3 Event Log Extraction & 3.3 Metadata
|
|
13004
|
+
getDemoEvents() {
|
|
13005
|
+
this.ensureAnalysis();
|
|
13006
|
+
return this.cachedEvents || [];
|
|
13007
|
+
}
|
|
13008
|
+
filterEvents(type, entityId) {
|
|
13009
|
+
const events = this.getDemoEvents();
|
|
13010
|
+
return events.filter((e) => {
|
|
13011
|
+
if (e.type !== type) return false;
|
|
13012
|
+
if (entityId !== void 0 && e.entityId !== entityId) return false;
|
|
13013
|
+
return true;
|
|
13014
|
+
});
|
|
13015
|
+
}
|
|
13016
|
+
getEventSummary() {
|
|
13017
|
+
this.ensureAnalysis();
|
|
13018
|
+
return this.cachedSummary || {
|
|
13019
|
+
totalKills: 0,
|
|
13020
|
+
totalDeaths: 0,
|
|
13021
|
+
damageDealt: 0,
|
|
13022
|
+
damageReceived: 0,
|
|
13023
|
+
weaponUsage: /* @__PURE__ */ new Map()
|
|
13024
|
+
};
|
|
13025
|
+
}
|
|
13026
|
+
getDemoHeader() {
|
|
13027
|
+
this.ensureAnalysis();
|
|
13028
|
+
return this.cachedHeader;
|
|
13029
|
+
}
|
|
13030
|
+
getDemoConfigStrings() {
|
|
13031
|
+
this.ensureAnalysis();
|
|
13032
|
+
return this.cachedConfigStrings || /* @__PURE__ */ new Map();
|
|
13033
|
+
}
|
|
13034
|
+
getDemoServerInfo() {
|
|
13035
|
+
this.ensureAnalysis();
|
|
13036
|
+
return this.cachedServerInfo || {};
|
|
13037
|
+
}
|
|
13038
|
+
getDemoStatistics() {
|
|
13039
|
+
this.ensureAnalysis();
|
|
13040
|
+
return this.cachedStatistics;
|
|
13041
|
+
}
|
|
13042
|
+
ensureAnalysis() {
|
|
13043
|
+
if (!this.cachedEvents && this.buffer) {
|
|
13044
|
+
const analyzer = new DemoAnalyzer(this.buffer);
|
|
13045
|
+
const result = analyzer.analyze();
|
|
13046
|
+
this.cachedEvents = result.events;
|
|
13047
|
+
this.cachedSummary = result.summary;
|
|
13048
|
+
this.cachedHeader = result.header;
|
|
13049
|
+
this.cachedConfigStrings = result.configStrings;
|
|
13050
|
+
this.cachedServerInfo = result.serverInfo;
|
|
13051
|
+
this.cachedStatistics = result.statistics;
|
|
13052
|
+
}
|
|
13053
|
+
}
|
|
12782
13054
|
};
|
|
12783
13055
|
|
|
12784
13056
|
// src/demo/recorder.ts
|