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
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
ClientConfigStrings: () => ClientConfigStrings,
|
|
24
24
|
ClientMode: () => ClientMode,
|
|
25
25
|
ClientPrediction: () => import_cgame5.ClientPrediction,
|
|
26
|
+
DemoCameraMode: () => DemoCameraMode,
|
|
26
27
|
GameSession: () => GameSession,
|
|
27
28
|
InputAction: () => InputAction,
|
|
28
29
|
InputBindings: () => InputBindings,
|
|
@@ -1855,6 +1856,9 @@ var CommandRegistry = class {
|
|
|
1855
1856
|
this.commands.set(name, command);
|
|
1856
1857
|
return command;
|
|
1857
1858
|
}
|
|
1859
|
+
registerCommand(name, callback) {
|
|
1860
|
+
this.register(name, callback);
|
|
1861
|
+
}
|
|
1858
1862
|
get(name) {
|
|
1859
1863
|
return this.commands.get(name);
|
|
1860
1864
|
}
|
|
@@ -1870,10 +1874,33 @@ var CommandRegistry = class {
|
|
|
1870
1874
|
command.execute(args);
|
|
1871
1875
|
return true;
|
|
1872
1876
|
}
|
|
1877
|
+
this.onConsoleOutput?.(`Unknown command "${name}"`);
|
|
1873
1878
|
return false;
|
|
1874
1879
|
}
|
|
1880
|
+
executeCommand(cmd) {
|
|
1881
|
+
this.execute(cmd);
|
|
1882
|
+
}
|
|
1875
1883
|
tokenize(text) {
|
|
1876
|
-
|
|
1884
|
+
const args = [];
|
|
1885
|
+
let currentArg = "";
|
|
1886
|
+
let inQuote = false;
|
|
1887
|
+
for (let i = 0; i < text.length; i++) {
|
|
1888
|
+
const char = text[i];
|
|
1889
|
+
if (char === '"') {
|
|
1890
|
+
inQuote = !inQuote;
|
|
1891
|
+
} else if (char === " " && !inQuote) {
|
|
1892
|
+
if (currentArg.length > 0) {
|
|
1893
|
+
args.push(currentArg);
|
|
1894
|
+
currentArg = "";
|
|
1895
|
+
}
|
|
1896
|
+
} else {
|
|
1897
|
+
currentArg += char;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
if (currentArg.length > 0) {
|
|
1901
|
+
args.push(currentArg);
|
|
1902
|
+
}
|
|
1903
|
+
return args;
|
|
1877
1904
|
}
|
|
1878
1905
|
list() {
|
|
1879
1906
|
return [...this.commands.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -2958,13 +2985,21 @@ var CvarRegistry = class {
|
|
|
2958
2985
|
if (existing) {
|
|
2959
2986
|
return existing;
|
|
2960
2987
|
}
|
|
2961
|
-
const
|
|
2988
|
+
const originalOnChange = def.onChange;
|
|
2989
|
+
const wrappedOnChange = (cvar2, prev) => {
|
|
2990
|
+
originalOnChange?.(cvar2, prev);
|
|
2991
|
+
this.onCvarChange?.(cvar2.name, cvar2.string);
|
|
2992
|
+
};
|
|
2993
|
+
const cvar = new Cvar({ ...def, onChange: wrappedOnChange });
|
|
2962
2994
|
this.cvars.set(def.name, cvar);
|
|
2963
2995
|
return cvar;
|
|
2964
2996
|
}
|
|
2965
2997
|
get(name) {
|
|
2966
2998
|
return this.cvars.get(name);
|
|
2967
2999
|
}
|
|
3000
|
+
getCvar(name) {
|
|
3001
|
+
return this.get(name);
|
|
3002
|
+
}
|
|
2968
3003
|
setValue(name, value) {
|
|
2969
3004
|
const cvar = this.get(name);
|
|
2970
3005
|
if (!cvar) {
|
|
@@ -2973,6 +3008,9 @@ var CvarRegistry = class {
|
|
|
2973
3008
|
cvar.set(value);
|
|
2974
3009
|
return cvar;
|
|
2975
3010
|
}
|
|
3011
|
+
setCvar(name, value) {
|
|
3012
|
+
this.setValue(name, value);
|
|
3013
|
+
}
|
|
2976
3014
|
resetAll() {
|
|
2977
3015
|
for (const cvar of this.cvars.values()) {
|
|
2978
3016
|
cvar.reset();
|
|
@@ -2988,6 +3026,15 @@ var CvarRegistry = class {
|
|
|
2988
3026
|
list() {
|
|
2989
3027
|
return [...this.cvars.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
2990
3028
|
}
|
|
3029
|
+
listCvars() {
|
|
3030
|
+
return this.list().map((cvar) => ({
|
|
3031
|
+
name: cvar.name,
|
|
3032
|
+
value: cvar.string,
|
|
3033
|
+
defaultValue: cvar.defaultValue,
|
|
3034
|
+
flags: cvar.flags,
|
|
3035
|
+
description: cvar.description
|
|
3036
|
+
}));
|
|
3037
|
+
}
|
|
2991
3038
|
};
|
|
2992
3039
|
var EngineHost = class {
|
|
2993
3040
|
constructor(game, client, options = {}) {
|
|
@@ -8796,6 +8843,162 @@ var NetworkMessageParser = class _NetworkMessageParser {
|
|
|
8796
8843
|
}
|
|
8797
8844
|
}
|
|
8798
8845
|
};
|
|
8846
|
+
var DemoAnalyzer = class {
|
|
8847
|
+
constructor(buffer) {
|
|
8848
|
+
this.events = [];
|
|
8849
|
+
this.summary = {
|
|
8850
|
+
totalKills: 0,
|
|
8851
|
+
totalDeaths: 0,
|
|
8852
|
+
damageDealt: 0,
|
|
8853
|
+
damageReceived: 0,
|
|
8854
|
+
weaponUsage: /* @__PURE__ */ new Map()
|
|
8855
|
+
};
|
|
8856
|
+
this.header = null;
|
|
8857
|
+
this.configStrings = /* @__PURE__ */ new Map();
|
|
8858
|
+
this.serverInfo = {};
|
|
8859
|
+
this.statistics = null;
|
|
8860
|
+
this.playerStats = /* @__PURE__ */ new Map();
|
|
8861
|
+
this.weaponStats = /* @__PURE__ */ new Map();
|
|
8862
|
+
this.buffer = buffer;
|
|
8863
|
+
}
|
|
8864
|
+
analyze() {
|
|
8865
|
+
const reader = new DemoReader(this.buffer);
|
|
8866
|
+
let currentFrameIndex = -1;
|
|
8867
|
+
let currentTime = 0;
|
|
8868
|
+
let frameDuration = 0.1;
|
|
8869
|
+
let protocolVersion = 0;
|
|
8870
|
+
const handler = {
|
|
8871
|
+
onServerData: (protocol, serverCount, attractLoop, gameDir, playerNum, levelName, tickRate, demoType) => {
|
|
8872
|
+
protocolVersion = protocol;
|
|
8873
|
+
this.header = {
|
|
8874
|
+
protocolVersion: protocol,
|
|
8875
|
+
gameDir,
|
|
8876
|
+
levelName,
|
|
8877
|
+
playerNum,
|
|
8878
|
+
serverCount,
|
|
8879
|
+
spawnCount: serverCount,
|
|
8880
|
+
// Mapping generic arg
|
|
8881
|
+
tickRate,
|
|
8882
|
+
demoType
|
|
8883
|
+
};
|
|
8884
|
+
if (tickRate && tickRate > 0) {
|
|
8885
|
+
frameDuration = 1 / tickRate;
|
|
8886
|
+
}
|
|
8887
|
+
},
|
|
8888
|
+
onConfigString: (index, str3) => {
|
|
8889
|
+
this.configStrings.set(index, str3);
|
|
8890
|
+
if (index === 0) {
|
|
8891
|
+
this.parseServerInfo(str3);
|
|
8892
|
+
}
|
|
8893
|
+
},
|
|
8894
|
+
onSpawnBaseline: (entity) => {
|
|
8895
|
+
},
|
|
8896
|
+
onFrame: (frame) => {
|
|
8897
|
+
},
|
|
8898
|
+
onPrint: (level, msg) => {
|
|
8899
|
+
if (msg.includes("died") || msg.includes("killed")) {
|
|
8900
|
+
this.summary.totalDeaths++;
|
|
8901
|
+
this.recordEvent({
|
|
8902
|
+
type: 4,
|
|
8903
|
+
frame: currentFrameIndex,
|
|
8904
|
+
time: currentTime,
|
|
8905
|
+
description: msg.trim()
|
|
8906
|
+
});
|
|
8907
|
+
}
|
|
8908
|
+
},
|
|
8909
|
+
onCenterPrint: () => {
|
|
8910
|
+
},
|
|
8911
|
+
onStuffText: () => {
|
|
8912
|
+
},
|
|
8913
|
+
onSound: () => {
|
|
8914
|
+
},
|
|
8915
|
+
onTempEntity: () => {
|
|
8916
|
+
},
|
|
8917
|
+
onLayout: () => {
|
|
8918
|
+
},
|
|
8919
|
+
onInventory: () => {
|
|
8920
|
+
},
|
|
8921
|
+
onMuzzleFlash: (ent, weapon) => {
|
|
8922
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
8923
|
+
},
|
|
8924
|
+
onMuzzleFlash2: (ent, weapon) => {
|
|
8925
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
8926
|
+
},
|
|
8927
|
+
onMuzzleFlash3: (ent, weapon) => {
|
|
8928
|
+
this.handleWeaponFire(ent, weapon, currentFrameIndex, currentTime);
|
|
8929
|
+
},
|
|
8930
|
+
onDisconnect: () => {
|
|
8931
|
+
},
|
|
8932
|
+
onReconnect: () => {
|
|
8933
|
+
},
|
|
8934
|
+
onDownload: () => {
|
|
8935
|
+
},
|
|
8936
|
+
// Rerelease specific
|
|
8937
|
+
onDamage: (indicators) => {
|
|
8938
|
+
for (const ind of indicators) {
|
|
8939
|
+
this.recordEvent({
|
|
8940
|
+
type: 2,
|
|
8941
|
+
frame: currentFrameIndex,
|
|
8942
|
+
time: currentTime,
|
|
8943
|
+
value: ind.damage,
|
|
8944
|
+
position: ind.dir,
|
|
8945
|
+
description: `Took ${ind.damage} damage`
|
|
8946
|
+
});
|
|
8947
|
+
this.summary.damageReceived += ind.damage;
|
|
8948
|
+
}
|
|
8949
|
+
}
|
|
8950
|
+
};
|
|
8951
|
+
while (reader.hasMore()) {
|
|
8952
|
+
const block = reader.readNextBlock();
|
|
8953
|
+
if (!block) break;
|
|
8954
|
+
currentFrameIndex++;
|
|
8955
|
+
currentTime = currentFrameIndex * frameDuration;
|
|
8956
|
+
const parser = new NetworkMessageParser(block.data, handler);
|
|
8957
|
+
parser.setProtocolVersion(protocolVersion);
|
|
8958
|
+
parser.parseMessage();
|
|
8959
|
+
protocolVersion = parser.getProtocolVersion();
|
|
8960
|
+
}
|
|
8961
|
+
this.statistics = {
|
|
8962
|
+
duration: currentTime,
|
|
8963
|
+
frameCount: currentFrameIndex + 1,
|
|
8964
|
+
averageFps: (currentFrameIndex + 1) / (currentTime || 1),
|
|
8965
|
+
mapName: this.header?.levelName || "unknown",
|
|
8966
|
+
playerCount: 1
|
|
8967
|
+
// Default to 1 for SP/client demo
|
|
8968
|
+
};
|
|
8969
|
+
return {
|
|
8970
|
+
events: this.events,
|
|
8971
|
+
summary: this.summary,
|
|
8972
|
+
header: this.header,
|
|
8973
|
+
configStrings: this.configStrings,
|
|
8974
|
+
serverInfo: this.serverInfo,
|
|
8975
|
+
statistics: this.statistics
|
|
8976
|
+
};
|
|
8977
|
+
}
|
|
8978
|
+
handleWeaponFire(ent, weapon, frame, time) {
|
|
8979
|
+
this.recordEvent({
|
|
8980
|
+
type: 0,
|
|
8981
|
+
frame,
|
|
8982
|
+
time,
|
|
8983
|
+
entityId: ent,
|
|
8984
|
+
value: weapon,
|
|
8985
|
+
description: `Weapon ${weapon} fired by ${ent}`
|
|
8986
|
+
});
|
|
8987
|
+
const count = this.summary.weaponUsage.get(weapon) || 0;
|
|
8988
|
+
this.summary.weaponUsage.set(weapon, count + 1);
|
|
8989
|
+
}
|
|
8990
|
+
recordEvent(event) {
|
|
8991
|
+
this.events.push(event);
|
|
8992
|
+
}
|
|
8993
|
+
parseServerInfo(str3) {
|
|
8994
|
+
const parts = str3.split("\\");
|
|
8995
|
+
for (let i = 1; i < parts.length; i += 2) {
|
|
8996
|
+
if (i + 1 < parts.length) {
|
|
8997
|
+
this.serverInfo[parts[i]] = parts[i + 1];
|
|
8998
|
+
}
|
|
8999
|
+
}
|
|
9000
|
+
}
|
|
9001
|
+
};
|
|
8799
9002
|
var PlaybackState = /* @__PURE__ */ ((PlaybackState22) => {
|
|
8800
9003
|
PlaybackState22[PlaybackState22["Stopped"] = 0] = "Stopped";
|
|
8801
9004
|
PlaybackState22[PlaybackState22["Playing"] = 1] = "Playing";
|
|
@@ -8806,6 +9009,7 @@ var PlaybackState = /* @__PURE__ */ ((PlaybackState22) => {
|
|
|
8806
9009
|
var DemoPlaybackController = class {
|
|
8807
9010
|
constructor() {
|
|
8808
9011
|
this.reader = null;
|
|
9012
|
+
this.buffer = null;
|
|
8809
9013
|
this.state = 0;
|
|
8810
9014
|
this.playbackSpeed = 1;
|
|
8811
9015
|
this.currentProtocolVersion = 0;
|
|
@@ -8815,6 +9019,12 @@ var DemoPlaybackController = class {
|
|
|
8815
9019
|
this.frameDuration = 100;
|
|
8816
9020
|
this.snapshotInterval = 100;
|
|
8817
9021
|
this.snapshots = /* @__PURE__ */ new Map();
|
|
9022
|
+
this.cachedEvents = null;
|
|
9023
|
+
this.cachedSummary = null;
|
|
9024
|
+
this.cachedHeader = null;
|
|
9025
|
+
this.cachedConfigStrings = null;
|
|
9026
|
+
this.cachedServerInfo = null;
|
|
9027
|
+
this.cachedStatistics = null;
|
|
8818
9028
|
}
|
|
8819
9029
|
setHandler(handler) {
|
|
8820
9030
|
this.handler = handler;
|
|
@@ -8823,6 +9033,7 @@ var DemoPlaybackController = class {
|
|
|
8823
9033
|
this.callbacks = callbacks;
|
|
8824
9034
|
}
|
|
8825
9035
|
loadDemo(buffer) {
|
|
9036
|
+
this.buffer = buffer;
|
|
8826
9037
|
this.reader = new DemoReader(buffer);
|
|
8827
9038
|
this.transitionState(
|
|
8828
9039
|
0
|
|
@@ -8833,6 +9044,12 @@ var DemoPlaybackController = class {
|
|
|
8833
9044
|
this.currentFrameIndex = -1;
|
|
8834
9045
|
this.snapshots.clear();
|
|
8835
9046
|
this.lastFrameData = null;
|
|
9047
|
+
this.cachedEvents = null;
|
|
9048
|
+
this.cachedSummary = null;
|
|
9049
|
+
this.cachedHeader = null;
|
|
9050
|
+
this.cachedConfigStrings = null;
|
|
9051
|
+
this.cachedServerInfo = null;
|
|
9052
|
+
this.cachedStatistics = null;
|
|
8836
9053
|
}
|
|
8837
9054
|
play() {
|
|
8838
9055
|
if (this.reader && this.state !== 1) {
|
|
@@ -9160,6 +9377,57 @@ var DemoPlaybackController = class {
|
|
|
9160
9377
|
this.seek(originalFrame);
|
|
9161
9378
|
return trajectory;
|
|
9162
9379
|
}
|
|
9380
|
+
// 3.2.3 Event Log Extraction & 3.3 Metadata
|
|
9381
|
+
getDemoEvents() {
|
|
9382
|
+
this.ensureAnalysis();
|
|
9383
|
+
return this.cachedEvents || [];
|
|
9384
|
+
}
|
|
9385
|
+
filterEvents(type, entityId) {
|
|
9386
|
+
const events = this.getDemoEvents();
|
|
9387
|
+
return events.filter((e) => {
|
|
9388
|
+
if (e.type !== type) return false;
|
|
9389
|
+
if (entityId !== void 0 && e.entityId !== entityId) return false;
|
|
9390
|
+
return true;
|
|
9391
|
+
});
|
|
9392
|
+
}
|
|
9393
|
+
getEventSummary() {
|
|
9394
|
+
this.ensureAnalysis();
|
|
9395
|
+
return this.cachedSummary || {
|
|
9396
|
+
totalKills: 0,
|
|
9397
|
+
totalDeaths: 0,
|
|
9398
|
+
damageDealt: 0,
|
|
9399
|
+
damageReceived: 0,
|
|
9400
|
+
weaponUsage: /* @__PURE__ */ new Map()
|
|
9401
|
+
};
|
|
9402
|
+
}
|
|
9403
|
+
getDemoHeader() {
|
|
9404
|
+
this.ensureAnalysis();
|
|
9405
|
+
return this.cachedHeader;
|
|
9406
|
+
}
|
|
9407
|
+
getDemoConfigStrings() {
|
|
9408
|
+
this.ensureAnalysis();
|
|
9409
|
+
return this.cachedConfigStrings || /* @__PURE__ */ new Map();
|
|
9410
|
+
}
|
|
9411
|
+
getDemoServerInfo() {
|
|
9412
|
+
this.ensureAnalysis();
|
|
9413
|
+
return this.cachedServerInfo || {};
|
|
9414
|
+
}
|
|
9415
|
+
getDemoStatistics() {
|
|
9416
|
+
this.ensureAnalysis();
|
|
9417
|
+
return this.cachedStatistics;
|
|
9418
|
+
}
|
|
9419
|
+
ensureAnalysis() {
|
|
9420
|
+
if (!this.cachedEvents && this.buffer) {
|
|
9421
|
+
const analyzer = new DemoAnalyzer(this.buffer);
|
|
9422
|
+
const result = analyzer.analyze();
|
|
9423
|
+
this.cachedEvents = result.events;
|
|
9424
|
+
this.cachedSummary = result.summary;
|
|
9425
|
+
this.cachedHeader = result.header;
|
|
9426
|
+
this.cachedConfigStrings = result.configStrings;
|
|
9427
|
+
this.cachedServerInfo = result.serverInfo;
|
|
9428
|
+
this.cachedStatistics = result.statistics;
|
|
9429
|
+
}
|
|
9430
|
+
}
|
|
9163
9431
|
};
|
|
9164
9432
|
var DemoRecorder = class {
|
|
9165
9433
|
// -1 means start of demo
|
|
@@ -9239,12 +9507,56 @@ var __export3 = (target, all) => {
|
|
|
9239
9507
|
};
|
|
9240
9508
|
var ZERO_VEC3 = { x: 0, y: 0, z: 0 };
|
|
9241
9509
|
var DEG_TO_RAD2 = Math.PI / 180;
|
|
9510
|
+
var PITCH = 0;
|
|
9511
|
+
var YAW = 1;
|
|
9512
|
+
var ROLL = 2;
|
|
9242
9513
|
var DEG2RAD_FACTOR2 = Math.PI / 180;
|
|
9243
9514
|
var RAD2DEG_FACTOR2 = 180 / Math.PI;
|
|
9515
|
+
function axisComponent(vec, axis) {
|
|
9516
|
+
switch (axis) {
|
|
9517
|
+
case PITCH:
|
|
9518
|
+
return vec.x;
|
|
9519
|
+
case YAW:
|
|
9520
|
+
return vec.y;
|
|
9521
|
+
case ROLL:
|
|
9522
|
+
default:
|
|
9523
|
+
return vec.z;
|
|
9524
|
+
}
|
|
9525
|
+
}
|
|
9526
|
+
function degToRad(degrees) {
|
|
9527
|
+
return degrees * DEG2RAD_FACTOR2;
|
|
9528
|
+
}
|
|
9244
9529
|
function angleMod(angle2) {
|
|
9245
9530
|
const value = angle2 % 360;
|
|
9246
9531
|
return value < 0 ? 360 + value : value;
|
|
9247
9532
|
}
|
|
9533
|
+
function angleVectors(angles) {
|
|
9534
|
+
const yaw = degToRad(axisComponent(angles, YAW));
|
|
9535
|
+
const pitch = degToRad(axisComponent(angles, PITCH));
|
|
9536
|
+
const roll = degToRad(axisComponent(angles, ROLL));
|
|
9537
|
+
const sy = Math.sin(yaw);
|
|
9538
|
+
const cy = Math.cos(yaw);
|
|
9539
|
+
const sp = Math.sin(pitch);
|
|
9540
|
+
const cp = Math.cos(pitch);
|
|
9541
|
+
const sr = Math.sin(roll);
|
|
9542
|
+
const cr = Math.cos(roll);
|
|
9543
|
+
const forward = {
|
|
9544
|
+
x: cp * cy,
|
|
9545
|
+
y: cp * sy,
|
|
9546
|
+
z: -sp
|
|
9547
|
+
};
|
|
9548
|
+
const right = {
|
|
9549
|
+
x: -sr * sp * cy - cr * -sy,
|
|
9550
|
+
y: -sr * sp * sy - cr * cy,
|
|
9551
|
+
z: -sr * cp
|
|
9552
|
+
};
|
|
9553
|
+
const up = {
|
|
9554
|
+
x: cr * sp * cy - sr * -sy,
|
|
9555
|
+
y: cr * sp * sy - sr * cy,
|
|
9556
|
+
z: cr * cp
|
|
9557
|
+
};
|
|
9558
|
+
return { forward, right, up };
|
|
9559
|
+
}
|
|
9248
9560
|
var ANORMS2 = [
|
|
9249
9561
|
[-0.525731, 0, 0.850651],
|
|
9250
9562
|
[-0.442863, 0.238856, 0.864188],
|
|
@@ -13140,10 +13452,11 @@ var MultiplayerConnection = class {
|
|
|
13140
13452
|
|
|
13141
13453
|
// src/ui/demo-controls.ts
|
|
13142
13454
|
var DemoControls = class {
|
|
13143
|
-
constructor(playback) {
|
|
13455
|
+
constructor(playback, onSpeedChange) {
|
|
13144
13456
|
this.isVisible = true;
|
|
13145
13457
|
this.demoName = null;
|
|
13146
13458
|
this.playback = playback;
|
|
13459
|
+
this.onSpeedChange = onSpeedChange;
|
|
13147
13460
|
}
|
|
13148
13461
|
setDemoName(name) {
|
|
13149
13462
|
this.demoName = name;
|
|
@@ -13221,6 +13534,9 @@ var DemoControls = class {
|
|
|
13221
13534
|
if (newSpeed < 0.1) newSpeed = 0.1;
|
|
13222
13535
|
if (newSpeed > 16) newSpeed = 16;
|
|
13223
13536
|
this.playback.setSpeed(newSpeed);
|
|
13537
|
+
if (this.onSpeedChange) {
|
|
13538
|
+
this.onSpeedChange(newSpeed);
|
|
13539
|
+
}
|
|
13224
13540
|
}
|
|
13225
13541
|
formatTime(ms) {
|
|
13226
13542
|
const totalSeconds = Math.floor(ms / 1e3);
|
|
@@ -13230,6 +13546,15 @@ var DemoControls = class {
|
|
|
13230
13546
|
}
|
|
13231
13547
|
};
|
|
13232
13548
|
|
|
13549
|
+
// src/demo/camera.ts
|
|
13550
|
+
var DemoCameraMode = /* @__PURE__ */ ((DemoCameraMode2) => {
|
|
13551
|
+
DemoCameraMode2[DemoCameraMode2["FirstPerson"] = 0] = "FirstPerson";
|
|
13552
|
+
DemoCameraMode2[DemoCameraMode2["ThirdPerson"] = 1] = "ThirdPerson";
|
|
13553
|
+
DemoCameraMode2[DemoCameraMode2["Free"] = 2] = "Free";
|
|
13554
|
+
DemoCameraMode2[DemoCameraMode2["Follow"] = 3] = "Follow";
|
|
13555
|
+
return DemoCameraMode2;
|
|
13556
|
+
})(DemoCameraMode || {});
|
|
13557
|
+
|
|
13233
13558
|
// src/effects.ts
|
|
13234
13559
|
function addDLight(dlights, origin, color, intensity, minLight = 0, die = 0) {
|
|
13235
13560
|
dlights.push({
|
|
@@ -13917,13 +14242,28 @@ function createClient(imports) {
|
|
|
13917
14242
|
const prediction = new import_cgame3.ClientPrediction(imports.engine.trace, pointContents);
|
|
13918
14243
|
const view = new import_cgame4.ViewEffects();
|
|
13919
14244
|
const demoPlayback = new DemoPlaybackController();
|
|
13920
|
-
const demoControls = new DemoControls(demoPlayback)
|
|
14245
|
+
const demoControls = new DemoControls(demoPlayback, (speed) => {
|
|
14246
|
+
if (imports.engine.audio) {
|
|
14247
|
+
const audio = imports.engine.audio;
|
|
14248
|
+
if (typeof audio.setPlaybackRate === "function") {
|
|
14249
|
+
audio.setPlaybackRate(speed);
|
|
14250
|
+
}
|
|
14251
|
+
}
|
|
14252
|
+
});
|
|
13921
14253
|
const demoHandler = new ClientNetworkHandler(imports);
|
|
13922
14254
|
const demoRecorder = new DemoRecorder();
|
|
13923
14255
|
demoHandler.setView(view);
|
|
13924
14256
|
let isDemoPlaying = false;
|
|
13925
14257
|
let currentDemoName = null;
|
|
13926
14258
|
let clientMode = 0 /* Normal */;
|
|
14259
|
+
const demoCameraState = {
|
|
14260
|
+
mode: 0 /* FirstPerson */,
|
|
14261
|
+
thirdPersonDistance: 80,
|
|
14262
|
+
thirdPersonOffset: { x: 0, y: 0, z: 0 },
|
|
14263
|
+
freeCameraOrigin: { x: 0, y: 0, z: 0 },
|
|
14264
|
+
freeCameraAngles: { x: 0, y: 0, z: 0 },
|
|
14265
|
+
followEntityId: -1
|
|
14266
|
+
};
|
|
13927
14267
|
const menuSystem = new MenuSystem();
|
|
13928
14268
|
const loadingScreen = new LoadingScreen();
|
|
13929
14269
|
const errorDialog = new ErrorDialog();
|
|
@@ -14138,6 +14478,8 @@ function createClient(imports) {
|
|
|
14138
14478
|
},
|
|
14139
14479
|
handleInput(key, down) {
|
|
14140
14480
|
if (isDemoPlaying) {
|
|
14481
|
+
if (demoCameraState.mode === 2 /* Free */) {
|
|
14482
|
+
}
|
|
14141
14483
|
if (demoControls.handleInput(key, down)) {
|
|
14142
14484
|
return true;
|
|
14143
14485
|
}
|
|
@@ -14223,18 +14565,51 @@ function createClient(imports) {
|
|
|
14223
14565
|
lastRenderTime = now;
|
|
14224
14566
|
demoPlayback.update(dt);
|
|
14225
14567
|
lastRendered = demoHandler.getPredictionState(demoPlayback.getCurrentTime());
|
|
14226
|
-
const frameDuration = 100;
|
|
14227
14568
|
renderEntities = demoHandler.getRenderableEntities(1, configStrings);
|
|
14228
14569
|
if (demoHandler.latestFrame && demoHandler.latestFrame.packetEntities) {
|
|
14229
14570
|
currentPacketEntities = demoHandler.latestFrame.packetEntities.entities;
|
|
14230
14571
|
}
|
|
14231
14572
|
if (lastRendered) {
|
|
14232
14573
|
const demoCamera = demoHandler.getDemoCamera(1);
|
|
14233
|
-
if (
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14574
|
+
if (demoCameraState.mode === 0 /* FirstPerson */) {
|
|
14575
|
+
if (demoCamera) {
|
|
14576
|
+
lastRendered.origin = demoCamera.origin;
|
|
14577
|
+
lastRendered.viewAngles = demoCamera.angles;
|
|
14578
|
+
if (demoCamera.fov) {
|
|
14579
|
+
lastRendered.fov = demoCamera.fov;
|
|
14580
|
+
}
|
|
14581
|
+
}
|
|
14582
|
+
} else if (demoCameraState.mode === 1 /* ThirdPerson */) {
|
|
14583
|
+
if (demoCamera) {
|
|
14584
|
+
const vectors = angleVectors(demoCamera.angles);
|
|
14585
|
+
const forward = vectors.forward;
|
|
14586
|
+
const dist2 = demoCameraState.thirdPersonDistance;
|
|
14587
|
+
const camOrigin = { ...demoCamera.origin };
|
|
14588
|
+
camOrigin.x -= forward.x * dist2;
|
|
14589
|
+
camOrigin.y -= forward.y * dist2;
|
|
14590
|
+
camOrigin.z -= forward.z * dist2;
|
|
14591
|
+
const traceStart = demoCamera.origin;
|
|
14592
|
+
const traceEnd = camOrigin;
|
|
14593
|
+
const mins = { x: -4, y: -4, z: -4 };
|
|
14594
|
+
const maxs = { x: 4, y: 4, z: 4 };
|
|
14595
|
+
const trace = imports.engine.trace(traceStart, traceEnd, mins, maxs);
|
|
14596
|
+
if (trace.fraction < 1) {
|
|
14597
|
+
lastRendered.origin = trace.endpos;
|
|
14598
|
+
} else {
|
|
14599
|
+
lastRendered.origin = camOrigin;
|
|
14600
|
+
}
|
|
14601
|
+
lastRendered.viewAngles = demoCamera.angles;
|
|
14602
|
+
}
|
|
14603
|
+
} else if (demoCameraState.mode === 2 /* Free */) {
|
|
14604
|
+
lastRendered.origin = demoCameraState.freeCameraOrigin;
|
|
14605
|
+
lastRendered.viewAngles = demoCameraState.freeCameraAngles;
|
|
14606
|
+
} else if (demoCameraState.mode === 3 /* Follow */) {
|
|
14607
|
+
if (demoCameraState.followEntityId !== -1) {
|
|
14608
|
+
const ent = renderEntities.find((e) => e.id === demoCameraState.followEntityId);
|
|
14609
|
+
if (ent) {
|
|
14610
|
+
const mat = ent.transform;
|
|
14611
|
+
lastRendered.origin = { x: mat[12], y: mat[13], z: mat[14] };
|
|
14612
|
+
}
|
|
14238
14613
|
}
|
|
14239
14614
|
}
|
|
14240
14615
|
}
|
|
@@ -14274,8 +14649,10 @@ function createClient(imports) {
|
|
|
14274
14649
|
const { origin, viewAngles } = lastRendered;
|
|
14275
14650
|
camera = new Camera();
|
|
14276
14651
|
camera.position = vec3_exports.fromValues(origin.x, origin.y, origin.z);
|
|
14277
|
-
|
|
14278
|
-
|
|
14652
|
+
if (!isDemoPlaying || demoCameraState.mode === 0 /* FirstPerson */) {
|
|
14653
|
+
const viewOffset = lastView?.offset ?? { x: 0, y: 0, z: 0 };
|
|
14654
|
+
vec3_exports.add(camera.position, camera.position, [viewOffset.x, viewOffset.y, viewOffset.z]);
|
|
14655
|
+
}
|
|
14279
14656
|
const effectAngles = lastView?.angles ?? { x: 0, y: 0, z: 0 };
|
|
14280
14657
|
camera.angles = vec3_exports.fromValues(viewAngles.x + effectAngles.x, viewAngles.y + effectAngles.y, viewAngles.z + effectAngles.z);
|
|
14281
14658
|
if (isDemoPlaying && lastRendered.fov) {
|
|
@@ -14508,7 +14885,21 @@ function createClient(imports) {
|
|
|
14508
14885
|
},
|
|
14509
14886
|
demoHandler,
|
|
14510
14887
|
multiplayer,
|
|
14511
|
-
configStrings
|
|
14888
|
+
configStrings,
|
|
14889
|
+
// Demo Camera API
|
|
14890
|
+
setDemoCameraMode(mode) {
|
|
14891
|
+
demoCameraState.mode = mode;
|
|
14892
|
+
},
|
|
14893
|
+
setDemoThirdPersonDistance(dist2) {
|
|
14894
|
+
demoCameraState.thirdPersonDistance = dist2;
|
|
14895
|
+
},
|
|
14896
|
+
setDemoThirdPersonOffset(offset) {
|
|
14897
|
+
demoCameraState.thirdPersonOffset = offset;
|
|
14898
|
+
},
|
|
14899
|
+
setDemoFreeCamera(origin, angles) {
|
|
14900
|
+
demoCameraState.freeCameraOrigin = origin;
|
|
14901
|
+
demoCameraState.freeCameraAngles = angles;
|
|
14902
|
+
}
|
|
14512
14903
|
};
|
|
14513
14904
|
return clientExports;
|
|
14514
14905
|
}
|
|
@@ -14517,6 +14908,7 @@ function createClient(imports) {
|
|
|
14517
14908
|
ClientConfigStrings,
|
|
14518
14909
|
ClientMode,
|
|
14519
14910
|
ClientPrediction,
|
|
14911
|
+
DemoCameraMode,
|
|
14520
14912
|
GameSession,
|
|
14521
14913
|
InputAction,
|
|
14522
14914
|
InputBindings,
|