quake2ts 0.0.470 → 0.0.473

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.
@@ -12229,6 +12229,9 @@ var ClientNetworkHandler = class {
12229
12229
  }
12230
12230
  }
12231
12231
  onLayout(layout) {
12232
+ if (this.callbacks?.onLayout) {
12233
+ this.callbacks.onLayout(layout);
12234
+ }
12232
12235
  }
12233
12236
  onInventory(inventory) {
12234
12237
  this.inventory = [...inventory];
@@ -14445,6 +14448,7 @@ var ScoreboardManager = class {
14445
14448
  entry.frags = existing.frags;
14446
14449
  entry.deaths = existing.deaths;
14447
14450
  entry.ping = existing.ping;
14451
+ entry.team = existing.team;
14448
14452
  }
14449
14453
  this.players.set(id, entry);
14450
14454
  }
@@ -14491,7 +14495,8 @@ var ScoreboardManager = class {
14491
14495
  deaths: 0,
14492
14496
  ping: 0,
14493
14497
  skin: info.skin,
14494
- model: info.model
14498
+ model: info.model,
14499
+ team: void 0
14495
14500
  };
14496
14501
  }
14497
14502
  // Method to update scores explicitly
@@ -14504,6 +14509,105 @@ var ScoreboardManager = class {
14504
14509
  this.notifyUpdate();
14505
14510
  }
14506
14511
  }
14512
+ /**
14513
+ * Parses the layout string from svc_layout and updates player scores.
14514
+ * Expected format example:
14515
+ * xv 32 yv 32 string "%4i %4i %-12.12s %4i"
14516
+ * followed by values? No, the string command draws text.
14517
+ * In Q2, the layout message sends a series of drawing commands.
14518
+ * The server formats the string:
14519
+ * "xv 32 yv %i string \"%4i %4i %-12.12s %4i\" "
14520
+ * The client receives the formatting commands AND the string data.
14521
+ * Wait, svc_layout in Q2 sends a single string that the client parses and draws.
14522
+ * The string contains tokens.
14523
+ * Example:
14524
+ * "xv 32 yv 32 string \" 10 50 PlayerName 10\""
14525
+ * We need to regex this.
14526
+ */
14527
+ processScoreboardMessage(layout) {
14528
+ const stringCmdRegex = /string\s+"([^"]+)"/g;
14529
+ let match;
14530
+ while ((match = stringCmdRegex.exec(layout)) !== null) {
14531
+ const content = match[1];
14532
+ if (content.length > 20) {
14533
+ const fragsStr = content.substring(0, 4).trim();
14534
+ const pingStr = content.substring(5, 9).trim();
14535
+ const nameStr = content.substring(10, 22).trim();
14536
+ const frags = parseInt(fragsStr, 10);
14537
+ const ping = parseInt(pingStr, 10);
14538
+ if (!isNaN(frags) && !isNaN(ping) && nameStr.length > 0) {
14539
+ for (const player of this.players.values()) {
14540
+ if (player.name === nameStr) {
14541
+ player.frags = frags;
14542
+ player.ping = ping;
14543
+ }
14544
+ }
14545
+ }
14546
+ }
14547
+ }
14548
+ this.notifyUpdate();
14549
+ }
14550
+ };
14551
+
14552
+ // src/chat.ts
14553
+ var ChatManager = class {
14554
+ constructor(sendCommand) {
14555
+ this.history = [];
14556
+ this.maxHistory = 100;
14557
+ this.listeners = [];
14558
+ this.sendCommand = sendCommand;
14559
+ }
14560
+ addListener(listener) {
14561
+ this.listeners.push(listener);
14562
+ }
14563
+ removeListener(listener) {
14564
+ const index = this.listeners.indexOf(listener);
14565
+ if (index !== -1) {
14566
+ this.listeners.splice(index, 1);
14567
+ }
14568
+ }
14569
+ sendChatMessage(message, team = false) {
14570
+ const escaped = message.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
14571
+ const cmd = team ? `say_team "${escaped}"` : `say "${escaped}"`;
14572
+ this.sendCommand(cmd);
14573
+ }
14574
+ addMessage(level, text) {
14575
+ let sender;
14576
+ let content = text;
14577
+ let team = false;
14578
+ const match = text.match(/^([^:]+):\s(.*)$/);
14579
+ const teamMatch = text.match(/^\(([^)]+)\):\s(.*)$/);
14580
+ if (teamMatch) {
14581
+ sender = teamMatch[1];
14582
+ content = teamMatch[2];
14583
+ team = true;
14584
+ } else if (match) {
14585
+ sender = match[1];
14586
+ content = match[2];
14587
+ team = false;
14588
+ }
14589
+ const message = {
14590
+ timestamp: Date.now(),
14591
+ sender,
14592
+ text: content,
14593
+ team
14594
+ };
14595
+ this.history.push(message);
14596
+ if (this.history.length > this.maxHistory) {
14597
+ this.history.shift();
14598
+ }
14599
+ if (sender) {
14600
+ this.notifyListeners(sender, content, team);
14601
+ }
14602
+ }
14603
+ getHistory() {
14604
+ return [...this.history];
14605
+ }
14606
+ notifyListeners(sender, message, team) {
14607
+ for (const listener of this.listeners) {
14608
+ listener(sender, message, team);
14609
+ }
14610
+ }
14507
14611
  };
