quake2ts 0.0.298 → 0.0.301

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.
Files changed (44) hide show
  1. package/package.json +1 -1
  2. package/packages/cgame/dist/index.cjs +52 -1
  3. package/packages/cgame/dist/index.cjs.map +1 -1
  4. package/packages/cgame/dist/index.d.cts +7 -0
  5. package/packages/cgame/dist/index.d.ts +7 -0
  6. package/packages/cgame/dist/index.js +53 -2
  7. package/packages/cgame/dist/index.js.map +1 -1
  8. package/packages/client/dist/browser/index.global.js +13 -13
  9. package/packages/client/dist/browser/index.global.js.map +1 -1
  10. package/packages/client/dist/cjs/index.cjs +166 -10
  11. package/packages/client/dist/cjs/index.cjs.map +1 -1
  12. package/packages/client/dist/esm/index.js +161 -5
  13. package/packages/client/dist/esm/index.js.map +1 -1
  14. package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
  15. package/packages/client/dist/types/cgameBridge.d.ts.map +1 -1
  16. package/packages/client/dist/types/index.d.ts.map +1 -1
  17. package/packages/client/dist/types/input/controller.d.ts +1 -0
  18. package/packages/client/dist/types/input/controller.d.ts.map +1 -1
  19. package/packages/client/dist/types/net/connection.d.ts +3 -0
  20. package/packages/client/dist/types/net/connection.d.ts.map +1 -1
  21. package/packages/client/dist/types/ui/demo-controls.d.ts +11 -0
  22. package/packages/client/dist/types/ui/demo-controls.d.ts.map +1 -0
  23. package/packages/engine/dist/browser/index.global.js.map +1 -1
  24. package/packages/engine/dist/cjs/index.cjs.map +1 -1
  25. package/packages/engine/dist/esm/index.js.map +1 -1
  26. package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
  27. package/packages/game/dist/browser/index.global.js +4 -4
  28. package/packages/game/dist/browser/index.global.js.map +1 -1
  29. package/packages/game/dist/cjs/index.cjs +17 -10
  30. package/packages/game/dist/cjs/index.cjs.map +1 -1
  31. package/packages/game/dist/esm/index.js +17 -10
  32. package/packages/game/dist/esm/index.js.map +1 -1
  33. package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
  34. package/packages/game/dist/types/entities/gibs.d.ts +1 -1
  35. package/packages/game/dist/types/entities/gibs.d.ts.map +1 -1
  36. package/packages/server/dist/index.cjs +9 -2
  37. package/packages/server/dist/index.js +9 -2
  38. package/packages/shared/dist/browser/index.global.js.map +1 -1
  39. package/packages/shared/dist/cjs/index.cjs.map +1 -1
  40. package/packages/shared/dist/esm/index.js.map +1 -1
  41. package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
  42. package/packages/shared/dist/types/protocol/usercmd.d.ts +3 -0
  43. package/packages/shared/dist/types/protocol/usercmd.d.ts.map +1 -1
  44. package/packages/tools/dist/tsconfig.tsbuildinfo +1 -1
@@ -8309,6 +8309,13 @@ var NetworkMessageParser = class _NetworkMessageParser {
8309
8309
  if (bitsHigh & U_OLD_FRAME_HIGH) to.oldFrame = this.stream.readShort();
8310
8310
  }
8311
8311
  };
