quake2ts 0.0.193 → 0.0.195

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 (40) hide show
  1. package/package.json +1 -1
  2. package/packages/cgame/dist/index.cjs +769 -103
  3. package/packages/cgame/dist/index.cjs.map +1 -1
  4. package/packages/cgame/dist/index.d.cts +83 -2
  5. package/packages/cgame/dist/index.d.ts +83 -2
  6. package/packages/cgame/dist/index.js +766 -105
  7. package/packages/cgame/dist/index.js.map +1 -1
  8. package/packages/client/dist/browser/index.global.js +5 -5
  9. package/packages/client/dist/browser/index.global.js.map +1 -1
  10. package/packages/client/dist/cjs/index.cjs +56 -502
  11. package/packages/client/dist/cjs/index.cjs.map +1 -1
  12. package/packages/client/dist/esm/index.js +55 -497
  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/demo/handler.d.ts +1 -1
  16. package/packages/client/dist/types/demo/handler.d.ts.map +1 -1
  17. package/packages/client/dist/types/index.d.ts +4 -5
  18. package/packages/client/dist/types/index.d.ts.map +1 -1
  19. package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
  20. package/packages/game/dist/browser/index.global.js +2 -2
  21. package/packages/game/dist/browser/index.global.js.map +1 -1
  22. package/packages/game/dist/cjs/index.cjs +14 -2
  23. package/packages/game/dist/cjs/index.cjs.map +1 -1
  24. package/packages/game/dist/esm/index.js +14 -2
  25. package/packages/game/dist/esm/index.js.map +1 -1
  26. package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
  27. package/packages/game/dist/types/index.d.ts +5 -0
  28. package/packages/game/dist/types/index.d.ts.map +1 -1
  29. package/packages/server/dist/index.cjs +7 -1
  30. package/packages/server/dist/index.js +7 -1
  31. package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
  32. package/packages/shared/dist/types/protocol/player-state.d.ts +5 -0
  33. package/packages/shared/dist/types/protocol/player-state.d.ts.map +1 -1
  34. package/packages/tools/dist/tsconfig.tsbuildinfo +1 -1
  35. package/packages/client/dist/types/prediction.d.ts +0 -51
  36. package/packages/client/dist/types/prediction.d.ts.map +0 -1
  37. package/packages/client/dist/types/view-effects.d.ts +0 -41
  38. package/packages/client/dist/types/view-effects.d.ts.map +0 -1
  39. package/packages/client/dist/types/view.d.ts +0 -4
  40. package/packages/client/dist/types/view.d.ts.map +0 -1
@@ -21,16 +21,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ClientConfigStrings: () => ClientConfigStrings,
24
- ClientPrediction: () => ClientPrediction,
24
+ ClientPrediction: () => import_cgame4.ClientPrediction,
25
25
  InputAction: () => InputAction,
26
26
  InputBindings: () => InputBindings,
27
27
  InputCommandBuffer: () => InputCommandBuffer,
28
28
  InputController: () => InputController,
29
- ViewEffects: () => ViewEffects,
29
+ ViewEffects: () => import_cgame5.ViewEffects,
30
30
  createClient: () => createClient,
31
31
  createDefaultBindings: () => createDefaultBindings,
32
- defaultPredictionState: () => defaultPredictionState,
33
- interpolatePredictionState: () => interpolatePredictionState,
32
+ interpolatePredictionState: () => import_cgame4.interpolatePredictionState,
34
33
  normalizeCommand: () => normalizeCommand,
35
34
  normalizeInputCode: () => normalizeInputCode
36
35
  });
@@ -3527,25 +3526,9 @@ var __export3 = (target, all) => {
3527
3526
  };
3528
3527
  var ZERO_VEC3 = { x: 0, y: 0, z: 0 };
3529
3528
  var DEG_TO_RAD2 = Math.PI / 180;
3530
- function addVec3(a, b) {
3531
- return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
3532
- }
3533
- function scaleVec3(a, scalar) {
3534
- return { x: a.x * scalar, y: a.y * scalar, z: a.z * scalar };
3535
- }
3536
3529
  function dotVec3(a, b) {
3537
3530
  return a.x * b.x + a.y * b.y + a.z * b.z;
3538
3531
  }
3539
- function lengthSquaredVec3(a) {
3540
- return dotVec3(a, a);
3541
- }
3542
- function lengthVec3(a) {
3543
- return Math.sqrt(lengthSquaredVec3(a));
3544
- }
3545
- function normalizeVec3(a) {
3546
- const len2 = lengthVec3(a);
3547
- return len2 === 0 ? a : scaleVec3(a, 1 / len2);
3548
- }
3549
3532
  var PITCH = 0;
3550
3533
  var YAW = 1;
3551
3534
  var ROLL = 2;
