quake2ts 0.0.466 → 0.0.468

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.
@@ -14353,6 +14353,123 @@ var updateBlend = (state, ps, dt, damageIntensity = 0) => {
14353
14353
  return [0, 0, 0, 0];
14354
14354
  };
14355
14355
 
14356
+ // src/scoreboard.ts
14357
+ var ScoreboardManager = class {
14358
+ constructor(configStrings) {
14359
+ this.localPlayerId = -1;
14360
+ this.listeners = [];
14361
+ // Cache players to support stateful updates (e.g. scores)
14362
+ this.players = /* @__PURE__ */ new Map();
14363
+ this.configStrings = configStrings;
14364
+ this.refreshAll();
14365
+ }
14366
+ setLocalPlayerId(id) {
14367
+ this.localPlayerId = id;
14368
+ }
14369
+ addListener(listener) {
14370
+ this.listeners.push(listener);
14371
+ }
14372
+ removeListener(listener) {
14373
+ const index = this.listeners.indexOf(listener);
14374
+ if (index !== -1) {
14375
+ this.listeners.splice(index, 1);
14376
+ }
14377
+ }
14378
+ notifyUpdate() {
14379
+ const data = this.getScoreboard();
14380
+ for (const listener of this.listeners) {
14381
+ listener(data);
14382
+ }
14383
+ }
14384
+ refreshAll() {
14385
+ this.players.clear();
14386
+ for (let i = 0; i < MAX_CLIENTS2; i++) {
14387
+ const csIndex = ConfigStringIndex2.PlayerSkins + i;
14388
+ const str3 = this.configStrings.get(csIndex);
14389
+ if (str3 && str3.length > 0) {
14390
+ this.parseConfigString(csIndex, str3);
14391
+ }
14392
+ }
14393
+ }
14394
+ parseConfigString(index, str3) {
14395
+ if (index < ConfigStringIndex2.PlayerSkins || index >= ConfigStringIndex2.PlayerSkins + MAX_CLIENTS2) {
14396
+ return;
14397
+ }
14398
+ const id = index - ConfigStringIndex2.PlayerSkins;
14399
+ if (!str3 || str3.length === 0) {
14400
+ if (this.players.has(id)) {
14401
+ this.players.delete(id);
14402
+ }
14403
+ return;
14404
+ }
14405
+ const entry = this.parsePlayerConfigString(id, str3);
14406
+ if (entry) {
14407
+ const existing = this.players.get(id);
14408
+ if (existing) {
14409
+ entry.frags = existing.frags;
14410
+ entry.deaths = existing.deaths;
14411
+ entry.ping = existing.ping;
14412
+ }
14413
+ this.players.set(id, entry);
14414
+ }
14415
+ }
14416
+ getScoreboard() {
14417
+ const players = Array.from(this.players.values());
14418
+ players.sort((a, b) => b.frags - a.frags);
14419
+ const worldModel = this.configStrings.getModelName(1);
14420
+ let mapName = "unknown";
14421
+ if (worldModel) {
14422
+ const match = worldModel.match(/maps\/(.*)\.bsp/i);
14423
+ if (match) {
14424
+ mapName = match[1];
14425
+ } else {
14426
+ mapName = worldModel;
14427
+ }
14428
+ }
14429
+ return {
14430
+ players,
14431
+ mapName
14432
+ };
14433
+ }
14434
+ parsePlayerConfigString(id, str3) {
14435
+ const parts = str3.split("\\");
14436
+ const info = {};
14437
+ let startIndex = 0;
14438
+ if (parts.length > 0 && parts[0] === "") {
14439
+ startIndex = 1;
14440
+ }
14441
+ for (let i = startIndex; i < parts.length; i += 2) {
14442
+ if (i + 1 < parts.length) {
14443
+ const key = parts[i].toLowerCase();
14444
+ const value = parts[i + 1];
14445
+ info[key] = value;
14446
+ }
14447
+ }
14448
+ if (!info.name) {
14449
+ return null;
14450
+ }
14451
+ return {
14452
+ id,
14453
+ name: info.name,
14454
+ frags: 0,
14455
+ deaths: 0,
14456
+ ping: 0,
14457
+ skin: info.skin,
14458
+ model: info.model
14459
+ };
14460
+ }
14461
+ // Method to update scores explicitly
14462
+ updateScore(id, frags, deaths, ping) {
14463
+ const player = this.players.get(id);
14464
+ if (player) {
14465
+ player.frags = frags;
14466
+ player.deaths = deaths;
14467
+ player.ping = ping;
14468
+ this.notifyUpdate();
14469
+ }
14470
+ }
14471
+ };
14472
+
14356
14473
  // src/input/bindings.ts