8312
+ var PlaybackState = /* @__PURE__ */ ((PlaybackState22) => {
8313
+ PlaybackState22[PlaybackState22["Stopped"] = 0] = "Stopped";
8314
+ PlaybackState22[PlaybackState22["Playing"] = 1] = "Playing";
8315
+ PlaybackState22[PlaybackState22["Paused"] = 2] = "Paused";
8316
+ PlaybackState22[PlaybackState22["Finished"] = 3] = "Finished";
8317
+ return PlaybackState22;
8318
+ })(PlaybackState || {});
8312
8319
  var DemoPlaybackController = class {
8313
8320
  // ms (10Hz default)
8314
8321
  constructor() {
@@ -9623,7 +9630,7 @@ var AmmoType2 = /* @__PURE__ */ ((AmmoType22) => {
9623
9630
  var AMMO_TYPE_COUNT2 = Object.keys(AmmoType2).length / 2;
9624
9631
 
9625
9632
  // src/index.ts
9626
- import { ClientPrediction, interpolatePredictionState as interpolatePredictionState2, GetCGameAPI } from "@quake2ts/cgame";
9633
+ import { ClientPrediction as ClientPrediction2, interpolatePredictionState as interpolatePredictionState2, GetCGameAPI } from "@quake2ts/cgame";
9627
9634
  import { ViewEffects as ViewEffects2 } from "@quake2ts/cgame";
9628
9635
 
9629
9636
  // src/cgameBridge.ts
@@ -9674,6 +9681,24 @@ function createCGameImport(imports, state) {
9674
9681
  flags
9675
9682
  });
9676
9683
  },
9684
+ Cvar_Get: (name, value, flags) => {
9685
+ if (!imports.host || !imports.host.cvars) {
9686
+ return { value: parseInt(value) || 0 };
9687
+ }
9688
+ let existing = imports.host.cvars.get(name);
9689
+ if (!existing) {
9690
+ existing = imports.host.cvars.register({
9691
+ name,
9692
+ defaultValue: value,
9693
+ flags
9694
+ });
9695
+ }
9696
+ return {
9697
+ get value() {
9698
+ return existing.number;
9699
+ }
9700
+ };
9701
+ },
9677
9702
  cvar_set: (name, value) => {
9678
9703
  imports.host?.cvars?.setValue(name, value);
9679
9704
  },
@@ -11611,6 +11636,7 @@ var BrowserWebSocketNetDriver = class {
11611
11636
  };
11612
11637
 
11613
11638
  // src/net/connection.ts
11639
+ import { defaultPredictionState as defaultPredictionState2 } from "@quake2ts/cgame";
11614
11640
  var MultiplayerConnection = class {
11615
11641
  constructor(options) {
11616
11642
  this.state = 0 /* Disconnected */;
@@ -11628,6 +11654,8 @@ var MultiplayerConnection = class {
11628
11654
  this.connectPacketTime = 0;
11629
11655
  this.latestServerFrame = 0;
11630
11656
  this.commandHistory = [];
11657
+ // Prediction
11658
+ this.prediction = null;
11631
11659
  this.driver = new BrowserWebSocketNetDriver();
11632
11660
  this.options = options;
11633
11661
  this.netchan = new NetChan();
@@ -11635,6 +11663,9 @@ var MultiplayerConnection = class {
11635
11663
  this.driver.onClose(() => this.handleDisconnect());
11636
11664
  this.driver.onError((err2) => console.error("Network Error:", err2));
11637
11665
  }
11666
+ setPrediction(prediction) {
11667
+ this.prediction = prediction;
11668
+ }
11638
11669
  async connect(url) {
11639
11670
  if (this.state !== 0 /* Disconnected */) {
11640
11671
  this.disconnect();
@@ -11672,6 +11703,9 @@ var MultiplayerConnection = class {
11672
11703
  if (this.commandHistory.length > CMD_BACKUP) {
11673
11704
  this.commandHistory.shift();
11674
11705
  }
11706
+ if (this.prediction) {
11707
+ this.prediction.enqueueCommand(commandWithFrame);
11708
+ }
11675
11709
  const writer = new BinaryWriter2();
11676
11710
  writer.writeByte(ClientCommand.move);
11677
11711
  writer.writeByte(0);
@@ -11769,6 +11803,31 @@ var MultiplayerConnection = class {
11769
11803
  if (frame.serverFrame > this.latestServerFrame) {
11770
11804
  this.latestServerFrame = frame.serverFrame;
11771
11805
  }
11806
+ if (this.prediction && frame.playerState) {
11807
+ const ps = frame.playerState;
11808
+ const predState = {
11809
+ ...defaultPredictionState2(),
11810
+ // Manual mapping due to type mismatch (MutableVec3 vs Vec3, and property names)
11811
+ origin: { x: ps.origin.x, y: ps.origin.y, z: ps.origin.z },
11812
+ velocity: { x: ps.velocity.x, y: ps.velocity.y, z: ps.velocity.z },
11813
+ viewAngles: { x: ps.viewangles.x, y: ps.viewangles.y, z: ps.viewangles.z },
11814
+ deltaAngles: { x: ps.delta_angles.x, y: ps.delta_angles.y, z: ps.delta_angles.z },
11815
+ pmFlags: ps.pm_flags,
11816
+ pmType: ps.pm_type,
11817
+ gravity: ps.gravity,
11818
+ // Copy other matching fields
11819
+ health: ps.stats[0]
11820
+ // Assuming stat 0 is health? Or generic copy
11821
+ // ...
11822
+ };
11823
+ const gameFrame = {
11824
+ frame: frame.serverFrame,
11825
+ timeMs: 0,
11826
+ // Should be server time, but frame doesn't always have it explicitly?
11827
+ state: predState
11828
+ };
11829
+ this.prediction.setAuthoritative(gameFrame);
11830
+ }
11772
11831
  }
11773
11832
  // Stubs for other handlers
11774
11833
  onCenterPrint(msg) {
@@ -11796,6 +11855,89 @@ var MultiplayerConnection = class {
11796
11855
  }
11797
11856
  };
11798
11857
 
11858
+ // src/ui/demo-controls.ts
11859
+ var DemoControls = class {
11860
+ constructor(playback) {
11861
+ this.isVisible = true;
11862
+ this.playback = playback;
11863
+ }
11864
+ render(renderer, width, height) {
11865
+ if (!this.isVisible) return;
11866
+ const state = this.playback.getState();
11867
+ const isPlaying = state === PlaybackState.Playing;
11868
+ const overlayHeight = 60;
11869
+ const y = height - overlayHeight;
11870
+ renderer.drawfillRect(0, y, width, overlayHeight, [0, 0, 0, 0.5]);
11871
+ const iconSize = 24;
11872
+ const iconY = y + (overlayHeight - iconSize) / 2;
11873
+ const iconX = 20;
11874
+ const statusText = isPlaying ? "PAUSE" : "PLAY";
11875
+ renderer.drawString(iconX, iconY, statusText);
11876
+ const speed = this.playback.getSpeed();
11877
+ const speedText = `Speed: ${speed}x`;
11878
+ renderer.drawCenterString(iconY, speedText);
11879
+ const currentTime = this.playback.getCurrentTime();
11880
+ const currentFormatted = this.formatTime(currentTime);
11881
+ const totalFormatted = "--:--";
11882
+ const timeText = `${currentFormatted} / ${totalFormatted}`;
11883
+ const timeX = width - 150;
11884
+ renderer.drawString(timeX, iconY, timeText);
11885
+ const timelineY = y + 5;
11886
+ const timelineHeight = 4;
11887
+ const timelineWidth = width - 40;
11888
+ const timelineX = 20;
11889
+ renderer.drawfillRect(timelineX, timelineY, timelineWidth, timelineHeight, [0.3, 0.3, 0.3, 1]);
11890
+ const progress = 0;
11891
+ const progressWidth = timelineWidth * progress;
11892
+ renderer.drawfillRect(timelineX, timelineY, progressWidth, timelineHeight, [1, 1, 1, 1]);
11893
+ const markerX = timelineX + progressWidth;
11894
+ renderer.drawfillRect(markerX - 2, timelineY - 2, 4, timelineHeight + 4, [1, 0, 0, 1]);
11895
+ const helpText = "[Space] Toggle [< >] Step [ [ ] ] Speed [Esc] Stop";
11896
+ renderer.drawCenterString(y + 35, helpText);
11897
+ }
11898
+ handleInput(key, down) {
11899
+ if (!down) return false;
11900
+ switch (key.toLowerCase()) {
11901
+ case " ":
11902
+ if (this.playback.getState() === PlaybackState.Playing) {
11903
+ this.playback.pause();
11904
+ } else if (this.playback.getState() === PlaybackState.Paused) {
11905
+ this.playback.play();
11906
+ }
11907
+ return true;
11908
+ case "arrowright":
11909
+ this.playback.stepForward();
11910
+ return true;
11911
+ case "arrowleft":
11912
+ this.playback.stepBackward();
11913
+ return true;
11914
+ case "]":
11915
+ this.changeSpeed(2);
11916
+ return true;
11917
+ case "[":
11918
+ this.changeSpeed(0.5);
11919
+ return true;
11920
+ case "escape":
11921
+ this.playback.stop();
11922
+ return true;
11923
+ }
11924
+ return false;
11925
+ }
11926
+ changeSpeed(factor) {
11927
+ const current = this.playback.getSpeed();
11928
+ let newSpeed = current * factor;
11929
+ if (newSpeed < 0.1) newSpeed = 0.1;
11930
+ if (newSpeed > 16) newSpeed = 16;
11931
+ this.playback.setSpeed(newSpeed);
11932
+ }
11933
+ formatTime(ms) {
11934
+ const totalSeconds = Math.floor(ms / 1e3);
11935
+ const minutes = Math.floor(totalSeconds / 60);
11936
+ const seconds = totalSeconds % 60;
11937
+ return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
11938
+ }
11939
+ };
11940
+
11799
11941
  // src/input/bindings.ts
11800
11942
  var DEFAULT_BINDINGS = [
11801
11943
  { code: "KeyW", command: "+forward" },
@@ -11960,6 +12102,7 @@ var InputController = class {
11960
12102
  this.touchButtons = /* @__PURE__ */ new Map();
11961
12103
  this.touchMove = { x: 0, y: 0 };
11962
12104
  this.touchLook = { x: 0, y: 0 };
12105
+ this.sequence = 0;
11963
12106
  this.bindings = bindings;
11964
12107
  this.forwardSpeed = options.forwardSpeed ?? DEFAULT_FORWARD_SPEED;
11965
12108
  this.sideSpeed = options.sideSpeed ?? DEFAULT_SIDE_SPEED;
@@ -12098,6 +12241,7 @@ var InputController = class {
12098
12241
  buttons |= PlayerButton.Any;
12099
12242
  }
12100
12243
  this.anyPressed = false;
12244
+ this.sequence++;
12101
12245
  return {
12102
12246
  msec,
12103
12247
  buttons,
@@ -12105,7 +12249,10 @@ var InputController = class {
12105
12249
  forwardmove,
12106
12250
  sidemove,
12107
12251
  upmove,
12108
- serverFrame
12252
+ serverFrame,
12253
+ sequence: this.sequence,
12254
+ lightlevel: 0,
12255
+ impulse: 0
12109
12256
  };
12110
12257
  }
12111
12258
  consumeConsoleCommands() {
@@ -12286,7 +12433,7 @@ var InputCommandBuffer = class {
12286
12433
 
12287
12434
  // src/index.ts
12288
12435
  import {
12289
- ClientPrediction as ClientPrediction2,
12436
+ ClientPrediction as ClientPrediction3,
12290
12437
  interpolatePredictionState as interpolatePredictionState3
12291
12438
  } from "@quake2ts/cgame";
12292
12439
  import { ViewEffects as ViewEffects3 } from "@quake2ts/cgame";
@@ -12303,9 +12450,10 @@ function createClient(imports) {
12303
12450
  const tr = imports.engine.trace(point, point, zero3, zero3);
12304
12451
  return tr.contents || 0;
12305
12452
  };
12306
- const prediction = new ClientPrediction(imports.engine.trace, pointContents);
12453
+ const prediction = new ClientPrediction2(imports.engine.trace, pointContents);
12307
12454
  const view = new ViewEffects2();
12308
12455
  const demoPlayback = new DemoPlaybackController();
12456
+ const demoControls = new DemoControls(demoPlayback);
12309
12457
  const demoHandler = new ClientNetworkHandler(imports);
12310
12458
  demoHandler.setView(view);
12311
12459
  let isDemoPlaying = false;
@@ -12500,6 +12648,11 @@ function createClient(imports) {
12500
12648
  return prediction.enqueueCommand(command);
12501
12649
  },
12502
12650
  handleInput(key, down) {
12651
+ if (isDemoPlaying) {
12652
+ if (demoControls.handleInput(key, down)) {
12653
+ return true;
12654
+ }
12655
+ }
12503
12656
  if (!menuSystem.isActive()) return false;
12504
12657
  if (!down) return true;
12505
12658
  const lowerKey = key.toLowerCase();
@@ -12719,6 +12872,9 @@ function createClient(imports) {
12719
12872
  if (menuSystem.isActive()) {
12720
12873
  Draw_Menu(imports.engine.renderer, menuSystem.getState(), imports.engine.renderer.width, imports.engine.renderer.height);
12721
12874
  }
12875
+ if (isDemoPlaying) {
12876
+ demoControls.render(imports.engine.renderer, imports.engine.renderer.width, imports.engine.renderer.height);
12877
+ }
12722
12878
  if (lastRendered && lastRendered.client) {
12723
12879
  wheelMenuSystem.render(imports.engine.renderer, imports.engine.renderer.width, imports.engine.renderer.height, lastRendered.client);
12724
12880
  }
@@ -12803,7 +12959,7 @@ function createClient(imports) {
12803
12959
  export {
12804
12960
  ClientConfigStrings,
12805
12961
  ClientMode,
12806
- ClientPrediction2 as ClientPrediction,
12962
+ ClientPrediction3 as ClientPrediction,
12807
12963
  InputAction,
12808
12964
  InputBindings,
12809
12965
  InputCommandBuffer,