@@ -3756,16 +3739,6 @@ var PmFlag = /* @__PURE__ */ ((PmFlag22) => {
3756
3739
  function hasPmFlag(flags, flag) {
3757
3740
  return (flags & flag) !== 0;
3758
3741
  }
3759
- var PmType = /* @__PURE__ */ ((PmType22) => {
3760
- PmType22[PmType22["Normal"] = 0] = "Normal";
3761
- PmType22[PmType22["Grapple"] = 1] = "Grapple";
3762
- PmType22[PmType22["NoClip"] = 2] = "NoClip";
3763
- PmType22[PmType22["Spectator"] = 3] = "Spectator";
3764
- PmType22[PmType22["Dead"] = 4] = "Dead";
3765
- PmType22[PmType22["Gib"] = 5] = "Gib";
3766
- PmType22[PmType22["Freeze"] = 6] = "Freeze";
3767
- return PmType22;
3768
- })(PmType || {});
3769
3742
  var PlayerButton = /* @__PURE__ */ ((PlayerButton2) => {
3770
3743
  PlayerButton2[PlayerButton2["None"] = 0] = "None";
3771
3744
  PlayerButton2[PlayerButton2["Attack"] = 1] = "Attack";
@@ -3776,153 +3749,7 @@ var PlayerButton = /* @__PURE__ */ ((PlayerButton2) => {
3776
3749
  PlayerButton2[PlayerButton2["Any"] = 128] = "Any";
3777
3750
  return PlayerButton2;
3778
3751
  })(PlayerButton || {});
3779
- function applyPmoveFriction(params) {
3780
- const {
3781
- velocity,
3782
- frametime,
3783
- onGround,
3784
- groundIsSlick,
3785
- onLadder,
3786
- waterlevel,
3787
- pmFriction,
3788
- pmStopSpeed,
3789
- pmWaterFriction
3790
- } = params;
3791
- const speed = lengthVec3(velocity);
3792
- if (speed < 1) {
3793
- return { x: 0, y: 0, z: velocity.z };
3794
- }
3795
- let drop = 0;
3796
- if (onGround && !groundIsSlick || onLadder) {
3797
- const control = speed < pmStopSpeed ? pmStopSpeed : speed;
3798
- const friction = pmFriction;
3799
- drop += control * friction * frametime;
3800
- }
3801
- if (waterlevel > 0 && !onLadder) {
3802
- drop += speed * pmWaterFriction * waterlevel * frametime;
3803
- }
3804
- let newspeed = speed - drop;
3805
- if (newspeed < 0) {
3806
- newspeed = 0;
3807
- }
3808
- if (newspeed === speed) {
3809
- return velocity;
3810
- }
3811
- const scale3 = newspeed / speed;
3812
- return scaleVec3(velocity, scale3);
3813
- }
3814
- function applyPmoveAccelerate(params) {
3815
- const { velocity, wishdir, wishspeed, accel, frametime } = params;
3816
- const currentSpeed = dotVec3(velocity, wishdir);
3817
- const addSpeed = wishspeed - currentSpeed;
3818
- if (addSpeed <= 0) {
3819
- return velocity;
3820
- }
3821
- let accelSpeed = accel * frametime * wishspeed;
3822
- if (accelSpeed > addSpeed) {
3823
- accelSpeed = addSpeed;
3824
- }
3825
- return {
3826
- x: velocity.x + wishdir.x * accelSpeed,
3827
- y: velocity.y + wishdir.y * accelSpeed,
3828
- z: velocity.z + wishdir.z * accelSpeed
3829
- };
3830
- }
3831
- function applyPmoveAirAccelerate(params) {
3832
- const { velocity, wishdir, wishspeed, accel, frametime } = params;
3833
- const wishspd = Math.min(wishspeed, 30);
3834
- const currentSpeed = dotVec3(velocity, wishdir);
3835
- const addSpeed = wishspd - currentSpeed;
3836
- if (addSpeed <= 0) {
3837
- return velocity;
3838
- }
3839
- let accelSpeed = accel * wishspeed * frametime;
3840
- if (accelSpeed > addSpeed) {
3841
- accelSpeed = addSpeed;
3842
- }
3843
- return {
3844
- x: velocity.x + wishdir.x * accelSpeed,
3845
- y: velocity.y + wishdir.y * accelSpeed,
3846
- z: velocity.z + wishdir.z * accelSpeed
3847
- };
3848
- }
3849
- function buildAirGroundWish(params) {
3850
- const { forward, right, cmd, maxSpeed } = params;
3851
- let wishvel = {
3852
- x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
3853
- y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
3854
- z: 0
3855
- };
3856
- let wishspeed = lengthVec3(wishvel);
3857
- if (wishspeed > maxSpeed) {
3858
- const scale3 = maxSpeed / wishspeed;
3859
- wishvel = scaleVec3(wishvel, scale3);
3860
- wishspeed = maxSpeed;
3861
- }
3862
- return {
3863
- wishdir: wishspeed === 0 ? wishvel : normalizeVec3(wishvel),
3864
- wishspeed
3865
- };
3866
- }
3867
- function buildWaterWish(params) {
3868
- const { forward, right, cmd, maxSpeed } = params;
3869
- let wishvel = {
3870
- x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
3871
- y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
3872
- z: 0
3873
- };
3874
- if (cmd.upmove > 10) {
3875
- wishvel = addVec3(wishvel, { x: 0, y: 0, z: cmd.upmove });
3876
- } else if (cmd.upmove < -10) {
3877
- wishvel = addVec3(wishvel, { x: 0, y: 0, z: cmd.upmove });
3878
- } else {
3879
- wishvel = addVec3(wishvel, { x: 0, y: 0, z: 10 });
3880
- }
3881
- let wishspeed = lengthVec3(wishvel);
3882
- if (wishspeed > maxSpeed) {
3883
- const scale3 = maxSpeed / wishspeed;
3884
- wishvel = scaleVec3(wishvel, scale3);
3885
- wishspeed = maxSpeed;
3886
- }
3887
- wishspeed *= 0.5;
3888
- return {
3889
- wishdir: wishspeed === 0 ? wishvel : normalizeVec3(wishvel),
3890
- wishspeed
3891
- };
3892
- }
3893
3752
  var WATERJUMP_CLEAR2 = 8 | 16 | 32 | 1024;
3894
- function addAngles(cmdAngles, deltaAngles) {
3895
- return {
3896
- x: cmdAngles.x + deltaAngles.x,
3897
- y: cmdAngles.y + deltaAngles.y,
3898
- z: cmdAngles.z + deltaAngles.z
3899
- };
3900
- }
3901
- function clampPitch(pitch) {
3902
- if (pitch > 89 && pitch < 180) {
3903
- return 89;
3904
- }
3905
- if (pitch < 271 && pitch >= 180) {
3906
- return 271;
3907
- }
3908
- return pitch;
3909
- }
3910
- function clampViewAngles(params) {
3911
- const { pmFlags, cmdAngles, deltaAngles } = params;
3912
- let viewangles;
3913
- if ((pmFlags & 32) !== 0) {
3914
- viewangles = {
3915
- x: 0,
3916
- y: cmdAngles.y + deltaAngles.y,
3917
- z: 0
3918
- };
3919
- } else {
3920
- viewangles = addAngles(cmdAngles, deltaAngles);
3921
- viewangles = { ...viewangles, x: clampPitch(viewangles.x) };
3922
- }
3923
- const vectors = angleVectors(viewangles);
3924
- return { viewangles, ...vectors };
3925
- }
3926
3753
  var DEFAULT_FORWARD_SPEED = 200;
3927
3754
  var DEFAULT_SIDE_SPEED = 200;
3928
3755
  var DEFAULT_UP_SPEED = 200;
@@ -4012,303 +3839,9 @@ var AmmoType2 = /* @__PURE__ */ ((AmmoType22) => {
4012
3839
  })(AmmoType2 || {});
4013
3840
  var AMMO_TYPE_COUNT2 = Object.keys(AmmoType2).length / 2;
4014
3841
 
4015
- // src/prediction.ts
4016
- var DEFAULTS = {
4017
- pmFriction: 6,
4018
- pmStopSpeed: 100,
4019
- pmAccelerate: 10,
4020
- pmAirAccelerate: 1,
4021
- pmWaterAccelerate: 4,
4022
- pmWaterFriction: 1,
4023
- pmMaxSpeed: 300,
4024
- pmDuckSpeed: 100,
4025
- pmWaterSpeed: 400,
4026
- groundIsSlick: false
4027
- };
4028
- var DEFAULT_GRAVITY = 800;
4029
- var ZERO_VEC32 = { x: 0, y: 0, z: 0 };
4030
- var MSEC_MAX = 250;
4031
- function defaultPredictionState() {
4032
- return {
4033
- origin: ZERO_VEC32,
4034
- velocity: ZERO_VEC32,
4035
- viewangles: ZERO_VEC32,
4036
- pmFlags: PmFlag.OnGround,
4037
- pmType: PmType.Normal,
4038
- waterlevel: WaterLevel.None,
4039
- gravity: DEFAULT_GRAVITY,
4040
- deltaAngles: ZERO_VEC32,
4041
- health: 0,
4042
- armor: 0,
4043
- ammo: 0,
4044
- blend: [0, 0, 0, 0],
4045
- damageAlpha: 0,
4046
- damageIndicators: []
4047
- };
4048
- }
4049
- function normalizeState(state) {
4050
- if (!state) return defaultPredictionState();
4051
- return {
4052
- ...defaultPredictionState(),
4053
- ...state,
4054
- origin: { ...state.origin },
4055
- velocity: { ...state.velocity },
4056
- viewangles: { ...state.viewangles },
4057
- deltaAngles: state.deltaAngles ? { ...state.deltaAngles } : ZERO_VEC32,
4058
- blend: state.blend ? [...state.blend] : [0, 0, 0, 0],
4059
- damageIndicators: state.damageIndicators ? [...state.damageIndicators] : []
4060
- };
4061
- }
4062
- function lerp2(a, b, t) {
4063
- return a + (b - a) * t;
4064
- }
4065
- function lerpAngle(a, b, t) {
4066
- let delta = angleMod(b - a);
4067
- if (delta > 180) {
4068
- delta -= 360;
4069
- }
4070
- return angleMod(a + delta * t);
4071
- }
4072
- function interpolatePredictionState(previous, latest, alpha) {
4073
- const clamped = Math.max(0, Math.min(alpha, 1));
4074
- return {
4075
- origin: {
4076
- x: lerp2(previous.origin.x, latest.origin.x, clamped),
4077
- y: lerp2(previous.origin.y, latest.origin.y, clamped),
4078
- z: lerp2(previous.origin.z, latest.origin.z, clamped)
4079
- },
4080
- velocity: {
4081
- x: lerp2(previous.velocity.x, latest.velocity.x, clamped),
4082
- y: lerp2(previous.velocity.y, latest.velocity.y, clamped),
4083
- z: lerp2(previous.velocity.z, latest.velocity.z, clamped)
4084
- },
4085
- viewangles: {
4086
- x: lerpAngle(previous.viewangles.x, latest.viewangles.x, clamped),
4087
- y: lerpAngle(previous.viewangles.y, latest.viewangles.y, clamped),
4088
- z: lerpAngle(previous.viewangles.z, latest.viewangles.z, clamped)
4089
- },
4090
- pmFlags: latest.pmFlags,
4091
- pmType: latest.pmType,
4092
- waterlevel: latest.waterlevel,
4093
- gravity: latest.gravity,
4094
- deltaAngles: latest.deltaAngles,
4095
- client: latest.client,
4096
- health: lerp2(previous.health, latest.health, clamped),
4097
- armor: lerp2(previous.armor, latest.armor, clamped),
4098
- ammo: lerp2(previous.ammo, latest.ammo, clamped),
4099
- centerPrint: latest.centerPrint,
4100
- notify: latest.notify,
4101
- blend: latest.blend,
4102
- pickupIcon: latest.pickupIcon,
4103
- damageAlpha: latest.damageAlpha,
4104
- damageIndicators: latest.damageIndicators
4105
- };
4106
- }
4107
- function simulateCommand(state, cmd, settings, trace) {
4108
- const frametime = Math.min(Math.max(cmd.msec, 0), MSEC_MAX) / 1e3;
4109
- const onGround = hasPmFlag(state.pmFlags, PmFlag.OnGround);
4110
- const onLadder = hasPmFlag(state.pmFlags, PmFlag.OnLadder);
4111
- let velocity = applyPmoveFriction({
4112
- velocity: state.velocity,
4113
- frametime,
4114
- onGround,
4115
- groundIsSlick: settings.groundIsSlick,
4116
- onLadder,
4117
- waterlevel: state.waterlevel,
4118
- pmFriction: settings.pmFriction,
4119
- pmStopSpeed: settings.pmStopSpeed,
4120
- pmWaterFriction: settings.pmWaterFriction
4121
- });
4122
- const { viewangles, forward, right } = clampViewAngles({
4123
- pmFlags: state.pmFlags,
4124
- cmdAngles: cmd.angles,
4125
- deltaAngles: state.deltaAngles ?? ZERO_VEC32
4126
- });
4127
- const wish = state.waterlevel > WaterLevel.None ? buildWaterWish({ forward, right, cmd, maxSpeed: settings.pmWaterSpeed }) : buildAirGroundWish({ forward, right, cmd, maxSpeed: settings.pmMaxSpeed });
4128
- if (state.waterlevel > WaterLevel.None) {
4129
- velocity = applyPmoveAccelerate({
4130
- velocity,
4131
- wishdir: wish.wishdir,
4132
- wishspeed: wish.wishspeed,
4133
- accel: settings.pmWaterAccelerate,
4134
- frametime
4135
- });
4136
- } else if (onGround || onLadder) {
4137
- const maxSpeed = hasPmFlag(state.pmFlags, PmFlag.Ducked) ? settings.pmDuckSpeed : settings.pmMaxSpeed;
4138
- const clampedWish = wish.wishspeed > maxSpeed ? {
4139
- wishdir: wish.wishdir,
4140
- wishspeed: maxSpeed
4141
- } : wish;
4142
- velocity = applyPmoveAccelerate({
4143
- velocity,
4144
- wishdir: clampedWish.wishdir,
4145
- wishspeed: clampedWish.wishspeed,
4146
- accel: settings.pmAccelerate,
4147
- frametime
4148
- });
4149
- } else {
4150
- velocity = applyPmoveAirAccelerate({
4151
- velocity,
4152
- wishdir: wish.wishdir,
4153
- wishspeed: wish.wishspeed,
4154
- accel: settings.pmAirAccelerate,
4155
- frametime
4156
- });
4157
- velocity = { ...velocity, z: velocity.z - state.gravity * frametime };
4158
- }
4159
- const traceResult = trace(state.origin, addVec3(state.origin, scaleVec3(velocity, frametime)));
4160
- const origin = traceResult.endpos;
4161
- return {
4162
- ...state,
4163
- origin,
4164
- velocity,
4165
- viewangles
4166
- };
4167
- }
4168
- var ClientPrediction = class {
4169
- constructor(trace, settings = {}) {
4170
- this.baseFrame = {
4171
- frame: 0,
4172
- timeMs: 0,
4173
- state: defaultPredictionState()
4174
- };
4175
- this.commands = [];
4176
- this.predicted = defaultPredictionState();
4177
- this.settings = { ...DEFAULTS, ...settings };
4178
- this.trace = trace;
4179
- this.predicted = this.baseFrame.state ?? defaultPredictionState();
4180
- }
4181
- setAuthoritative(frame) {
4182
- const normalized = normalizeState(frame.state);
4183
- this.baseFrame = { ...frame, state: normalized };
4184
- this.commands = this.commands.filter((cmd) => (cmd.serverFrame ?? Number.MAX_SAFE_INTEGER) > frame.frame);
4185
- return this.recompute();
4186
- }
4187
- enqueueCommand(cmd) {
4188
- this.commands.push(cmd);
4189
- return this.recompute();
4190
- }
4191
- getPredictedState() {
4192
- return this.predicted;
4193
- }
4194
- recompute() {
4195
- let state = normalizeState(this.baseFrame.state);
4196
- for (const cmd of this.commands) {
4197
- state = simulateCommand(state, cmd, this.settings, this.trace);
4198
- }
4199
- this.predicted = state;
4200
- return state;
4201
- }
4202
- };
4203
-
4204
- // src/view-effects.ts
4205
- var DEFAULT_SETTINGS = {
4206
- runPitch: 2e-3,
4207
- runRoll: 0.01,
4208
- // Changed from 0.005 to match Quake 2 slope (2.0 / 200.0)
4209
- bobUp: 5e-3,
4210
- bobPitch: 2e-3,
4211
- bobRoll: 2e-3,
4212
- maxBobHeight: 6,
4213
- maxBobAngle: 1.2
4214
- };
4215
- function clampViewOffset(offset) {
4216
- return {
4217
- x: Math.max(-14, Math.min(14, offset.x)),
4218
- y: Math.max(-14, Math.min(14, offset.y)),
4219
- z: Math.max(-22, Math.min(30, offset.z))
4220
- };
4221
- }
4222
- function computeBobMove(xyspeed, onGround, frameTimeMs) {
4223
- if (!onGround) return 0;
4224
- if (xyspeed > 210) return frameTimeMs / 400;
4225
- if (xyspeed > 100) return frameTimeMs / 800;
4226
- return frameTimeMs / 1600;
4227
- }
4228
- function computeBobValues(previousBobTime, xyspeed, pmFlags, onGround, frameTimeMs) {
4229
- if (xyspeed < 5) {
4230
- return { bobTime: 0, bobCycle: 0, bobCycleRun: 0, bobFracSin: 0 };
4231
- }
4232
- const bobMove = computeBobMove(xyspeed, onGround, frameTimeMs);
4233
- const bobTimeRun = previousBobTime + bobMove;
4234
- const crouched = hasPmFlag(pmFlags, PmFlag.Ducked) && onGround;
4235
- const bobTime = crouched ? bobTimeRun * 4 : bobTimeRun;
4236
- return {
4237
- bobTime: bobTimeRun,
4238
- bobCycle: Math.floor(bobTime),
4239
- bobCycleRun: Math.floor(bobTimeRun),
4240
- bobFracSin: Math.abs(Math.sin(bobTime * Math.PI))
4241
- };
4242
- }
4243
- var ViewEffects = class {
4244
- constructor(settings = {}) {
4245
- this.bobTime = 0;
4246
- this.bobCycle = 0;
4247
- this.bobCycleRun = 0;
4248
- this.bobFracSin = 0;
4249
- this.settings = { ...DEFAULT_SETTINGS, ...settings };
4250
- }
4251
- addKick(kick) {
4252
- if (kick.durationMs <= 0) return;
4253
- this.kick = { ...kick, remainingMs: kick.durationMs };
4254
- }
4255
- get last() {
4256
- return this.lastSample;
4257
- }
4258
- sample(state, frameTimeMs) {
4259
- const { forward, right } = angleVectors(
4260
- clampViewAngles({ pmFlags: state.pmFlags, cmdAngles: state.viewangles, deltaAngles: state.deltaAngles ?? ZERO_VEC3 }).viewangles
4261
- );
4262
- const xyspeed = Math.sqrt(state.velocity.x * state.velocity.x + state.velocity.y * state.velocity.y);
4263
- const onGround = hasPmFlag(state.pmFlags, PmFlag.OnGround);
4264
- const bobValues = computeBobValues(this.bobTime, xyspeed, state.pmFlags, onGround, frameTimeMs);
4265
- this.bobTime = bobValues.bobTime;
4266
- this.bobCycle = bobValues.bobCycle;
4267
- this.bobCycleRun = bobValues.bobCycleRun;
4268
- this.bobFracSin = bobValues.bobFracSin;
4269
- let pitchTilt = dotVec3(state.velocity, forward) * this.settings.runPitch;
4270
- const side = dotVec3(state.velocity, right);
4271
- const sign = side < 0 ? -1 : 1;
4272
- const absSide = Math.abs(side);
4273
- let rollTilt = absSide * this.settings.runRoll;
4274
- if (rollTilt > 2) {
4275
- rollTilt = 2;
4276
- }
4277
- rollTilt *= sign;
4278
- let pitchDelta = this.bobFracSin * this.settings.bobPitch * xyspeed;
4279
- let rollDelta = this.bobFracSin * this.settings.bobRoll * xyspeed;
4280
- if (hasPmFlag(state.pmFlags, PmFlag.Ducked) && onGround) {
4281
- pitchDelta *= 6;
4282
- rollDelta *= 6;
4283
- }
4284
- pitchTilt += Math.min(pitchDelta, this.settings.maxBobAngle);
4285
- rollDelta = Math.min(rollDelta, this.settings.maxBobAngle);
4286
- if (this.bobCycle & 1) rollDelta = -rollDelta;
4287
- rollTilt += rollDelta;
4288
- const bobHeight = Math.min(this.bobFracSin * xyspeed * this.settings.bobUp, this.settings.maxBobHeight);
4289
- let kickPitch = 0;
4290
- let kickRoll = 0;
4291
- if (this.kick && this.kick.remainingMs > 0) {
4292
- const ratio = Math.max(0, Math.min(1, this.kick.remainingMs / this.kick.durationMs));
4293
- kickPitch += ratio * this.kick.pitch;
4294
- kickRoll += ratio * this.kick.roll;
4295
- this.kick.remainingMs = Math.max(0, this.kick.remainingMs - frameTimeMs);
4296
- if (this.kick.remainingMs === 0) this.kick = void 0;
4297
- }
4298
- const angles = { x: pitchTilt + kickPitch, y: 0, z: rollTilt + kickRoll };
4299
- const offset = { x: 0, y: 0, z: bobHeight };
4300
- const sample = {
4301
- angles,
4302
- offset: clampViewOffset(offset),
4303
- bobCycle: this.bobCycle,
4304
- bobCycleRun: this.bobCycleRun,
4305
- bobFracSin: this.bobFracSin,
4306
- xyspeed
4307
- };
4308
- this.lastSample = sample;
4309
- return sample;
4310
- }
4311
- };
3842
+ // src/index.ts
3843
+ var import_cgame2 = require("@quake2ts/cgame");
3844
+ var import_cgame3 = require("@quake2ts/cgame");
4312
3845
 
4313
3846
  // src/hud/crosshair.ts
4314
3847
  var crosshairPic = null;
@@ -4771,6 +4304,9 @@ var SubtitleSystem = class {
4771
4304
  }
4772
4305
  };
4773
4306
 
4307
+ // src/demo/handler.ts
4308
+ var import_cgame = require("@quake2ts/cgame");
4309
+
4774
4310
  // src/demo/itemMapping.ts
4775
4311
  var import_game3 = require("@quake2ts/game");
4776
4312
  var import_game4 = require("@quake2ts/game");
@@ -5149,15 +4685,15 @@ var ClientNetworkHandler = class {
5149
4685
  }
5150
4686
  const origin = { ...ps.origin };
5151
4687
  const velocity = { ...ps.velocity };
5152
- const viewangles = { ...ps.viewangles };
4688
+ const viewAngles = { ...ps.viewangles };
5153
4689
  const deltaAngles = { ...ps.delta_angles };
5154
4690
  return {
5155
4691
  origin,
5156
4692
  velocity,
5157
- viewangles,
4693
+ viewAngles,
5158
4694
  pmFlags: ps.pm_flags,
5159
4695
  pmType: ps.pm_type,
5160
- waterlevel: WaterLevel.None,
4696
+ waterLevel: WaterLevel.None,
5161
4697
  gravity: ps.gravity,
5162
4698
  deltaAngles,
5163
4699
  client: {
@@ -5177,11 +4713,21 @@ var ClientNetworkHandler = class {
5177
4713
  // No blend from demo frame currently (need to parse svc_playerinfo more fully)
5178
4714
  damageAlpha: 0,
5179
4715
  // Need to extract from renderfx/flash
5180
- damageIndicators: []
4716
+ damageIndicators: [],
4717
+ // Stubs
4718
+ stats: [...ps.stats],
4719
+ kick_angles: ZERO_VEC3,
4720
+ gunoffset: ZERO_VEC3,
4721
+ gunangles: ZERO_VEC3,
4722
+ gunindex: 0,
4723
+ onGround: false,
4724
+ // Infer from pmFlags?
4725
+ mins: { x: -16, y: -16, z: -24 },
4726
+ maxs: { x: 16, y: 16, z: 32 }
5181
4727
  };
5182
4728
  }
5183
4729
  getPredictionState(timeMs) {
5184
- if (!this.latestFrame) return defaultPredictionState();
4730
+ if (!this.latestFrame) return (0, import_cgame.defaultPredictionState)();
5185
4731
  const latestState = this.convertFrameToPredictionState(this.latestFrame);
5186
4732
  if (this.previousFrame && timeMs !== void 0) {
5187
4733
  const latestServerTime = this.latestFrame.serverFrame * 100;
@@ -5189,7 +4735,7 @@ var ClientNetworkHandler = class {
5189
4735
  if (timeMs >= previousServerTime && timeMs <= latestServerTime) {
5190
4736
  const alpha = (timeMs - previousServerTime) / (latestServerTime - previousServerTime);
5191
4737
  const previousState = this.convertFrameToPredictionState(this.previousFrame);
5192
- return interpolatePredictionState(previousState, latestState, Math.max(0, Math.min(1, alpha)));
4738
+ return (0, import_cgame.interpolatePredictionState)(previousState, latestState, Math.max(0, Math.min(1, alpha)));
5193
4739
  }
5194
4740
  }
5195
4741
  return latestState;
@@ -6098,7 +5644,7 @@ function normalizeCommand(command) {
6098
5644
  }
6099
5645
 
6100
5646
  // src/input/controller.ts
6101
- var MSEC_MAX2 = 250;
5647
+ var MSEC_MAX = 250;
6102
5648
  var KeyButton = class {
6103
5649
  constructor() {
6104
5650
  this.activeCodes = /* @__PURE__ */ new Set();
@@ -6328,7 +5874,7 @@ var InputController = class {
6328
5874
  sidemove = this.clampMove(sidemove, this.sideSpeed);
6329
5875
  upmove = this.clampMove(upmove, this.upSpeed);
6330
5876
  let buttons = this.collectButtonBits(frameMsec, now);
6331
- const msec = Math.min(Math.max(Math.round(frameMsec), 1), MSEC_MAX2);
5877
+ const msec = Math.min(Math.max(Math.round(frameMsec), 1), MSEC_MAX);
6332
5878
  if (this.anyPressed || buttons !== PlayerButton.None) {
6333
5879
  buttons |= PlayerButton.Any;
6334
5880
  }
@@ -6520,11 +6066,14 @@ var InputCommandBuffer = class {
6520
6066
  };
6521
6067
 
6522
6068
  // src/index.ts
6523
- function lerp3(a, b, t) {
6069
+ var import_cgame4 = require("@quake2ts/cgame");
6070
+ var import_cgame5 = require("@quake2ts/cgame");
6071
+ var ZERO_VEC32 = { x: 0, y: 0, z: 0 };
6072
+ function lerp2(a, b, t) {
6524
6073
  return a + (b - a) * t;
6525
6074
  }
6526
- function lerpAngle2(a, b, t) {
6527
- return lerp3(a, b, t);
6075
+ function lerpAngle(a, b, t) {
6076
+ return lerp2(a, b, t);
6528
6077
  }
6529
6078
  function buildRenderableEntities(latestEntities, previousEntities, alpha, configStrings, imports) {
6530
6079
  const renderables = [];
@@ -6538,14 +6087,14 @@ function buildRenderableEntities(latestEntities, previousEntities, alpha, config
6538
6087
  const model = assets.getMd2Model(modelName) || assets.getMd3Model(modelName);
6539
6088
  if (!model) continue;
6540
6089
  const origin = {
6541
- x: lerp3(prev.origin.x, ent.origin.x, alpha),
6542
- y: lerp3(prev.origin.y, ent.origin.y, alpha),
6543
- z: lerp3(prev.origin.z, ent.origin.z, alpha)
6090
+ x: lerp2(prev.origin.x, ent.origin.x, alpha),
6091
+ y: lerp2(prev.origin.y, ent.origin.y, alpha),
6092
+ z: lerp2(prev.origin.z, ent.origin.z, alpha)
6544
6093
  };
6545
6094
  const angles = {
6546
- x: lerpAngle2(prev.angles.x, ent.angles.x, alpha),
6547
- y: lerpAngle2(prev.angles.y, ent.angles.y, alpha),
6548
- z: lerpAngle2(prev.angles.z, ent.angles.z, alpha)
6095
+ x: lerpAngle(prev.angles.x, ent.angles.x, alpha),
6096
+ y: lerpAngle(prev.angles.y, ent.angles.y, alpha),
6097
+ z: lerpAngle(prev.angles.z, ent.angles.z, alpha)
6549
6098
  };
6550
6099
  const frame = ent.frame;
6551
6100
  const prevFrame = prev.frame;
@@ -6584,8 +6133,8 @@ function buildRenderableEntities(latestEntities, previousEntities, alpha, config
6584
6133
  return renderables;
6585
6134
  }
6586
6135
  function createClient(imports) {
6587
- const prediction = new ClientPrediction(imports.engine.trace);
6588
- const view = new ViewEffects();
6136
+ const prediction = new import_cgame2.ClientPrediction(imports.engine.trace);
6137
+ const view = new import_cgame3.ViewEffects();
6589
6138
  const messageSystem = new MessageSystem();
6590
6139
  const subtitleSystem = new SubtitleSystem();
6591
6140
  const demoPlayback = new DemoPlaybackController();
@@ -6784,7 +6333,7 @@ function createClient(imports) {
6784
6333
  latestFrame = sample.latest;
6785
6334
  }
6786
6335
  if (sample.previous?.state && sample.latest?.state) {
6787
- lastRendered = interpolatePredictionState(sample.previous.state, sample.latest.state, sample.alpha);
6336
+ lastRendered = (0, import_cgame2.interpolatePredictionState)(sample.previous.state, sample.latest.state, sample.alpha);
6788
6337
  if (sample.latest.state.packetEntities && sample.previous.state.packetEntities) {
6789
6338
  renderEntities = buildRenderableEntities(
6790
6339
  sample.latest.state.packetEntities,
@@ -6802,13 +6351,13 @@ function createClient(imports) {
6802
6351
  lastView = view.sample(lastRendered, frameTimeMs);
6803
6352
  const command = {};
6804
6353
  if (lastRendered) {
6805
- const { origin, viewangles } = lastRendered;
6354
+ const { origin, viewAngles } = lastRendered;
6806
6355
  camera = new Camera();
6807
6356
  camera.position = vec3_exports.fromValues(origin.x, origin.y, origin.z);
6808
6357
  const viewOffset = lastView?.offset ?? { x: 0, y: 0, z: 0 };
6809
6358
  vec3_exports.add(camera.position, camera.position, [viewOffset.x, viewOffset.y, viewOffset.z]);
6810
6359
  const effectAngles = lastView?.angles ?? { x: 0, y: 0, z: 0 };
6811
- camera.angles = vec3_exports.fromValues(viewangles.x + effectAngles.x, viewangles.y + effectAngles.y, viewangles.z + effectAngles.z);
6360
+ camera.angles = vec3_exports.fromValues(viewAngles.x + effectAngles.x, viewAngles.y + effectAngles.y, viewAngles.z + effectAngles.z);
6812
6361
  camera.fov = isZooming ? 40 : fovValue;
6813
6362
  camera.aspect = 4 / 3;
6814
6363
  if (imports.engine.renderer) {
@@ -6863,9 +6412,9 @@ function createClient(imports) {
6863
6412
  const playerState = {
6864
6413
  origin: lastRendered.origin,
6865
6414
  velocity: lastRendered.velocity,
6866
- viewAngles: lastRendered.viewangles,
6415
+ viewAngles: lastRendered.viewAngles,
6867
6416
  onGround: hasPmFlag(lastRendered.pmFlags, PmFlag.OnGround),
6868
- waterLevel: lastRendered.waterlevel,
6417
+ waterLevel: lastRendered.waterLevel,
6869
6418
  mins: { x: -16, y: -16, z: -24 },
6870
6419
  maxs: { x: 16, y: 16, z: 32 },
6871
6420
  damageAlpha: lastRendered.damageAlpha ?? 0,
@@ -6874,7 +6423,13 @@ function createClient(imports) {
6874
6423
  pickupIcon: lastRendered.pickupIcon,
6875
6424
  centerPrint: messageSystem["centerPrintMsg"]?.text,
6876
6425
  // Hack to get text for legacy state? No, Draw_Hud uses messageSystem directly now.
6877
- notify: void 0
6426
+ notify: void 0,
6427
+ // Stubs for new fields
6428
+ stats: [],
6429
+ kick_angles: ZERO_VEC32,
6430
+ gunoffset: ZERO_VEC32,
6431
+ gunangles: ZERO_VEC32,
6432
+ gunindex: 0
6878
6433
  };
6879
6434
  const playbackState = demoPlayback.getState();
6880
6435
  const hudTimeMs = playbackState === PlaybackState.Playing || playbackState === PlaybackState.Paused ? (demoHandler.latestFrame?.serverFrame || 0) * 100 : timeMs;
@@ -6882,9 +6437,9 @@ function createClient(imports) {
6882
6437
  imports.engine.renderer,
6883
6438
  playerState,
6884
6439
  lastRendered.client,
6885
- lastRendered.health,
6886
- lastRendered.armor,
6887
- lastRendered.ammo,
6440
+ lastRendered.health ?? 0,
6441
+ lastRendered.armor ?? 0,
6442
+ lastRendered.ammo ?? 0,
6888
6443
  stats,
6889
6444
  messageSystem,
6890
6445
  subtitleSystem,
@@ -6983,7 +6538,6 @@ function createClient(imports) {
6983
6538
  ViewEffects,
6984
6539
  createClient,
6985
6540
  createDefaultBindings,
6986
- defaultPredictionState,
6987
6541
  interpolatePredictionState,
6988
6542
  normalizeCommand,
6989
6543
  normalizeInputCode