14357
14474
  var DEFAULT_BINDINGS = [
14358
14475
  { code: "KeyW", command: "+forward" },
@@ -14883,6 +15000,7 @@ var GameSession = class {
14883
15000
  this.currentMapName = "";
14884
15001
  this.options = options;
14885
15002
  this.engine = options.engine;
15003
+ this.inputController = new InputController();
14886
15004
  }
14887
15005
  startNewGame(mapName, skill = 1) {
14888
15006
  if (this.host) {
@@ -14973,9 +15091,16 @@ var GameSession = class {
14973
15091
  this.host = new EngineHost(this.game, clientProxy);
14974
15092
  const clientImports = {
14975
15093
  engine: this.engine,
14976
- host: this.host
15094
+ host: this.host,
15095
+ inputController: this.inputController
14977
15096
  };
14978
15097
  this.client = createClient(clientImports);
15098
+ if (this._onInputCommand) {
15099
+ this.client.onInputCommand = this._onInputCommand;
15100
+ }
15101
+ if (this._onHudUpdate) {
15102
+ this.client.onHudUpdate = this._onHudUpdate;
15103
+ }
14979
15104
  this.game.spawnWorld();
14980
15105
  this.host.start();
14981
15106
  if (this.engine.cmd) {
@@ -15069,9 +15194,16 @@ var GameSession = class {
15069
15194
  this.host = new EngineHost(this.game, clientProxy);
15070
15195
  const clientImports = {
15071
15196
  engine: this.engine,
15072
- host: this.host
15197
+ host: this.host,
15198
+ inputController: this.inputController
15073
15199
  };
15074
15200
  this.client = createClient(clientImports);
15201
+ if (this._onInputCommand) {
15202
+ this.client.onInputCommand = this._onInputCommand;
15203
+ }
15204
+ if (this._onHudUpdate) {
15205
+ this.client.onHudUpdate = this._onHudUpdate;
15206
+ }
15075
15207
  if (this.engine.cmd) {
15076
15208
  this.engine.cmd.executeText(`map ${mapName}`);
15077
15209
  } else if (this.host.commands) {
@@ -15102,6 +15234,43 @@ var GameSession = class {
15102
15234
  getHost() {
15103
15235
  return this.host;
15104
15236
  }
15237
+ bindInputSource(source) {
15238
+ this.inputController.bindInputSource(source);
15239
+ }
15240
+ setKeyBinding(action, keys) {
15241
+ this.inputController.setKeyBinding(action, keys);
15242
+ }
15243
+ getDefaultBindings() {
15244
+ return this.inputController.getDefaultBindings();
15245
+ }
15246
+ set onInputCommand(handler) {
15247
+ this._onInputCommand = handler;
15248
+ if (this.client) {
15249
+ this.client.onInputCommand = handler;
15250
+ }
15251
+ }
15252
+ get onInputCommand() {
15253
+ return this._onInputCommand;
15254
+ }
15255
+ // Section 4.2: HUD and UI Integration
15256
+ getHudData() {
15257
+ return this.client?.getHudData() ?? null;
15258
+ }
15259
+ getStatusBar() {
15260
+ return this.client?.getStatusBar() ?? null;
15261
+ }
15262
+ getCrosshairInfo() {
15263
+ return this.client?.getCrosshairInfo() ?? null;
15264
+ }
15265
+ set onHudUpdate(handler) {
15266
+ this._onHudUpdate = handler;
15267
+ if (this.client) {
15268
+ this.client.onHudUpdate = handler;
15269
+ }
15270
+ }
15271
+ get onHudUpdate() {
15272
+ return this._onHudUpdate;
15273
+ }
15105
15274
  // Section 4.1.3: Game State Queries
15106
15275
  getPlayerState() {
15107
15276
  if (this.client && this.client.lastRendered) {
@@ -15204,6 +15373,12 @@ function createClient(imports) {
15204
15373
  freeCameraAngles: { x: 0, y: 0, z: 0 },
15205
15374
  followEntityId: -1
15206
15375
  };
15376
+ const inputController = imports.inputController ?? new InputController();
15377
+ inputController.onInputCommand = (cmd) => {
15378
+ if (clientExports.onInputCommand) {
15379
+ clientExports.onInputCommand(cmd);
15380
+ }
15381
+ };
15207
15382
  const inputState = {
15208
15383
  forward: false,
15209
15384
  backward: false,
@@ -15220,6 +15395,7 @@ function createClient(imports) {
15220
15395
  let pauseMenuFactory;
15221
15396
  let optionsFactory;
15222
15397
  const configStrings = new ClientConfigStrings();
15398
+ const scoreboardManager = new ScoreboardManager(configStrings);
15223
15399
  const blendState = createBlendState();
15224
15400
  let currentBlend = [0, 0, 0, 0];
15225
15401
  let pendingDamage = 0;
@@ -15274,6 +15450,10 @@ function createClient(imports) {
15274
15450
  onConfigString: (index, str3) => {
15275
15451
  configStrings.set(index, str3);
15276
15452
  cg.ParseConfigString(index, str3);
15453
+ if (index >= ConfigStringIndex2.PlayerSkins && index < ConfigStringIndex2.PlayerSkins + MAX_CLIENTS2) {
15454
+ scoreboardManager.parseConfigString(index, str3);
15455
+ scoreboardManager.notifyUpdate();
15456
+ }
15277
15457
  },
15278
15458
  onServerData: (protocol, tickRate) => {
15279
15459
  if (tickRate && tickRate > 0) {
@@ -15509,6 +15689,15 @@ function createClient(imports) {
15509
15689
  menuSystem.pushMenu(pauseMenuFactory.createPauseMenu());
15510
15690
  }
15511
15691
  },
15692
+ bindInputSource(source) {
15693
+ inputController.bindInputSource(source);
15694
+ },
15695
+ setKeyBinding(action, keys) {
15696
+ inputController.setKeyBinding(action, keys);
15697
+ },
15698
+ getDefaultBindings() {
15699
+ return inputController.getDefaultBindings();
15700
+ },
15512
15701
  createMainMenu(options, storage, saveCallback, loadCallback, deleteCallback) {
15513
15702
  const saveLoadFactory = new SaveLoadMenuFactory(menuSystem, storage, saveCallback, loadCallback, deleteCallback);
15514
15703
  let optsFactory = optionsFactory;
@@ -15676,7 +15865,10 @@ function createClient(imports) {
15676
15865
  } else {
15677
15866
  currentBlend = [0, 0, 0, 0];
15678
15867
  }
15679
- const command = {};
15868
+ const command = inputController.buildCommand(dtMs, now, demoHandler.latestServerFrame);
15869
+ if (!isDemoPlaying && !menuSystem.isActive()) {
15870
+ clientExports.predict(command);
15871
+ }
15680
15872
  const timeSeconds = sample.nowMs / 1e3;
15681
15873
  dlightManager.update(timeSeconds, dtMs / 1e3);
15682
15874
  const dlights = [...dlightManager.getActiveLights()];
@@ -15977,8 +16169,17 @@ function createClient(imports) {
15977
16169
  },
15978
16170
  setDemoFollowEntity(entityId) {
15979
16171
  demoCameraState.followEntityId = entityId;
16172
+ },
16173
+ // Scoreboard API
16174
+ getScoreboard() {
16175
+ return scoreboardManager.getScoreboard();
15980
16176
  }
15981
16177
  };
16178
+ scoreboardManager.addListener((data) => {
16179
+ if (clientExports.onScoreboardUpdate) {
16180
+ clientExports.onScoreboardUpdate(data);
16181
+ }
16182
+ });
15982
16183
  return clientExports;
15983
16184
  }
15984
16185
  export {
@@ -15991,6 +16192,7 @@ export {
15991
16192
  InputBindings,
15992
16193
  InputCommandBuffer,
15993
16194
  InputController,
16195
+ ScoreboardManager,
15994
16196
  ViewEffects3 as ViewEffects,
15995
16197
  createClient,
15996
16198
  createDefaultBindings,