14508
14612
 
14509
14613
  // src/input/bindings.ts
@@ -15429,6 +15533,11 @@ function createClient(imports) {
15429
15533
  let optionsFactory;
15430
15534
  const configStrings = new ClientConfigStrings();
15431
15535
  const scoreboardManager = new ScoreboardManager(configStrings);
15536
+ const chatManager = new ChatManager((cmd) => {
15537
+ if (imports.engine.cmd) {
15538
+ imports.engine.cmd.executeText(cmd);
15539
+ }
15540
+ });
15432
15541
  const blendState = createBlendState();
15433
15542
  let currentBlend = [0, 0, 0, 0];
15434
15543
  let pendingDamage = 0;
@@ -15479,7 +15588,10 @@ function createClient(imports) {
15479
15588
  const multiplayerFactory = new MultiplayerMenuFactory(menuSystem, multiplayer);
15480
15589
  demoHandler.setCallbacks({
15481
15590
  onCenterPrint: (msg) => cg.ParseCenterPrint(msg, 0, false),
15482
- onPrint: (level, msg) => cg.NotifyMessage(0, msg, false),
15591
+ onPrint: (level, msg) => {
15592
+ cg.NotifyMessage(0, msg, false);
15593
+ chatManager.addMessage(level, msg);
15594
+ },
15483
15595
  onConfigString: (index, str3) => {
15484
15596
  configStrings.set(index, str3);
15485
15597
  cg.ParseConfigString(index, str3);
@@ -15510,6 +15622,10 @@ function createClient(imports) {
15510
15622
  },
15511
15623
  onDamage: (indicators) => {
15512
15624
  pendingDamage = 0.5;
15625
+ },
15626
+ onLayout: (layout) => {
15627
+ scoreboardManager.processScoreboardMessage(layout);
15628
+ scoreboardManager.notifyUpdate();
15513
15629
  }
15514
15630
  });
15515
15631
  demoPlayback.setHandler(demoHandler);
@@ -16206,6 +16322,13 @@ function createClient(imports) {
16206
16322
  // Scoreboard API
16207
16323
  getScoreboard() {
16208
16324
  return scoreboardManager.getScoreboard();
16325
+ },
16326
+ // Chat API
16327
+ sendChatMessage(message, team = false) {
16328
+ chatManager.sendChatMessage(message, team);
16329
+ },
16330
+ getChatHistory() {
16331
+ return chatManager.getHistory();
16209
16332
  }
16210
16333
  };
16211
16334
  scoreboardManager.addListener((data) => {
@@ -16213,6 +16336,11 @@ function createClient(imports) {
16213
16336
  clientExports.onScoreboardUpdate(data);
16214
16337
  }
16215
16338
  });
16339
+ chatManager.addListener((sender, message, team) => {
16340
+ if (clientExports.onChatMessage) {
16341
+ clientExports.onChatMessage(sender, message, team);
16342
+ }
16343
+ });
16216
16344
  return clientExports;
16217
16345
  }
16218
16346
  // Annotate the CommonJS export names for ESM import in node: