quake2ts 0.0.403 → 0.0.407
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 +405 -13
- package/packages/client/dist/cjs/index.cjs.map +1 -1
- package/packages/client/dist/esm/index.js +404 -13
- 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/client/dist/types/ui/demo-controls.d.ts +2 -1
- package/packages/client/dist/types/ui/demo-controls.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 +362 -4
- package/packages/engine/dist/cjs/index.cjs.map +1 -1
- package/packages/engine/dist/esm/index.js +361 -4
- package/packages/engine/dist/esm/index.js.map +1 -1
- package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/engine/dist/types/assets/mapStatistics.d.ts +20 -0
- package/packages/engine/dist/types/assets/mapStatistics.d.ts.map +1 -0
- package/packages/engine/dist/types/audio/api.d.ts +1 -0
- package/packages/engine/dist/types/audio/api.d.ts.map +1 -1
- package/packages/engine/dist/types/audio/context.d.ts +1 -0
- package/packages/engine/dist/types/audio/context.d.ts.map +1 -1
- package/packages/engine/dist/types/audio/system.d.ts +3 -0
- package/packages/engine/dist/types/audio/system.d.ts.map +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/engine/dist/types/index.d.ts +1 -0
- package/packages/engine/dist/types/index.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
|
|
@@ -1537,6 +1583,9 @@ var AudioApi = class {
|
|
|
1537
1583
|
stop_entity_sounds(entnum) {
|
|
1538
1584
|
this.system.stopEntitySounds(entnum);
|
|
1539
1585
|
}
|
|
1586
|
+
setPlaybackRate(rate) {
|
|
1587
|
+
this.system.setPlaybackRate(rate);
|
|
1588
|
+
}
|
|
1540
1589
|
set_listener(listener) {
|
|
1541
1590
|
this.system.setListener(listener);
|
|
1542
1591
|
}
|
|
@@ -4359,6 +4408,7 @@ function spatializeOrigin(origin, listener, masterVolume, attenuation, isListene
|
|
|
4359
4408
|
var AudioSystem = class {
|
|
4360
4409
|
constructor(options) {
|
|
4361
4410
|
this.activeSources = /* @__PURE__ */ new Map();
|
|
4411
|
+
this.playbackRate = 1;
|
|
4362
4412
|
this.contextController = options.context;
|
|
4363
4413
|
this.registry = options.registry;
|
|
4364
4414
|
this.playerEntity = options.playerEntity;
|
|
@@ -4380,6 +4430,15 @@ var AudioSystem = class {
|
|
|
4380
4430
|
setSfxVolume(volume) {
|
|
4381
4431
|
this.sfxVolume = volume;
|
|
4382
4432
|
}
|
|
4433
|
+
setPlaybackRate(rate) {
|
|
4434
|
+
this.playbackRate = rate;
|
|
4435
|
+
for (const active of this.activeSources.values()) {
|
|
4436
|
+
if (active.source.playbackRate) {
|
|
4437
|
+
active.source.playbackRate.value = rate;
|
|
4438
|
+
}
|
|
4439
|
+
this.updateSourceGain(active);
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4383
4442
|
async ensureRunning() {
|
|
4384
4443
|
await this.contextController.resume();
|
|
4385
4444
|
}
|
|
@@ -4402,6 +4461,9 @@ var AudioSystem = class {
|
|
|
4402
4461
|
const source = ctx.createBufferSource();
|
|
4403
4462
|
source.buffer = buffer;
|
|
4404
4463
|
source.loop = request.looping ?? false;
|
|
4464
|
+
if (source.playbackRate) {
|
|
4465
|
+
source.playbackRate.value = this.playbackRate;
|
|
4466
|
+
}
|
|
4405
4467
|
const origin = request.origin ?? this.listener.origin;
|
|
4406
4468
|
const gain = ctx.createGain();
|
|
4407
4469
|
const panner = this.createPanner(ctx, request.attenuation);
|
|
@@ -4413,7 +4475,8 @@ var AudioSystem = class {
|
|
|
4413
4475
|
const spatial = spatializeOrigin(origin, this.listener, request.volume, request.attenuation, isListenerSound);
|
|
4414
4476
|
const attenuationScale = request.volume === 0 ? 0 : Math.max(spatial.left, spatial.right) / Math.max(1, request.volume);
|
|
4415
4477
|
const gainValue = attenuationScale * (request.volume / 255) * this.masterVolume * this.sfxVolume;
|
|
4416
|
-
|
|
4478
|
+
const playbackRateMute = Math.abs(this.playbackRate - 1) < 1e-3 ? 1 : 0;
|
|
4479
|
+
gain.gain.value = gainValue * occlusionScale * playbackRateMute;
|
|
4417
4480
|
const startTimeSec = ctx.currentTime + (request.timeOffsetMs ?? 0) / 1e3;
|
|
4418
4481
|
const endTimeMs = (request.looping ? Number.POSITIVE_INFINITY : buffer.duration * 1e3) + startTimeSec * 1e3;
|
|
4419
4482
|
source.connect(panner);
|
|
@@ -4561,9 +4624,15 @@ var AudioSystem = class {
|
|
|
4561
4624
|
filter.frequency.value = clamp(cutoffHz, 10, 2e4);
|
|
4562
4625
|
return filter;
|
|
4563
4626
|
}
|
|
4627
|
+
updateSourceGain(active) {
|
|
4628
|
+
const occlusionScale = active.occlusion?.scale ?? 1;
|
|
4629
|
+
const playbackRateMute = Math.abs(this.playbackRate - 1) < 1e-3 ? 1 : 0;
|
|
4630
|
+
active.gain.gain.value = active.baseGain * occlusionScale * playbackRateMute;
|
|
4631
|
+
}
|
|
4564
4632
|
applyOcclusion(active, occlusion) {
|
|
4565
4633
|
const scale = clamp01(occlusion?.gainScale ?? 1);
|
|
4566
|
-
|
|
4634
|
+
const playbackRateMute = Math.abs(this.playbackRate - 1) < 1e-3 ? 1 : 0;
|
|
4635
|
+
active.gain.gain.value = active.baseGain * scale * playbackRateMute;
|
|
4567
4636
|
if (active.occlusion?.filter) {
|
|
4568
4637
|
const cutoff = occlusion?.lowpassHz ?? 2e4;
|
|
4569
4638
|
active.occlusion.filter.frequency.value = clamp(cutoff, 10, 2e4);
|
|
@@ -12426,6 +12495,165 @@ var NetworkMessageParser = class _NetworkMessageParser {
|
|
|
12426
12495
|
}
|
|
12427
12496
|
};
|
|
12428
12497
|
|
|
12498
|
+
// src/demo/analyzer.ts
|
|
12499
|
+
var DemoAnalyzer = class {
|
|
12500
|
+
constructor(buffer) {
|
|
12501
|
+
this.events = [];
|
|
12502
|
+
this.summary = {
|
|
12503
|
+
totalKills: 0,
|
|
12504
|
+
totalDeaths: 0,
|
|
12505
|
+
damageDealt: 0,
|
|
12506
|
+
damageReceived: 0,
|
|
12507
|
+
weaponUsage: /* @__PURE__ */ new Map()
|
|
12508
|
+
};
|
|
12509
|
+
this.header = null;
|
|
12510
|
+
this.configStrings = /* @__PURE__ */ new Map();
|
|
12511
|
+
this.serverInfo = {};
|
|
12512
|
+
this.statistics = null;
|
|
12513
|
+
this.playerStats = /* @__PURE__ */ new Map();
|
|
12514
|
+
// By playerNum
|
|
12515
|
+
this.weaponStats = /* @__PURE__ */ new Map();
|
|
12516
|
+
this.buffer = buffer;
|
|
12517
|
+
}
|
|
12518
|
+
analyze() {
|
|
12519
|
+
const reader = new DemoReader(this.buffer);
|
|
12520
|
+
let currentFrameIndex = -1;
|
|
12521
|
+
let currentTime = 0;
|
|
12522
|
+
let frameDuration = 0.1;
|
|
12523
|
+
let protocolVersion = 0;
|
|
12524
|
+
const handler = {
|
|
12525
|
+
onServerData: (protocol, serverCount, attractLoop, gameDir, playerNum, levelName, tickRate, demoType) => {
|
|
12526
|
+
protocolVersion = protocol;
|
|
12527
|
+
this.header = {
|
|
12528
|
+
protocolVersion: protocol,
|
|
12529
|
+
gameDir,
|
|
12530
|
+
levelName,
|
|
12531
|
+
playerNum,
|
|
12532
|
+
serverCount,
|
|
12533
|
+
spawnCount: serverCount,
|
|
12534
|
+
// Mapping generic arg
|
|
12535
|
+
tickRate,
|
|
12536
|
+
demoType
|
|
12537
|
+
};
|
|
12538
|
+
if (tickRate && tickRate > 0) {
|
|
12539
|
+
frameDuration = 1 / tickRate;
|
|
12540
|
+
}
|
|
12541
|
+
},
|
|
12542
|
+
onConfigString: (index, str) => {
|
|
12543
|
+
this.configStrings.set(index, str);
|
|
12544
|
+
if (index === 0) {
|
|
12545
|
+
this.parseServerInfo(str);
|
|
12546
|
+
}
|
|
12547
|
+
},
|
|
12548
|
+
onSpawnBaseline: (entity) => {
|
|
12549
|
+
},
|
|
12550
|
+
onFrame: (frame) => {
|
|
12551
|
+
},
|
|
12552
|
+
onPrint: (level, msg) => {
|
|
12553
|
+
if (msg.includes("died") || msg.includes("killed")) {
|
|
12554
|
+
this.summary.totalDeaths++;
|
|
12555
|
+
this.recordEvent({
|
|
12556
|
+
type: 4 /* Death */,
|
|
12557
|
+
frame: currentFrameIndex,
|
|
12558
|
+
time: currentTime,
|
|
12559
|
+
description: msg.trim()
|
|
12560
|
+
});
|
|
12561
|
+
}
|
|
12562
|
+
},
|
|
12563
|
+
onCenterPrint: () => {
|
|
12564
|
+
},
|
|
12565
|
+
onStuffText: () => {
|
|
12566
|
+
},
|
|
12567
|
+
onSound: () => {
|
|
12568
|
+
},
|
|
12569
|
+
onTempEntity: () => {
|
|
12570
|
+
},
|
|
12571
|
+
onLayout: () => {
|
|
12572
|
+
},
|
|
12573
|
+
onInventory: () => {
|
|
12574
|
+
},
|
|
12575
|
+
onMuzzleFlash: (ent, weapon) => {
|
|
12576
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
12577
|
+
},
|
|
12578
|
+
onMuzzleFlash2: (ent, weapon) => {
|
|
12579
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
12580
|
+
},
|
|
12581
|
+
onMuzzleFlash3: (ent, weapon) => {
|
|
12582
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
12583
|
+
},
|
|
12584
|
+
onDisconnect: () => {
|
|
12585
|
+
},
|
|
12586
|
+
onReconnect: () => {
|
|
12587
|
+
},
|
|
12588
|
+
onDownload: () => {
|
|
12589
|
+
},
|
|
12590
|
+
// Rerelease specific
|
|
12591
|
+
onDamage: (indicators) => {
|
|
12592
|
+
for (const ind of indicators) {
|
|
12593
|
+
this.recordEvent({
|
|
12594
|
+
type: 2 /* DamageReceived */,
|
|
12595
|
+
frame: currentFrameIndex,
|
|
12596
|
+
time: currentTime,
|
|
12597
|
+
value: ind.damage,
|
|
12598
|
+
position: ind.dir,
|
|
12599
|
+
description: `Took ${ind.damage} damage`
|
|
12600
|
+
});
|
|
12601
|
+
this.summary.damageReceived += ind.damage;
|
|
12602
|
+
}
|
|
12603
|
+
}
|
|
12604
|
+
};
|
|
12605
|
+
while (reader.hasMore()) {
|
|
12606
|
+
const block = reader.readNextBlock();
|
|
12607
|
+
if (!block) break;
|
|
12608
|
+
currentFrameIndex++;
|
|
12609
|
+
currentTime = currentFrameIndex * frameDuration;
|
|
12610
|
+
const parser = new NetworkMessageParser(block.data, handler);
|
|
12611
|
+
parser.setProtocolVersion(protocolVersion);
|
|
12612
|
+
parser.parseMessage();
|
|
12613
|
+
protocolVersion = parser.getProtocolVersion();
|
|
12614
|
+
}
|
|
12615
|
+
this.statistics = {
|
|
12616
|
+
duration: currentTime,
|
|
12617
|
+
frameCount: currentFrameIndex + 1,
|
|
12618
|
+
averageFps: (currentFrameIndex + 1) / (currentTime || 1),
|
|
12619
|
+
mapName: this.header?.levelName || "unknown",
|
|
12620
|
+
playerCount: 1
|
|
12621
|
+
// Default to 1 for SP/client demo
|
|
12622
|
+
};
|
|
12623
|
+
return {
|
|
12624
|
+
events: this.events,
|
|
12625
|
+
summary: this.summary,
|
|
12626
|
+
header: this.header,
|
|
12627
|
+
configStrings: this.configStrings,
|
|
12628
|
+
serverInfo: this.serverInfo,
|
|
12629
|
+
statistics: this.statistics
|
|
12630
|
+
};
|
|
12631
|
+
}
|
|
12632
|
+
handleWeaponFire(ent, weapon, frame, time) {
|
|
12633
|
+
this.recordEvent({
|
|
12634
|
+
type: 0 /* WeaponFire */,
|
|
12635
|
+
frame,
|
|
12636
|
+
time,
|
|
12637
|
+
entityId: ent,
|
|
12638
|
+
value: weapon,
|
|
12639
|
+
description: `Weapon ${weapon} fired by ${ent}`
|
|
12640
|
+
});
|
|
12641
|
+
const count = this.summary.weaponUsage.get(weapon) || 0;
|
|
12642
|
+
this.summary.weaponUsage.set(weapon, count + 1);
|
|
12643
|
+
}
|
|
12644
|
+
recordEvent(event) {
|
|
12645
|
+
this.events.push(event);
|
|
12646
|
+
}
|
|
12647
|
+
parseServerInfo(str) {
|
|
12648
|
+
const parts = str.split("\\");
|
|
12649
|
+
for (let i = 1; i < parts.length; i += 2) {
|
|
12650
|
+
if (i + 1 < parts.length) {
|
|
12651
|
+
this.serverInfo[parts[i]] = parts[i + 1];
|
|
12652
|
+
}
|
|
12653
|
+
}
|
|
12654
|
+
}
|
|
12655
|
+
};
|
|
12656
|
+
|
|
12429
12657
|
// src/demo/playback.ts
|
|
12430
12658
|
var PlaybackState = /* @__PURE__ */ ((PlaybackState2) => {
|
|
12431
12659
|
PlaybackState2[PlaybackState2["Stopped"] = 0] = "Stopped";
|
|
@@ -12437,6 +12665,8 @@ var PlaybackState = /* @__PURE__ */ ((PlaybackState2) => {
|
|
|
12437
12665
|
var DemoPlaybackController = class {
|
|
12438
12666
|
constructor() {
|
|
12439
12667
|
this.reader = null;
|
|
12668
|
+
this.buffer = null;
|
|
12669
|
+
// Keep reference for analysis
|
|
12440
12670
|
this.state = 0 /* Stopped */;
|
|
12441
12671
|
this.playbackSpeed = 1;
|
|
12442
12672
|
this.currentProtocolVersion = 0;
|
|
@@ -12452,6 +12682,13 @@ var DemoPlaybackController = class {
|
|
|
12452
12682
|
this.snapshotInterval = 100;
|
|
12453
12683
|
// frames
|
|
12454
12684
|
this.snapshots = /* @__PURE__ */ new Map();
|
|
12685
|
+
// Analysis Cache
|
|
12686
|
+
this.cachedEvents = null;
|
|
12687
|
+
this.cachedSummary = null;
|
|
12688
|
+
this.cachedHeader = null;
|
|
12689
|
+
this.cachedConfigStrings = null;
|
|
12690
|
+
this.cachedServerInfo = null;
|
|
12691
|
+
this.cachedStatistics = null;
|
|
12455
12692
|
}
|
|
12456
12693
|
setHandler(handler) {
|
|
12457
12694
|
this.handler = handler;
|
|
@@ -12460,6 +12697,7 @@ var DemoPlaybackController = class {
|
|
|
12460
12697
|
this.callbacks = callbacks;
|
|
12461
12698
|
}
|
|
12462
12699
|
loadDemo(buffer) {
|
|
12700
|
+
this.buffer = buffer;
|
|
12463
12701
|
this.reader = new DemoReader(buffer);
|
|
12464
12702
|
this.transitionState(0 /* Stopped */);
|
|
12465
12703
|
this.accumulatedTime = 0;
|
|
@@ -12467,6 +12705,12 @@ var DemoPlaybackController = class {
|
|
|
12467
12705
|
this.currentFrameIndex = -1;
|
|
12468
12706
|
this.snapshots.clear();
|
|
12469
12707
|
this.lastFrameData = null;
|
|
12708
|
+
this.cachedEvents = null;
|
|
12709
|
+
this.cachedSummary = null;
|
|
12710
|
+
this.cachedHeader = null;
|
|
12711
|
+
this.cachedConfigStrings = null;
|
|
12712
|
+
this.cachedServerInfo = null;
|
|
12713
|
+
this.cachedStatistics = null;
|
|
12470
12714
|
}
|
|
12471
12715
|
play() {
|
|
12472
12716
|
if (this.reader && this.state !== 1 /* Playing */) {
|
|
@@ -12779,6 +13023,57 @@ var DemoPlaybackController = class {
|
|
|
12779
13023
|
this.seek(originalFrame);
|
|
12780
13024
|
return trajectory;
|
|
12781
13025
|
}
|
|
13026
|
+
// 3.2.3 Event Log Extraction & 3.3 Metadata
|
|
13027
|
+
getDemoEvents() {
|
|
13028
|
+
this.ensureAnalysis();
|
|
13029
|
+
return this.cachedEvents || [];
|
|
13030
|
+
}
|
|
13031
|
+
filterEvents(type, entityId) {
|
|
13032
|
+
const events = this.getDemoEvents();
|
|
13033
|
+
return events.filter((e) => {
|
|
13034
|
+
if (e.type !== type) return false;
|
|
13035
|
+
if (entityId !== void 0 && e.entityId !== entityId) return false;
|
|
13036
|
+
return true;
|
|
13037
|
+
});
|
|
13038
|
+
}
|
|
13039
|
+
getEventSummary() {
|
|
13040
|
+
this.ensureAnalysis();
|
|
13041
|
+
return this.cachedSummary || {
|
|
13042
|
+
totalKills: 0,
|
|
13043
|
+
totalDeaths: 0,
|
|
13044
|
+
damageDealt: 0,
|
|
13045
|
+
damageReceived: 0,
|
|
13046
|
+
weaponUsage: /* @__PURE__ */ new Map()
|
|
13047
|
+
};
|
|
13048
|
+
}
|
|
13049
|
+
getDemoHeader() {
|
|
13050
|
+
this.ensureAnalysis();
|
|
13051
|
+
return this.cachedHeader;
|
|
13052
|
+
}
|
|
13053
|
+
getDemoConfigStrings() {
|
|
13054
|
+
this.ensureAnalysis();
|
|
13055
|
+
return this.cachedConfigStrings || /* @__PURE__ */ new Map();
|
|
13056
|
+
}
|
|
13057
|
+
getDemoServerInfo() {
|
|
13058
|
+
this.ensureAnalysis();
|
|
13059
|
+
return this.cachedServerInfo || {};
|
|
13060
|
+
}
|
|
13061
|
+
getDemoStatistics() {
|
|
13062
|
+
this.ensureAnalysis();
|
|
13063
|
+
return this.cachedStatistics;
|
|
13064
|
+
}
|
|
13065
|
+
ensureAnalysis() {
|
|
13066
|
+
if (!this.cachedEvents && this.buffer) {
|
|
13067
|
+
const analyzer = new DemoAnalyzer(this.buffer);
|
|
13068
|
+
const result = analyzer.analyze();
|
|
13069
|
+
this.cachedEvents = result.events;
|
|
13070
|
+
this.cachedSummary = result.summary;
|
|
13071
|
+
this.cachedHeader = result.header;
|
|
13072
|
+
this.cachedConfigStrings = result.configStrings;
|
|
13073
|
+
this.cachedServerInfo = result.serverInfo;
|
|
13074
|
+
this.cachedStatistics = result.statistics;
|
|
13075
|
+
}
|
|
13076
|
+
}
|
|
12782
13077
|
};
|
|
12783
13078
|
|
|
12784
13079
|
// src/demo/recorder.ts
|
|
@@ -13127,6 +13422,67 @@ var AssetPreviewGenerator = class {
|
|
|
13127
13422
|
}
|
|
13128
13423
|
};
|
|
13129
13424
|
|
|
13425
|
+
// src/assets/mapStatistics.ts
|
|
13426
|
+
var MapAnalyzer = class {
|
|
13427
|
+
constructor(loader) {
|
|
13428
|
+
this.loader = loader;
|
|
13429
|
+
}
|
|
13430
|
+
async getMapStatistics(mapName) {
|
|
13431
|
+
const map = await this.loader.load(mapName);
|
|
13432
|
+
const lightmapCount = map.faces.filter((f) => f.lightOffset !== -1).length;
|
|
13433
|
+
const worldModel = map.models[0];
|
|
13434
|
+
const bounds = worldModel ? {
|
|
13435
|
+
mins: worldModel.mins,
|
|
13436
|
+
maxs: worldModel.maxs
|
|
13437
|
+
} : {
|
|
13438
|
+
mins: [0, 0, 0],
|
|
13439
|
+
maxs: [0, 0, 0]
|
|
13440
|
+
};
|
|
13441
|
+
return {
|
|
13442
|
+
entityCount: map.entities.entities.length,
|
|
13443
|
+
surfaceCount: map.faces.length,
|
|
13444
|
+
lightmapCount,
|
|
13445
|
+
vertexCount: map.vertices.length,
|
|
13446
|
+
bounds
|
|
13447
|
+
};
|
|
13448
|
+
}
|
|
13449
|
+
async getUsedTextures(mapName) {
|
|
13450
|
+
const map = await this.loader.load(mapName);
|
|
13451
|
+
const textures = /* @__PURE__ */ new Set();
|
|
13452
|
+
for (const info of map.texInfo) {
|
|
13453
|
+
if (info.texture) {
|
|
13454
|
+
textures.add(info.texture);
|
|
13455
|
+
}
|
|
13456
|
+
}
|
|
13457
|
+
return Array.from(textures).sort();
|
|
13458
|
+
}
|
|
13459
|
+
async getUsedModels(mapName) {
|
|
13460
|
+
const map = await this.loader.load(mapName);
|
|
13461
|
+
const models = /* @__PURE__ */ new Set();
|
|
13462
|
+
for (const ent of map.entities.entities) {
|
|
13463
|
+
if (ent.properties["model"] && !ent.properties["model"].startsWith("*")) {
|
|
13464
|
+
models.add(ent.properties["model"]);
|
|
13465
|
+
}
|
|
13466
|
+
}
|
|
13467
|
+
return Array.from(models).sort();
|
|
13468
|
+
}
|
|
13469
|
+
async getUsedSounds(mapName) {
|
|
13470
|
+
const map = await this.loader.load(mapName);
|
|
13471
|
+
const sounds = /* @__PURE__ */ new Set();
|
|
13472
|
+
for (const ent of map.entities.entities) {
|
|
13473
|
+
if (ent.properties["noise"]) {
|
|
13474
|
+
sounds.add(ent.properties["noise"]);
|
|
13475
|
+
}
|
|
13476
|
+
for (const [key, value] of Object.entries(ent.properties)) {
|
|
13477
|
+
if ((key === "noise" || key.endsWith("_sound") || key === "sound") && typeof value === "string") {
|
|
13478
|
+
sounds.add(value);
|
|
13479
|
+
}
|
|
13480
|
+
}
|
|
13481
|
+
}
|
|
13482
|
+
return Array.from(sounds).sort();
|
|
13483
|
+
}
|
|
13484
|
+
};
|
|
13485
|
+
|
|
13130
13486
|
// src/index.ts
|
|
13131
13487
|
function createEngine(imports) {
|
|
13132
13488
|
return {
|
|
@@ -13183,6 +13539,7 @@ export {
|
|
|
13183
13539
|
MD2_VERTEX_SHADER,
|
|
13184
13540
|
MD3_FRAGMENT_SHADER,
|
|
13185
13541
|
MD3_VERTEX_SHADER,
|
|
13542
|
+
MapAnalyzer,
|
|
13186
13543
|
Md2Loader,
|
|
13187
13544
|
Md2MeshBuffers,
|
|
13188
13545
|
Md2ParseError,
|