quake2ts 0.0.403 → 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
|
@@ -295,6 +295,9 @@ var CommandRegistry = class {
|
|
|
295
295
|
this.commands.set(name, command);
|
|
296
296
|
return command;
|
|
297
297
|
}
|
|
298
|
+
registerCommand(name, callback) {
|
|
299
|
+
this.register(name, callback);
|
|
300
|
+
}
|
|
298
301
|
get(name) {
|
|
299
302
|
return this.commands.get(name);
|
|
300
303
|
}
|
|
@@ -310,10 +313,33 @@ var CommandRegistry = class {
|
|
|
310
313
|
command.execute(args);
|
|
311
314
|
return true;
|
|
312
315
|
}
|
|
316
|
+
this.onConsoleOutput?.(`Unknown command "${name}"`);
|
|
313
317
|
return false;
|
|
314
318
|
}
|
|
319
|
+
executeCommand(cmd) {
|
|
320
|
+
this.execute(cmd);
|
|
321
|
+
}
|
|
315
322
|
tokenize(text) {
|
|
316
|
-
|
|
323
|
+
const args = [];
|
|
324
|
+
let currentArg = "";
|
|
325
|
+
let inQuote = false;
|
|
326
|
+
for (let i = 0; i < text.length; i++) {
|
|
327
|
+
const char = text[i];
|
|
328
|
+
if (char === '"') {
|
|
329
|
+
inQuote = !inQuote;
|
|
330
|
+
} else if (char === " " && !inQuote) {
|
|
331
|
+
if (currentArg.length > 0) {
|
|
332
|
+
args.push(currentArg);
|
|
333
|
+
currentArg = "";
|
|
334
|
+
}
|
|
335
|
+
} else {
|
|
336
|
+
currentArg += char;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (currentArg.length > 0) {
|
|
340
|
+
args.push(currentArg);
|
|
341
|
+
}
|
|
342
|
+
return args;
|
|
317
343
|
}
|
|
318
344
|
list() {
|
|
319
345
|
return [...this.commands.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -1508,13 +1534,21 @@ var CvarRegistry = class {
|
|
|
1508
1534
|
if (existing) {
|
|
1509
1535
|
return existing;
|
|
1510
1536
|
}
|
|
1511
|
-
const
|
|
1537
|
+
const originalOnChange = def.onChange;
|
|
1538
|
+
const wrappedOnChange = (cvar2, prev) => {
|
|
1539
|
+
originalOnChange?.(cvar2, prev);
|
|
1540
|
+
this.onCvarChange?.(cvar2.name, cvar2.string);
|
|
1541
|
+
};
|
|
1542
|
+
const cvar = new Cvar({ ...def, onChange: wrappedOnChange });
|
|
1512
1543
|
this.cvars.set(def.name, cvar);
|
|
1513
1544
|
return cvar;
|
|
1514
1545
|
}
|
|
1515
1546
|
get(name) {
|
|
1516
1547
|
return this.cvars.get(name);
|
|
1517
1548
|
}
|
|
1549
|
+
getCvar(name) {
|
|
1550
|
+
return this.get(name);
|
|
1551
|
+
}
|
|
1518
1552
|
setValue(name, value) {
|
|
1519
1553
|
const cvar = this.get(name);
|
|
1520
1554
|
if (!cvar) {
|
|
@@ -1523,6 +1557,9 @@ var CvarRegistry = class {
|
|
|
1523
1557
|
cvar.set(value);
|
|
1524
1558
|
return cvar;
|
|
1525
1559
|
}
|
|
1560
|
+
setCvar(name, value) {
|
|
1561
|
+
this.setValue(name, value);
|
|
1562
|
+
}
|
|
1526
1563
|
resetAll() {
|
|
1527
1564
|
for (const cvar of this.cvars.values()) {
|
|
1528
1565
|
cvar.reset();
|
|
@@ -1538,6 +1575,15 @@ var CvarRegistry = class {
|
|
|
1538
1575
|
list() {
|
|
1539
1576
|
return [...this.cvars.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
1540
1577
|
}
|
|
1578
|
+
listCvars() {
|
|
1579
|
+
return this.list().map((cvar) => ({
|
|
1580
|
+
name: cvar.name,
|
|
1581
|
+
value: cvar.string,
|
|
1582
|
+
defaultValue: cvar.defaultValue,
|
|
1583
|
+
flags: cvar.flags,
|
|
1584
|
+
description: cvar.description
|
|
1585
|
+
}));
|
|
1586
|
+
}
|
|
1541
1587
|
};
|
|
1542
1588
|
|
|
1543
1589
|
// src/host.ts
|
|
@@ -12627,6 +12673,165 @@ var NetworkMessageParser = class _NetworkMessageParser {
|
|
|
12627
12673
|
}
|
|
12628
12674
|
};
|
|
12629
12675
|
|
|
12676
|
+
// src/demo/analyzer.ts
|
|
12677
|
+
var DemoAnalyzer = class {
|
|
12678
|
+
constructor(buffer) {
|
|
12679
|
+
this.events = [];
|
|
12680
|
+
this.summary = {
|
|
12681
|
+
totalKills: 0,
|
|
12682
|
+
totalDeaths: 0,
|
|
12683
|
+
damageDealt: 0,
|
|
12684
|
+
damageReceived: 0,
|
|
12685
|
+
weaponUsage: /* @__PURE__ */ new Map()
|
|
12686
|
+
};
|
|
12687
|
+
this.header = null;
|
|
12688
|
+
this.configStrings = /* @__PURE__ */ new Map();
|
|
12689
|
+
this.serverInfo = {};
|
|
12690
|
+
this.statistics = null;
|
|
12691
|
+
this.playerStats = /* @__PURE__ */ new Map();
|
|
12692
|
+
// By playerNum
|
|
12693
|
+
this.weaponStats = /* @__PURE__ */ new Map();
|
|
12694
|
+
this.buffer = buffer;
|
|
12695
|
+
}
|
|
12696
|
+
analyze() {
|
|
12697
|
+
const reader = new DemoReader(this.buffer);
|
|
12698
|
+
let currentFrameIndex = -1;
|
|
12699
|
+
let currentTime = 0;
|
|
12700
|
+
let frameDuration = 0.1;
|
|
12701
|
+
let protocolVersion = 0;
|
|
12702
|
+
const handler = {
|
|
12703
|
+
onServerData: (protocol, serverCount, attractLoop, gameDir, playerNum, levelName, tickRate, demoType) => {
|
|
12704
|
+
protocolVersion = protocol;
|
|
12705
|
+
this.header = {
|
|
12706
|
+
protocolVersion: protocol,
|
|
12707
|
+
gameDir,
|
|
12708
|
+
levelName,
|
|
12709
|
+
playerNum,
|
|
12710
|
+
serverCount,
|
|
12711
|
+
spawnCount: serverCount,
|
|
12712
|
+
// Mapping generic arg
|
|
12713
|
+
tickRate,
|
|
12714
|
+
demoType
|
|
12715
|
+
};
|
|
12716
|
+
if (tickRate && tickRate > 0) {
|
|
12717
|
+
frameDuration = 1 / tickRate;
|
|
12718
|
+
}
|
|
12719
|
+
},
|
|
12720
|
+
onConfigString: (index, str) => {
|
|
12721
|
+
this.configStrings.set(index, str);
|
|
12722
|
+
if (index === 0) {
|
|
12723
|
+
this.parseServerInfo(str);
|
|
12724
|
+
}
|
|
12725
|
+
},
|
|
12726
|
+
onSpawnBaseline: (entity) => {
|
|
12727
|
+
},
|
|
12728
|
+
onFrame: (frame) => {
|
|
12729
|
+
},
|
|
12730
|
+
onPrint: (level, msg) => {
|
|
12731
|
+
if (msg.includes("died") || msg.includes("killed")) {
|
|
12732
|
+
this.summary.totalDeaths++;
|
|
12733
|
+
this.recordEvent({
|
|
12734
|
+
type: 4 /* Death */,
|
|
12735
|
+
frame: currentFrameIndex,
|
|
12736
|
+
time: currentTime,
|
|
12737
|
+
description: msg.trim()
|
|
12738
|
+
});
|
|
12739
|
+
}
|
|
12740
|
+
},
|
|
12741
|
+
onCenterPrint: () => {
|
|
12742
|
+
},
|
|
12743
|
+
onStuffText: () => {
|
|
12744
|
+
},
|
|
12745
|
+
onSound: () => {
|
|
12746
|
+
},
|
|
12747
|
+
onTempEntity: () => {
|
|
12748
|
+
},
|
|
12749
|
+
onLayout: () => {
|
|
12750
|
+
},
|
|
12751
|
+
onInventory: () => {
|
|
12752
|
+
},
|
|
12753
|
+
onMuzzleFlash: (ent, weapon) => {
|
|
12754
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
12755
|
+
},
|
|
12756
|
+
onMuzzleFlash2: (ent, weapon) => {
|
|
12757
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
12758
|
+
},
|
|
12759
|
+
onMuzzleFlash3: (ent, weapon) => {
|
|
12760
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
12761
|
+
},
|
|
12762
|
+
onDisconnect: () => {
|
|
12763
|
+
},
|
|
12764
|
+
onReconnect: () => {
|
|
12765
|
+
},
|
|
12766
|
+
onDownload: () => {
|
|
12767
|
+
},
|
|
12768
|
+
// Rerelease specific
|
|
12769
|
+
onDamage: (indicators) => {
|
|
12770
|
+
for (const ind of indicators) {
|
|
12771
|
+
this.recordEvent({
|
|
12772
|
+
type: 2 /* DamageReceived */,
|
|
12773
|
+
frame: currentFrameIndex,
|
|
12774
|
+
time: currentTime,
|
|
12775
|
+
value: ind.damage,
|
|
12776
|
+
position: ind.dir,
|
|
12777
|
+
description: `Took ${ind.damage} damage`
|
|
12778
|
+
});
|
|
12779
|
+
this.summary.damageReceived += ind.damage;
|
|
12780
|
+
}
|
|
12781
|
+
}
|
|
12782
|
+
};
|
|
12783
|
+
while (reader.hasMore()) {
|
|
12784
|
+
const block = reader.readNextBlock();
|
|
12785
|
+
if (!block) break;
|
|
12786
|
+
currentFrameIndex++;
|
|
12787
|
+
currentTime = currentFrameIndex * frameDuration;
|
|
12788
|
+
const parser = new NetworkMessageParser(block.data, handler);
|
|
12789
|
+
parser.setProtocolVersion(protocolVersion);
|
|
12790
|
+
parser.parseMessage();
|
|
12791
|
+
protocolVersion = parser.getProtocolVersion();
|
|
12792
|
+
}
|
|
12793
|
+
this.statistics = {
|
|
12794
|
+
duration: currentTime,
|
|
12795
|
+
frameCount: currentFrameIndex + 1,
|
|
12796
|
+
averageFps: (currentFrameIndex + 1) / (currentTime || 1),
|
|
12797
|
+
mapName: this.header?.levelName || "unknown",
|
|
12798
|
+
playerCount: 1
|
|
12799
|
+
// Default to 1 for SP/client demo
|
|
12800
|
+
};
|
|
12801
|
+
return {
|
|
12802
|
+
events: this.events,
|
|
12803
|
+
summary: this.summary,
|
|
12804
|
+
header: this.header,
|
|
12805
|
+
configStrings: this.configStrings,
|
|
12806
|
+
serverInfo: this.serverInfo,
|
|
12807
|
+
statistics: this.statistics
|
|
12808
|
+
};
|
|
12809
|
+
}
|
|
12810
|
+
handleWeaponFire(ent, weapon, frame, time) {
|
|
12811
|
+
this.recordEvent({
|
|
12812
|
+
type: 0 /* WeaponFire */,
|
|
12813
|
+
frame,
|
|
12814
|
+
time,
|
|
12815
|
+
entityId: ent,
|
|
12816
|
+
value: weapon,
|
|
12817
|
+
description: `Weapon ${weapon} fired by ${ent}`
|
|
12818
|
+
});
|
|
12819
|
+
const count = this.summary.weaponUsage.get(weapon) || 0;
|
|
12820
|
+
this.summary.weaponUsage.set(weapon, count + 1);
|
|
12821
|
+
}
|
|
12822
|
+
recordEvent(event) {
|
|
12823
|
+
this.events.push(event);
|
|
12824
|
+
}
|
|
12825
|
+
parseServerInfo(str) {
|
|
12826
|
+
const parts = str.split("\\");
|
|
12827
|
+
for (let i = 1; i < parts.length; i += 2) {
|
|
12828
|
+
if (i + 1 < parts.length) {
|
|
12829
|
+
this.serverInfo[parts[i]] = parts[i + 1];
|
|
12830
|
+
}
|
|
12831
|
+
}
|
|
12832
|
+
}
|
|
12833
|
+
};
|
|
12834
|
+
|
|
12630
12835
|
// src/demo/playback.ts
|
|
12631
12836
|
var PlaybackState = /* @__PURE__ */ ((PlaybackState2) => {
|
|
12632
12837
|
PlaybackState2[PlaybackState2["Stopped"] = 0] = "Stopped";
|
|
@@ -12638,6 +12843,8 @@ var PlaybackState = /* @__PURE__ */ ((PlaybackState2) => {
|
|
|
12638
12843
|
var DemoPlaybackController = class {
|
|
12639
12844
|
constructor() {
|
|
12640
12845
|
this.reader = null;
|
|
12846
|
+
this.buffer = null;
|
|
12847
|
+
// Keep reference for analysis
|
|
12641
12848
|
this.state = 0 /* Stopped */;
|
|
12642
12849
|
this.playbackSpeed = 1;
|
|
12643
12850
|
this.currentProtocolVersion = 0;
|
|
@@ -12653,6 +12860,13 @@ var DemoPlaybackController = class {
|
|
|
12653
12860
|
this.snapshotInterval = 100;
|
|
12654
12861
|
// frames
|
|
12655
12862
|
this.snapshots = /* @__PURE__ */ new Map();
|
|
12863
|
+
// Analysis Cache
|
|
12864
|
+
this.cachedEvents = null;
|
|
12865
|
+
this.cachedSummary = null;
|
|
12866
|
+
this.cachedHeader = null;
|
|
12867
|
+
this.cachedConfigStrings = null;
|
|
12868
|
+
this.cachedServerInfo = null;
|
|
12869
|
+
this.cachedStatistics = null;
|
|
12656
12870
|
}
|
|
12657
12871
|
setHandler(handler) {
|
|
12658
12872
|
this.handler = handler;
|
|
@@ -12661,6 +12875,7 @@ var DemoPlaybackController = class {
|
|
|
12661
12875
|
this.callbacks = callbacks;
|
|
12662
12876
|
}
|
|
12663
12877
|
loadDemo(buffer) {
|
|
12878
|
+
this.buffer = buffer;
|
|
12664
12879
|
this.reader = new DemoReader(buffer);
|
|
12665
12880
|
this.transitionState(0 /* Stopped */);
|
|
12666
12881
|
this.accumulatedTime = 0;
|
|
@@ -12668,6 +12883,12 @@ var DemoPlaybackController = class {
|
|
|
12668
12883
|
this.currentFrameIndex = -1;
|
|
12669
12884
|
this.snapshots.clear();
|
|
12670
12885
|
this.lastFrameData = null;
|
|
12886
|
+
this.cachedEvents = null;
|
|
12887
|
+
this.cachedSummary = null;
|
|
12888
|
+
this.cachedHeader = null;
|
|
12889
|
+
this.cachedConfigStrings = null;
|
|
12890
|
+
this.cachedServerInfo = null;
|
|
12891
|
+
this.cachedStatistics = null;
|
|
12671
12892
|
}
|
|
12672
12893
|
play() {
|
|
12673
12894
|
if (this.reader && this.state !== 1 /* Playing */) {
|
|
@@ -12980,6 +13201,57 @@ var DemoPlaybackController = class {
|
|
|
12980
13201
|
this.seek(originalFrame);
|
|
12981
13202
|
return trajectory;
|
|
12982
13203
|
}
|
|
13204
|
+
// 3.2.3 Event Log Extraction & 3.3 Metadata
|
|
13205
|
+
getDemoEvents() {
|
|
13206
|
+
this.ensureAnalysis();
|
|
13207
|
+
return this.cachedEvents || [];
|
|
13208
|
+
}
|
|
13209
|
+
filterEvents(type, entityId) {
|
|
13210
|
+
const events = this.getDemoEvents();
|
|
13211
|
+
return events.filter((e) => {
|
|
13212
|
+
if (e.type !== type) return false;
|
|
13213
|
+
if (entityId !== void 0 && e.entityId !== entityId) return false;
|
|
13214
|
+
return true;
|
|
13215
|
+
});
|
|
13216
|
+
}
|
|
13217
|
+
getEventSummary() {
|
|
13218
|
+
this.ensureAnalysis();
|
|
13219
|
+
return this.cachedSummary || {
|
|
13220
|
+
totalKills: 0,
|
|
13221
|
+
totalDeaths: 0,
|
|
13222
|
+
damageDealt: 0,
|
|
13223
|
+
damageReceived: 0,
|
|
13224
|
+
weaponUsage: /* @__PURE__ */ new Map()
|
|
13225
|
+
};
|
|
13226
|
+
}
|
|
13227
|
+
getDemoHeader() {
|
|
13228
|
+
this.ensureAnalysis();
|
|
13229
|
+
return this.cachedHeader;
|
|
13230
|
+
}
|
|
13231
|
+
getDemoConfigStrings() {
|
|
13232
|
+
this.ensureAnalysis();
|
|
13233
|
+
return this.cachedConfigStrings || /* @__PURE__ */ new Map();
|
|
13234
|
+
}
|
|
13235
|
+
getDemoServerInfo() {
|
|
13236
|
+
this.ensureAnalysis();
|
|
13237
|
+
return this.cachedServerInfo || {};
|
|
13238
|
+
}
|
|
13239
|
+
getDemoStatistics() {
|
|
13240
|
+
this.ensureAnalysis();
|
|
13241
|
+
return this.cachedStatistics;
|
|
13242
|
+
}
|
|
13243
|
+
ensureAnalysis() {
|
|
13244
|
+
if (!this.cachedEvents && this.buffer) {
|
|
13245
|
+
const analyzer = new DemoAnalyzer(this.buffer);
|
|
13246
|
+
const result = analyzer.analyze();
|
|
13247
|
+
this.cachedEvents = result.events;
|
|
13248
|
+
this.cachedSummary = result.summary;
|
|
13249
|
+
this.cachedHeader = result.header;
|
|
13250
|
+
this.cachedConfigStrings = result.configStrings;
|
|
13251
|
+
this.cachedServerInfo = result.serverInfo;
|
|
13252
|
+
this.cachedStatistics = result.statistics;
|
|
13253
|
+
}
|
|
13254
|
+
}
|
|
12983
13255
|
};
|
|
12984
13256
|
|
|
12985
13257
|
// src/demo/recorder.ts
|