quake2ts 0.0.194 → 0.0.196

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
@@ -3495,25 +3495,9 @@ var __export3 = (target, all) => {
3495
3495
  };
3496
3496
  var ZERO_VEC3 = { x: 0, y: 0, z: 0 };
3497
3497
  var DEG_TO_RAD2 = Math.PI / 180;
3498
- function addVec3(a, b) {
3499
- return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
3500
- }
3501
- function scaleVec3(a, scalar) {
3502
- return { x: a.x * scalar, y: a.y * scalar, z: a.z * scalar };
3503
- }
3504
3498
  function dotVec3(a, b) {
3505
3499
  return a.x * b.x + a.y * b.y + a.z * b.z;
3506
3500
  }
3507
- function lengthSquaredVec3(a) {
3508
- return dotVec3(a, a);
3509
- }
3510
- function lengthVec3(a) {
3511
- return Math.sqrt(lengthSquaredVec3(a));
3512
- }
3513
- function normalizeVec3(a) {
3514
- const len2 = lengthVec3(a);
3515
- return len2 === 0 ? a : scaleVec3(a, 1 / len2);
3516
- }
3517
3501
  var PITCH = 0;
3518
3502
  var YAW = 1;
3519
3503
  var ROLL = 2;
@@ -3724,16 +3708,6 @@ var PmFlag = /* @__PURE__ */ ((PmFlag22) => {
3724
3708
  function hasPmFlag(flags, flag) {
3725
3709
  return (flags & flag) !== 0;
3726
3710
  }
3727
- var PmType = /* @__PURE__ */ ((PmType22) => {
3728
- PmType22[PmType22["Normal"] = 0] = "Normal";
3729
- PmType22[PmType22["Grapple"] = 1] = "Grapple";
3730
- PmType22[PmType22["NoClip"] = 2] = "NoClip";
3731
- PmType22[PmType22["Spectator"] = 3] = "Spectator";
3732
- PmType22[PmType22["Dead"] = 4] = "Dead";
3733
- PmType22[PmType22["Gib"] = 5] = "Gib";
3734
- PmType22[PmType22["Freeze"] = 6] = "Freeze";
3735
- return PmType22;
3736
- })(PmType || {});
3737
3711
  var PlayerButton = /* @__PURE__ */ ((PlayerButton2) => {
3738
3712
  PlayerButton2[PlayerButton2["None"] = 0] = "None";
3739
3713
  PlayerButton2[PlayerButton2["Attack"] = 1] = "Attack";
@@ -3744,153 +3718,7 @@ var PlayerButton = /* @__PURE__ */ ((PlayerButton2) => {
3744
3718
  PlayerButton2[PlayerButton2["Any"] = 128] = "Any";
3745
3719
  return PlayerButton2;
3746
3720
  })(PlayerButton || {});
3747
- function applyPmoveFriction(params) {
3748
- const {
3749
- velocity,
3750
- frametime,
3751
- onGround,
3752
- groundIsSlick,
3753
- onLadder,
3754
- waterlevel,
3755
- pmFriction,
3756
- pmStopSpeed,
3757
- pmWaterFriction
3758
- } = params;
3759
- const speed = lengthVec3(velocity);
3760
- if (speed < 1) {
3761
- return { x: 0, y: 0, z: velocity.z };
3762
- }
3763
- let drop = 0;
3764
- if (onGround && !groundIsSlick || onLadder) {
3765
- const control = speed < pmStopSpeed ? pmStopSpeed : speed;
3766
- const friction = pmFriction;
3767
- drop += control * friction * frametime;
3768
- }
3769
- if (waterlevel > 0 && !onLadder) {
3770
- drop += speed * pmWaterFriction * waterlevel * frametime;
3771
- }
3772
- let newspeed = speed - drop;
3773
- if (newspeed < 0) {
3774
- newspeed = 0;
3775
- }
3776
- if (newspeed === speed) {
3777
- return velocity;
3778
- }
3779
- const scale3 = newspeed / speed;
3780
- return scaleVec3(velocity, scale3);
3781
- }
3782
- function applyPmoveAccelerate(params) {
3783
- const { velocity, wishdir, wishspeed, accel, frametime } = params;
3784
- const currentSpeed = dotVec3(velocity, wishdir);
3785
- const addSpeed = wishspeed - currentSpeed;
3786
- if (addSpeed <= 0) {
3787
- return velocity;
3788
- }
3789
- let accelSpeed = accel * frametime * wishspeed;
3790
- if (accelSpeed > addSpeed) {
3791
- accelSpeed = addSpeed;
3792
- }
3793
- return {
3794
- x: velocity.x + wishdir.x * accelSpeed,
3795
- y: velocity.y + wishdir.y * accelSpeed,
3796
- z: velocity.z + wishdir.z * accelSpeed
3797
- };
3798
- }
3799
- function applyPmoveAirAccelerate(params) {
3800
- const { velocity, wishdir, wishspeed, accel, frametime } = params;
3801
- const wishspd = Math.min(wishspeed, 30);
3802
- const currentSpeed = dotVec3(velocity, wishdir);
3803
- const addSpeed = wishspd - currentSpeed;
3804
- if (addSpeed <= 0) {
3805
- return velocity;
3806
- }
3807
- let accelSpeed = accel * wishspeed * frametime;
3808
- if (accelSpeed > addSpeed) {
3809
- accelSpeed = addSpeed;
3810
- }
3811
- return {
3812
- x: velocity.x + wishdir.x * accelSpeed,
3813
- y: velocity.y + wishdir.y * accelSpeed,
3814
- z: velocity.z + wishdir.z * accelSpeed
3815
- };
3816
- }
3817
- function buildAirGroundWish(params) {
3818
- const { forward, right, cmd, maxSpeed } = params;
3819
- let wishvel = {
3820
- x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
3821
- y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
3822
- z: 0
3823
- };
3824
- let wishspeed = lengthVec3(wishvel);
3825
- if (wishspeed > maxSpeed) {
3826
- const scale3 = maxSpeed / wishspeed;
3827
- wishvel = scaleVec3(wishvel, scale3);
3828
- wishspeed = maxSpeed;
3829
- }
3830
- return {
3831
- wishdir: wishspeed === 0 ? wishvel : normalizeVec3(wishvel),
3832
- wishspeed
3833
- };
3834
- }
3835
- function buildWaterWish(params) {
3836
- const { forward, right, cmd, maxSpeed } = params;
3837
- let wishvel = {
3838
- x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
3839
- y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
3840
- z: 0
3841
- };
3842
- if (cmd.upmove > 10) {
3843
- wishvel = addVec3(wishvel, { x: 0, y: 0, z: cmd.upmove });
3844
- } else if (cmd.upmove < -10) {
3845
- wishvel = addVec3(wishvel, { x: 0, y: 0, z: cmd.upmove });
3846
- } else {
3847
- wishvel = addVec3(wishvel, { x: 0, y: 0, z: 10 });
3848
- }
3849
- let wishspeed = lengthVec3(wishvel);
3850
- if (wishspeed > maxSpeed) {
3851
- const scale3 = maxSpeed / wishspeed;
3852
- wishvel = scaleVec3(wishvel, scale3);
3853
- wishspeed = maxSpeed;
3854
- }
3855
- wishspeed *= 0.5;
3856
- return {
3857
- wishdir: wishspeed === 0 ? wishvel : normalizeVec3(wishvel),
3858
- wishspeed
3859
- };
3860
- }
3861
3721
  var WATERJUMP_CLEAR2 = 8 | 16 | 32 | 1024;
3862
- function addAngles(cmdAngles, deltaAngles) {
3863
- return {
3864
- x: cmdAngles.x + deltaAngles.x,
3865
- y: cmdAngles.y + deltaAngles.y,
3866
- z: cmdAngles.z + deltaAngles.z
3867
- };
3868
- }
3869
- function clampPitch(pitch) {
3870
- if (pitch > 89 && pitch < 180) {
3871
- return 89;
3872
- }
3873
- if (pitch < 271 && pitch >= 180) {
3874
- return 271;
3875
- }
3876
- return pitch;
3877
- }
3878
- function clampViewAngles(params) {
3879
- const { pmFlags, cmdAngles, deltaAngles } = params;
3880
- let viewangles;
3881
- if ((pmFlags & 32) !== 0) {
3882
- viewangles = {
3883
- x: 0,
3884
- y: cmdAngles.y + deltaAngles.y,
3885
- z: 0
3886
- };
3887
- } else {
3888
- viewangles = addAngles(cmdAngles, deltaAngles);
3889
- viewangles = { ...viewangles, x: clampPitch(viewangles.x) };
3890
- }
3891
- const vectors = angleVectors(viewangles);
3892
- return { viewangles, ...vectors };
3893
- }
3894
3722
  var DEFAULT_FORWARD_SPEED = 200;
3895
3723
  var DEFAULT_SIDE_SPEED = 200;
3896
3724
  var DEFAULT_UP_SPEED = 200;
@@ -3980,303 +3808,9 @@ var AmmoType2 = /* @__PURE__ */ ((AmmoType22) => {
3980
3808
  })(AmmoType2 || {});
3981
3809
  var AMMO_TYPE_COUNT2 = Object.keys(AmmoType2).length / 2;
3982
3810
 
3983
- // src/prediction.ts
3984
- var DEFAULTS = {
3985
- pmFriction: 6,
3986
- pmStopSpeed: 100,
3987
- pmAccelerate: 10,
3988
- pmAirAccelerate: 1,
3989
- pmWaterAccelerate: 4,
3990
- pmWaterFriction: 1,
3991
- pmMaxSpeed: 300,
3992
- pmDuckSpeed: 100,
3993
- pmWaterSpeed: 400,
3994
- groundIsSlick: false
3995
- };
3996
- var DEFAULT_GRAVITY = 800;
3997
- var ZERO_VEC32 = { x: 0, y: 0, z: 0 };
3998
- var MSEC_MAX = 250;
3999
- function defaultPredictionState() {
4000
- return {
4001
- origin: ZERO_VEC32,
4002
- velocity: ZERO_VEC32,
4003
- viewangles: ZERO_VEC32,
4004
- pmFlags: PmFlag.OnGround,
4005
- pmType: PmType.Normal,
4006
- waterlevel: WaterLevel.None,
4007
- gravity: DEFAULT_GRAVITY,
4008
- deltaAngles: ZERO_VEC32,
4009
- health: 0,
4010
- armor: 0,
4011
- ammo: 0,
4012
- blend: [0, 0, 0, 0],
4013
- damageAlpha: 0,
4014
- damageIndicators: []
4015
- };
4016
- }
4017
- function normalizeState(state) {
4018
- if (!state) return defaultPredictionState();
4019
- return {
4020
- ...defaultPredictionState(),
4021
- ...state,
4022
- origin: { ...state.origin },
4023
- velocity: { ...state.velocity },
4024
- viewangles: { ...state.viewangles },
4025
- deltaAngles: state.deltaAngles ? { ...state.deltaAngles } : ZERO_VEC32,
4026
- blend: state.blend ? [...state.blend] : [0, 0, 0, 0],
4027
- damageIndicators: state.damageIndicators ? [...state.damageIndicators] : []
4028
- };
4029
- }
4030
- function lerp2(a, b, t) {
4031
- return a + (b - a) * t;
4032
- }
4033
- function lerpAngle(a, b, t) {
4034
- let delta = angleMod(b - a);
4035
- if (delta > 180) {
4036
- delta -= 360;
4037
- }
4038
- return angleMod(a + delta * t);
4039
- }
4040
- function interpolatePredictionState(previous, latest, alpha) {
4041
- const clamped = Math.max(0, Math.min(alpha, 1));
4042
- return {
4043
- origin: {
4044
- x: lerp2(previous.origin.x, latest.origin.x, clamped),
4045
- y: lerp2(previous.origin.y, latest.origin.y, clamped),
4046
- z: lerp2(previous.origin.z, latest.origin.z, clamped)
4047
- },
4048
- velocity: {
4049
- x: lerp2(previous.velocity.x, latest.velocity.x, clamped),
4050
- y: lerp2(previous.velocity.y, latest.velocity.y, clamped),
4051
- z: lerp2(previous.velocity.z, latest.velocity.z, clamped)
4052
- },
4053
- viewangles: {
4054
- x: lerpAngle(previous.viewangles.x, latest.viewangles.x, clamped),
4055
- y: lerpAngle(previous.viewangles.y, latest.viewangles.y, clamped),
4056
- z: lerpAngle(previous.viewangles.z, latest.viewangles.z, clamped)
4057
- },
4058
- pmFlags: latest.pmFlags,
4059
- pmType: latest.pmType,
4060
- waterlevel: latest.waterlevel,
4061
- gravity: latest.gravity,
4062
- deltaAngles: latest.deltaAngles,
4063
- client: latest.client,
4064
- health: lerp2(previous.health, latest.health, clamped),
4065
- armor: lerp2(previous.armor, latest.armor, clamped),
4066
- ammo: lerp2(previous.ammo, latest.ammo, clamped),
4067
- centerPrint: latest.centerPrint,
4068
- notify: latest.notify,
4069
- blend: latest.blend,
4070
- pickupIcon: latest.pickupIcon,
4071
- damageAlpha: latest.damageAlpha,
4072
- damageIndicators: latest.damageIndicators
4073
- };
4074
- }
4075
- function simulateCommand(state, cmd, settings, trace) {
4076
- const frametime = Math.min(Math.max(cmd.msec, 0), MSEC_MAX) / 1e3;
4077
- const onGround = hasPmFlag(state.pmFlags, PmFlag.OnGround);
4078
- const onLadder = hasPmFlag(state.pmFlags, PmFlag.OnLadder);
4079
- let velocity = applyPmoveFriction({
4080
- velocity: state.velocity,
4081
- frametime,
4082
- onGround,
4083
- groundIsSlick: settings.groundIsSlick,
4084
- onLadder,
4085
- waterlevel: state.waterlevel,
4086
- pmFriction: settings.pmFriction,
4087
- pmStopSpeed: settings.pmStopSpeed,
4088
- pmWaterFriction: settings.pmWaterFriction
4089
- });
4090
- const { viewangles, forward, right } = clampViewAngles({
4091
- pmFlags: state.pmFlags,
4092
- cmdAngles: cmd.angles,
4093
- deltaAngles: state.deltaAngles ?? ZERO_VEC32
4094
- });
4095
- const wish = state.waterlevel > WaterLevel.None ? buildWaterWish({ forward, right, cmd, maxSpeed: settings.pmWaterSpeed }) : buildAirGroundWish({ forward, right, cmd, maxSpeed: settings.pmMaxSpeed });
4096
- if (state.waterlevel > WaterLevel.None) {
4097
- velocity = applyPmoveAccelerate({
4098
- velocity,
4099
- wishdir: wish.wishdir,
4100
- wishspeed: wish.wishspeed,
4101
- accel: settings.pmWaterAccelerate,
4102
- frametime
4103
- });
4104
- } else if (onGround || onLadder) {
4105
- const maxSpeed = hasPmFlag(state.pmFlags, PmFlag.Ducked) ? settings.pmDuckSpeed : settings.pmMaxSpeed;
4106
- const clampedWish = wish.wishspeed > maxSpeed ? {
4107
- wishdir: wish.wishdir,
4108
- wishspeed: maxSpeed
4109
- } : wish;
4110
- velocity = applyPmoveAccelerate({
4111
- velocity,
4112
- wishdir: clampedWish.wishdir,
4113
- wishspeed: clampedWish.wishspeed,
4114
- accel: settings.pmAccelerate,
4115
- frametime
4116
- });
4117
- } else {
4118
- velocity = applyPmoveAirAccelerate({
4119
- velocity,
4120
- wishdir: wish.wishdir,
4121
- wishspeed: wish.wishspeed,
4122
- accel: settings.pmAirAccelerate,
4123
- frametime
4124
- });
4125
- velocity = { ...velocity, z: velocity.z - state.gravity * frametime };
4126
- }
4127
- const traceResult = trace(state.origin, addVec3(state.origin, scaleVec3(velocity, frametime)));
4128
- const origin = traceResult.endpos;
4129
- return {
4130
- ...state,
4131
- origin,
4132
- velocity,
4133
- viewangles
4134
- };
4135
- }
4136
- var ClientPrediction = class {
4137
- constructor(trace, settings = {}) {
4138
- this.baseFrame = {
4139
- frame: 0,
4140
- timeMs: 0,
4141
- state: defaultPredictionState()
4142
- };
4143
- this.commands = [];
4144
- this.predicted = defaultPredictionState();
4145
- this.settings = { ...DEFAULTS, ...settings };
4146
- this.trace = trace;
4147
- this.predicted = this.baseFrame.state ?? defaultPredictionState();
4148
- }
4149
- setAuthoritative(frame) {
4150
- const normalized = normalizeState(frame.state);
4151
- this.baseFrame = { ...frame, state: normalized };
4152
- this.commands = this.commands.filter((cmd) => (cmd.serverFrame ?? Number.MAX_SAFE_INTEGER) > frame.frame);
4153
- return this.recompute();
4154
- }
4155
- enqueueCommand(cmd) {
4156
- this.commands.push(cmd);
4157
- return this.recompute();
4158
- }
4159
- getPredictedState() {
4160
- return this.predicted;
4161
- }
4162
- recompute() {
4163
- let state = normalizeState(this.baseFrame.state);
4164
- for (const cmd of this.commands) {
4165
- state = simulateCommand(state, cmd, this.settings, this.trace);
4166
- }
4167
- this.predicted = state;
4168
- return state;
4169
- }
4170
- };
4171
-
4172
- // src/view-effects.ts
4173
- var DEFAULT_SETTINGS = {
4174
- runPitch: 2e-3,
4175
- runRoll: 0.01,
4176
- // Changed from 0.005 to match Quake 2 slope (2.0 / 200.0)
4177
- bobUp: 5e-3,
4178
- bobPitch: 2e-3,
4179
- bobRoll: 2e-3,
4180
- maxBobHeight: 6,
4181
- maxBobAngle: 1.2
4182
- };
4183
- function clampViewOffset(offset) {
4184
- return {
4185
- x: Math.max(-14, Math.min(14, offset.x)),
4186
- y: Math.max(-14, Math.min(14, offset.y)),
4187
- z: Math.max(-22, Math.min(30, offset.z))
4188
- };
4189
- }
4190
- function computeBobMove(xyspeed, onGround, frameTimeMs) {
4191
- if (!onGround) return 0;
4192
- if (xyspeed > 210) return frameTimeMs / 400;
4193
- if (xyspeed > 100) return frameTimeMs / 800;
4194
- return frameTimeMs / 1600;
4195
- }
4196
- function computeBobValues(previousBobTime, xyspeed, pmFlags, onGround, frameTimeMs) {
4197
- if (xyspeed < 5) {
4198
- return { bobTime: 0, bobCycle: 0, bobCycleRun: 0, bobFracSin: 0 };
4199
- }
4200
- const bobMove = computeBobMove(xyspeed, onGround, frameTimeMs);
4201
- const bobTimeRun = previousBobTime + bobMove;
4202
- const crouched = hasPmFlag(pmFlags, PmFlag.Ducked) && onGround;
4203
- const bobTime = crouched ? bobTimeRun * 4 : bobTimeRun;
4204
- return {
4205
- bobTime: bobTimeRun,
4206
- bobCycle: Math.floor(bobTime),
4207
- bobCycleRun: Math.floor(bobTimeRun),
4208
- bobFracSin: Math.abs(Math.sin(bobTime * Math.PI))
4209
- };
4210
- }
4211
- var ViewEffects = class {
4212
- constructor(settings = {}) {
4213
- this.bobTime = 0;
4214
- this.bobCycle = 0;
4215
- this.bobCycleRun = 0;
4216
- this.bobFracSin = 0;
4217
- this.settings = { ...DEFAULT_SETTINGS, ...settings };
4218
- }
4219
- addKick(kick) {
4220
- if (kick.durationMs <= 0) return;
4221
- this.kick = { ...kick, remainingMs: kick.durationMs };
4222
- }
4223
- get last() {
4224
- return this.lastSample;
4225
- }
4226
- sample(state, frameTimeMs) {
4227
- const { forward, right } = angleVectors(
4228
- clampViewAngles({ pmFlags: state.pmFlags, cmdAngles: state.viewangles, deltaAngles: state.deltaAngles ?? ZERO_VEC3 }).viewangles
4229
- );
4230
- const xyspeed = Math.sqrt(state.velocity.x * state.velocity.x + state.velocity.y * state.velocity.y);
4231
- const onGround = hasPmFlag(state.pmFlags, PmFlag.OnGround);
4232
- const bobValues = computeBobValues(this.bobTime, xyspeed, state.pmFlags, onGround, frameTimeMs);
4233
- this.bobTime = bobValues.bobTime;
4234
- this.bobCycle = bobValues.bobCycle;
4235
- this.bobCycleRun = bobValues.bobCycleRun;
4236
- this.bobFracSin = bobValues.bobFracSin;
4237
- let pitchTilt = dotVec3(state.velocity, forward) * this.settings.runPitch;
4238
- const side = dotVec3(state.velocity, right);
4239
- const sign = side < 0 ? -1 : 1;
4240
- const absSide = Math.abs(side);
4241
- let rollTilt = absSide * this.settings.runRoll;
4242
- if (rollTilt > 2) {
4243
- rollTilt = 2;
4244
- }
4245
- rollTilt *= sign;
4246
- let pitchDelta = this.bobFracSin * this.settings.bobPitch * xyspeed;
4247
- let rollDelta = this.bobFracSin * this.settings.bobRoll * xyspeed;
4248
- if (hasPmFlag(state.pmFlags, PmFlag.Ducked) && onGround) {
4249
- pitchDelta *= 6;
4250
- rollDelta *= 6;
4251
- }
4252
- pitchTilt += Math.min(pitchDelta, this.settings.maxBobAngle);
4253
- rollDelta = Math.min(rollDelta, this.settings.maxBobAngle);
4254
- if (this.bobCycle & 1) rollDelta = -rollDelta;
4255
- rollTilt += rollDelta;
4256
- const bobHeight = Math.min(this.bobFracSin * xyspeed * this.settings.bobUp, this.settings.maxBobHeight);
4257
- let kickPitch = 0;
4258
- let kickRoll = 0;
4259
- if (this.kick && this.kick.remainingMs > 0) {
4260
- const ratio = Math.max(0, Math.min(1, this.kick.remainingMs / this.kick.durationMs));
4261
- kickPitch += ratio * this.kick.pitch;
4262
- kickRoll += ratio * this.kick.roll;
4263
- this.kick.remainingMs = Math.max(0, this.kick.remainingMs - frameTimeMs);
4264
- if (this.kick.remainingMs === 0) this.kick = void 0;
4265
- }
4266
- const angles = { x: pitchTilt + kickPitch, y: 0, z: rollTilt + kickRoll };
4267
- const offset = { x: 0, y: 0, z: bobHeight };
4268
- const sample = {
4269
- angles,
4270
- offset: clampViewOffset(offset),
4271
- bobCycle: this.bobCycle,
4272
- bobCycleRun: this.bobCycleRun,
4273
- bobFracSin: this.bobFracSin,
4274
- xyspeed
4275
- };
4276
- this.lastSample = sample;
4277
- return sample;
4278
- }
4279
- };
3811
+ // src/index.ts
3812
+ import { ClientPrediction, interpolatePredictionState as interpolatePredictionState2 } from "@quake2ts/cgame";
3813
+ import { ViewEffects } from "@quake2ts/cgame";
4280
3814
 
4281
3815
  // src/hud/crosshair.ts
4282
3816
  var crosshairPic = null;
@@ -4739,6 +4273,9 @@ var SubtitleSystem = class {
4739
4273
  }
4740
4274
  };
4741
4275
 
4276
+ // src/demo/handler.ts
4277
+ import { defaultPredictionState, interpolatePredictionState } from "@quake2ts/cgame";
4278
+
4742
4279
  // src/demo/itemMapping.ts
4743
4280
  import { WeaponId, PowerupId as PowerupId2, KeyId } from "@quake2ts/game";
4744
4281
  import { AmmoType as AmmoType3 } from "@quake2ts/game";
@@ -5117,15 +4654,15 @@ var ClientNetworkHandler = class {
5117
4654
  }
5118
4655
  const origin = { ...ps.origin };
5119
4656
  const velocity = { ...ps.velocity };
5120
- const viewangles = { ...ps.viewangles };
4657
+ const viewAngles = { ...ps.viewangles };
5121
4658
  const deltaAngles = { ...ps.delta_angles };
5122
4659
  return {
5123
4660
  origin,
5124
4661
  velocity,
5125
- viewangles,
4662
+ viewAngles,
5126
4663
  pmFlags: ps.pm_flags,
5127
4664
  pmType: ps.pm_type,
5128
- waterlevel: WaterLevel.None,
4665
+ waterLevel: WaterLevel.None,
5129
4666
  gravity: ps.gravity,
5130
4667
  deltaAngles,
5131
4668
  client: {
@@ -5145,7 +4682,17 @@ var ClientNetworkHandler = class {
5145
4682
  // No blend from demo frame currently (need to parse svc_playerinfo more fully)
5146
4683
  damageAlpha: 0,
5147
4684
  // Need to extract from renderfx/flash
5148
- damageIndicators: []
4685
+ damageIndicators: [],
4686
+ // Stubs
4687
+ stats: [...ps.stats],
4688
+ kick_angles: ZERO_VEC3,
4689
+ gunoffset: ZERO_VEC3,
4690
+ gunangles: ZERO_VEC3,
4691
+ gunindex: 0,
4692
+ onGround: false,
4693
+ // Infer from pmFlags?
4694
+ mins: { x: -16, y: -16, z: -24 },
4695
+ maxs: { x: 16, y: 16, z: 32 }
5149
4696
  };
5150
4697
  }
5151
4698
  getPredictionState(timeMs) {
@@ -6066,7 +5613,7 @@ function normalizeCommand(command) {
6066
5613
  }
6067
5614
 
6068
5615
  // src/input/controller.ts
6069
- var MSEC_MAX2 = 250;
5616
+ var MSEC_MAX = 250;
6070
5617
  var KeyButton = class {
6071
5618
  constructor() {
6072
5619
  this.activeCodes = /* @__PURE__ */ new Set();
@@ -6296,7 +5843,7 @@ var InputController = class {
6296
5843
  sidemove = this.clampMove(sidemove, this.sideSpeed);
6297
5844
  upmove = this.clampMove(upmove, this.upSpeed);
6298
5845
  let buttons = this.collectButtonBits(frameMsec, now);
6299
- const msec = Math.min(Math.max(Math.round(frameMsec), 1), MSEC_MAX2);
5846
+ const msec = Math.min(Math.max(Math.round(frameMsec), 1), MSEC_MAX);
6300
5847
  if (this.anyPressed || buttons !== PlayerButton.None) {
6301
5848
  buttons |= PlayerButton.Any;
6302
5849
  }
@@ -6488,11 +6035,17 @@ var InputCommandBuffer = class {
6488
6035
  };
6489
6036
 
6490
6037
  // src/index.ts
6491
- function lerp3(a, b, t) {
6038
+ import {
6039
+ ClientPrediction as ClientPrediction2,
6040
+ interpolatePredictionState as interpolatePredictionState3
6041
+ } from "@quake2ts/cgame";
6042
+ import { ViewEffects as ViewEffects2 } from "@quake2ts/cgame";
6043
+ var ZERO_VEC32 = { x: 0, y: 0, z: 0 };
6044
+ function lerp2(a, b, t) {
6492
6045
  return a + (b - a) * t;
6493
6046
  }
6494
- function lerpAngle2(a, b, t) {
6495
- return lerp3(a, b, t);
6047
+ function lerpAngle(a, b, t) {
6048
+ return lerp2(a, b, t);
6496
6049
  }
6497
6050
  function buildRenderableEntities(latestEntities, previousEntities, alpha, configStrings, imports) {
6498
6051
  const renderables = [];
@@ -6506,14 +6059,14 @@ function buildRenderableEntities(latestEntities, previousEntities, alpha, config
6506
6059
  const model = assets.getMd2Model(modelName) || assets.getMd3Model(modelName);
6507
6060
  if (!model) continue;
6508
6061
  const origin = {
6509
- x: lerp3(prev.origin.x, ent.origin.x, alpha),
6510
- y: lerp3(prev.origin.y, ent.origin.y, alpha),
6511
- z: lerp3(prev.origin.z, ent.origin.z, alpha)
6062
+ x: lerp2(prev.origin.x, ent.origin.x, alpha),
6063
+ y: lerp2(prev.origin.y, ent.origin.y, alpha),
6064
+ z: lerp2(prev.origin.z, ent.origin.z, alpha)
6512
6065
  };
6513
6066
  const angles = {
6514
- x: lerpAngle2(prev.angles.x, ent.angles.x, alpha),
6515
- y: lerpAngle2(prev.angles.y, ent.angles.y, alpha),
6516
- z: lerpAngle2(prev.angles.z, ent.angles.z, alpha)
6067
+ x: lerpAngle(prev.angles.x, ent.angles.x, alpha),
6068
+ y: lerpAngle(prev.angles.y, ent.angles.y, alpha),
6069
+ z: lerpAngle(prev.angles.z, ent.angles.z, alpha)
6517
6070
  };
6518
6071
  const frame = ent.frame;
6519
6072
  const prevFrame = prev.frame;
@@ -6752,7 +6305,7 @@ function createClient(imports) {
6752
6305
  latestFrame = sample.latest;
6753
6306
  }
6754
6307
  if (sample.previous?.state && sample.latest?.state) {
6755
- lastRendered = interpolatePredictionState(sample.previous.state, sample.latest.state, sample.alpha);
6308
+ lastRendered = interpolatePredictionState2(sample.previous.state, sample.latest.state, sample.alpha);
6756
6309
  if (sample.latest.state.packetEntities && sample.previous.state.packetEntities) {
6757
6310
  renderEntities = buildRenderableEntities(
6758
6311
  sample.latest.state.packetEntities,
@@ -6770,13 +6323,13 @@ function createClient(imports) {
6770
6323
  lastView = view.sample(lastRendered, frameTimeMs);
6771
6324
  const command = {};
6772
6325
  if (lastRendered) {
6773
- const { origin, viewangles } = lastRendered;
6326
+ const { origin, viewAngles } = lastRendered;
6774
6327
  camera = new Camera();
6775
6328
  camera.position = vec3_exports.fromValues(origin.x, origin.y, origin.z);
6776
6329
  const viewOffset = lastView?.offset ?? { x: 0, y: 0, z: 0 };
6777
6330
  vec3_exports.add(camera.position, camera.position, [viewOffset.x, viewOffset.y, viewOffset.z]);
6778
6331
  const effectAngles = lastView?.angles ?? { x: 0, y: 0, z: 0 };
6779
- camera.angles = vec3_exports.fromValues(viewangles.x + effectAngles.x, viewangles.y + effectAngles.y, viewangles.z + effectAngles.z);
6332
+ camera.angles = vec3_exports.fromValues(viewAngles.x + effectAngles.x, viewAngles.y + effectAngles.y, viewAngles.z + effectAngles.z);
6780
6333
  camera.fov = isZooming ? 40 : fovValue;
6781
6334
  camera.aspect = 4 / 3;
6782
6335
  if (imports.engine.renderer) {
@@ -6831,9 +6384,9 @@ function createClient(imports) {
6831
6384
  const playerState = {
6832
6385
  origin: lastRendered.origin,
6833
6386
  velocity: lastRendered.velocity,
6834
- viewAngles: lastRendered.viewangles,
6387
+ viewAngles: lastRendered.viewAngles,
6835
6388
  onGround: hasPmFlag(lastRendered.pmFlags, PmFlag.OnGround),
6836
- waterLevel: lastRendered.waterlevel,
6389
+ waterLevel: lastRendered.waterLevel,
6837
6390
  mins: { x: -16, y: -16, z: -24 },
6838
6391
  maxs: { x: 16, y: 16, z: 32 },
6839
6392
  damageAlpha: lastRendered.damageAlpha ?? 0,
@@ -6842,7 +6395,13 @@ function createClient(imports) {
6842
6395
  pickupIcon: lastRendered.pickupIcon,
6843
6396
  centerPrint: messageSystem["centerPrintMsg"]?.text,
6844
6397
  // Hack to get text for legacy state? No, Draw_Hud uses messageSystem directly now.
6845
- notify: void 0
6398
+ notify: void 0,
6399
+ // Stubs for new fields
6400
+ stats: [],
6401
+ kick_angles: ZERO_VEC32,
6402
+ gunoffset: ZERO_VEC32,
6403
+ gunangles: ZERO_VEC32,
6404
+ gunindex: 0
6846
6405
  };
6847
6406
  const playbackState = demoPlayback.getState();
6848
6407
  const hudTimeMs = playbackState === PlaybackState.Playing || playbackState === PlaybackState.Paused ? (demoHandler.latestFrame?.serverFrame || 0) * 100 : timeMs;
@@ -6850,9 +6409,9 @@ function createClient(imports) {
6850
6409
  imports.engine.renderer,
6851
6410
  playerState,
6852
6411
  lastRendered.client,
6853
- lastRendered.health,
6854
- lastRendered.armor,
6855
- lastRendered.ammo,
6412
+ lastRendered.health ?? 0,
6413
+ lastRendered.armor ?? 0,
6414
+ lastRendered.ammo ?? 0,
6856
6415
  stats,
6857
6416
  messageSystem,
6858
6417
  subtitleSystem,
@@ -6942,16 +6501,15 @@ function createClient(imports) {
6942
6501
  }
6943
6502
  export {
6944
6503
  ClientConfigStrings,
6945
- ClientPrediction,
6504
+ ClientPrediction2 as ClientPrediction,
6946
6505
  InputAction,
6947
6506
  InputBindings,
6948
6507
  InputCommandBuffer,
6949
6508
  InputController,
6950
- ViewEffects,
6509
+ ViewEffects2 as ViewEffects,
6951
6510
  createClient,
6952
6511
  createDefaultBindings,
6953
- defaultPredictionState,
6954
- interpolatePredictionState,
6512
+ interpolatePredictionState3 as interpolatePredictionState,
6955
6513
  normalizeCommand,
6956
6514
  normalizeInputCode
6957
6515
  };