cvar_t cl_gravity = {0, "cl_gravity", "800", "how much gravity to apply in client physics (should match sv_gravity)"};
cvar_t cl_slowmo = {0, "cl_slowmo", "1", "speed of game time (should match slowmo)"};
-cvar_t in_pitch_min = {0, "in_pitch_min", "-90", "how far downward you can aim (quake used -70"}; // quake used -70
-cvar_t in_pitch_max = {0, "in_pitch_max", "90", "how far upward you can aim (quake used 80"}; // quake used 80
+cvar_t in_pitch_min = {0, "in_pitch_min", "-90", "how far downward you can aim (quake used -70"};
+cvar_t in_pitch_max = {0, "in_pitch_max", "90", "how far upward you can aim (quake used 80"};
cvar_t m_filter = {CVAR_SAVE, "m_filter","0", "smoothes mouse movement, less responsive but smoother aiming"};
cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl.entities[cl.playerentity].render : NULL);
}
-void CL_ClientMovement_Replay(void);
-
void CL_ClientMovement_InputQW(void)
{
int i;
cl.movement_queue[cl.movement_numqueue].crouch = false;
cl.movement_numqueue++;
}
- CL_ClientMovement_Replay();
+
+ cl.movement_replay = true;
}
void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
cl.movement_numqueue++;
}
- CL_ClientMovement_Replay();
+
+ cl.movement_replay = true;
}
typedef enum waterlevel_e
VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + 1);
VectorSet(origin2, s->origin[0], s->origin[1], s->origin[2] - 2);
trace = CL_Move(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
- s->onground = trace.fraction < 1 && trace.plane.normal[2] > 0.7 && s->velocity[2] < cl_gravity.value * s->q.frametime;
+ s->onground = trace.fraction < 1 && trace.plane.normal[2] > 0.7;
// set watertype/waterlevel
VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + s->mins[2] + 1);
}
CL_ClientMovement_UpdateStatus(&s);
- // store replay location
- if (cl.movecmd[0].time > cl.movecmd[1].time)
+ if (cl.movement_replay)
{
- cl.movement_time[1] = cl.movecmd[1].time;
- cl.movement_time[0] = cl.movecmd[0].time;
- cl.movement_time[2] = cl.time;
- VectorCopy(cl.movement_origin, cl.movement_oldorigin);
+ cl.movement_replay = false;
+ // update interpolation timestamps if time has passed
+ if (cl.movecmd[0].time != cl.movecmd[1].time)
+ {
+ cl.movement_time[1] = cl.movecmd[1].time;
+ cl.movement_time[0] = cl.movecmd[0].time;
+ cl.movement_time[2] = cl.time;
+ VectorCopy(cl.movement_origin, cl.movement_oldorigin);
+ //VectorCopy(s.origin, cl.entities[cl.playerentity].state_current.origin);
+ //VectorSet(cl.entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
+ }
+
+ // update the interpolation target position and velocity
VectorCopy(s.origin, cl.movement_origin);
VectorCopy(s.velocity, cl.movement_velocity);
- //VectorCopy(s.origin, cl.entities[cl.playerentity].state_current.origin);
- //VectorSet(cl.entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
-
- // update the onground flag if appropriate
- // when not predicted, cl.onground is only cleared by cl_parse.c, but can
- // be set forcefully here to hide server inconsistencies in the onground
- // flag (such as when stepping up stairs, the onground flag tends to turn
- // off briefly due to precision errors, particularly at high framerates),
- // such inconsistencies can mess up the gun bobbing and stair smoothing,
- // so they must be avoided.
- if (cl.movement_predicted)
- cl.onground = s.onground;
- else if (s.onground)
+ }
+
+ // update the onground flag if appropriate
+ if (cl.movement_predicted)
+ {
+ // when predicted we simply set the flag according to the UpdateStatus
+ cl.onground = s.onground;
+ }
+ else
+ {
+ // when not predicted, cl.onground is cleared by cl_parse.c each time
+ // an update packet is received, but can be forced on here to hide
+ // server inconsistencies in the onground flag
+ // (which mostly occur when stepping up stairs at very high framerates
+ // where after the step up the move continues forward and not
+ // downward so the ground is not detected)
+ //
+ // such onground inconsistencies can cause jittery gun bobbing and
+ // stair smoothing, so we set onground if UpdateStatus says so
+ if (s.onground)
cl.onground = true;
+ }
- // react to onground state changes (for gun bob)
- if (cl.onground)
- {
- if (!cl.oldonground)
- cl.hitgroundtime = cl.movecmd[0].time;
- cl.lastongroundtime = cl.movecmd[0].time;
- }
- cl.oldonground = cl.onground;
+ // react to onground state changes (for gun bob)
+ if (cl.onground)
+ {
+ if (!cl.oldonground)
+ cl.hitgroundtime = cl.movecmd[0].time;
+ cl.lastongroundtime = cl.movecmd[0].time;
}
+ cl.oldonground = cl.onground;
}
void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, usercmd_t *from, usercmd_t *to)
if (!cls.netcon)
return;
+ // don't send too often or else network connections can get clogged by a high renderer framerate
packettime = 1.0 / bound(10, cl_netinputpacketspersecond.value, 100);
- // on quakeworld servers the server replies to client input, so we send
- // packets whenever we want to
- // on non-quakeworld servers the client replies to server updates
+ // quakeworld servers take only frametimes
+ // predicted dp7 servers take current interpolation time
+ // unpredicted servers take an echo of the latest server timestamp
if (cls.protocol == PROTOCOL_QUAKEWORLD)
{
- // don't send too often or else network connections can get clogged by a high renderer framerate
if (realtime < lastsendtime + packettime)
return;
cl.cmd.time = realtime;
}
- else if (cl.movement_predicted || cls.signon < SIGNONS)
+ else if (cl.movement_predicted)
{
- // don't send too often or else network connections can get clogged by a high renderer framerate
if (realtime < lastsendtime + packettime)
return;
- cl.cmd.time = cls.protocol == PROTOCOL_QUAKEWORLD ? realtime : cl.time;
+ cl.cmd.time = cl.time;
}
else
{
- // if not predicted, we should just reply to server packets, and
- // report the real latest packet time rather than our interpolated
- // time
+ // unpredicted movement should be sent immediately whenever a server
+ // packet is received, to minimize ping times
if (!cl.movement_needupdate && realtime < lastsendtime + packettime)
return;
- cl.cmd.time = cls.protocol == PROTOCOL_QUAKEWORLD ? realtime : cl.mtime[0];
+ cl.cmd.time = cl.mtime[0];
}
// don't let it fall behind if CL_SendMove hasn't been called recently
// (such is the case when framerate is too low for instance)
lastsendtime = bound(realtime, lastsendtime + packettime, realtime + packettime);
- // clear the note down that we sent a packet recently
+ // set the flag indicating that we sent a packet recently
cl.movement_needupdate = false;
Cmd_AddCommand ("-lookup", IN_LookupUp, "stop looking upward");
Cmd_AddCommand ("+lookdown", IN_LookdownDown, "look downward");
Cmd_AddCommand ("-lookdown", IN_LookdownUp, "stop looking downward");
- Cmd_AddCommand ("+strafe", IN_StrafeDown, "activate strafing mode (move instead of turn)\n");
+ Cmd_AddCommand ("+strafe", IN_StrafeDown, "activate strafing mode (move instead of turn)");
Cmd_AddCommand ("-strafe", IN_StrafeUp, "deactivate strafing mode");
Cmd_AddCommand ("+moveleft", IN_MoveleftDown, "strafe left");
Cmd_AddCommand ("-moveleft", IN_MoveleftUp, "stop strafing left");