{
float f;
- // dropped packet, or start of demo
- if (cl.mtime[1] < cl.mtime[0] - 0.1)
- cl.mtime[1] = cl.mtime[0] - 0.1;
-
- cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]);
+ if (cl_nettimesyncmode.integer == 3)
+ cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]);
// LordHavoc: lerp in listen games as the server is being capped below the client (usually)
- if (cl.mtime[0] <= cl.mtime[1] || cl_nolerp.integer || cls.timedemo || (cl.islocalgame && !sv_fixedframeratesingleplayer.integer))
+ if (cl.mtime[0] <= cl.mtime[1])
{
cl.time = cl.mtime[0];
return 1;
{
const matrix4x4_t *matrix;
matrix4x4_t blendmatrix, tempmatrix, matrix2;
- //matrix4x4_t dlightmatrix;
int j, k, l;
float origin[3], angles[3], delta[3], lerp, d;
entity_t *t;
// creates light and trails from an entity
void CL_UpdateNetworkEntityTrail(entity_t *e)
{
- //matrix4x4_t dlightmatrix;
effectnameindex_t trailtype;
vec3_t origin;
cvar_t cl_sound_r_exp3 = {0, "cl_sound_r_exp3", "weapons/r_exp3.wav", "sound to play during TE_EXPLOSION and related effects (empty cvar disables sound)"};
cvar_t cl_serverextension_download = {0, "cl_serverextension_download", "0", "indicates whether the server supports the download command"};
cvar_t cl_joinbeforedownloadsfinish = {0, "cl_joinbeforedownloadsfinish", "1", "if non-zero the game will begin after the map is loaded before other downloads finish"};
+cvar_t cl_nettimesyncmode = {0, "cl_nettimesyncmode", "2", "selects method of time synchronization in client with regard to server packets, values are: 0 = no sync, 1 = exact sync (reset timing each packet), 2 = loose sync (reset timing only if it is out of bounds), 3 = tight sync and bounding"};
static qboolean QW_CL_CheckOrDownloadFile(const char *filename);
static void QW_CL_RequestNextDownload(void);
return true;
}
+static void CL_NetworkTimeReceived(double newtime)
+{
+ if (cl_nolerp.integer || cls.timedemo || (cl.islocalgame && !sv_fixedframeratesingleplayer.integer))
+ cl.mtime[1] = cl.mtime[0] = newtime;
+ else
+ {
+ cl.mtime[1] = max(cl.mtime[0], newtime - 0.1);
+ cl.mtime[0] = newtime;
+ }
+ if (cl_nettimesyncmode.integer == 3)
+ cl.time = cl.mtime[1];
+ if (cl_nettimesyncmode.integer == 2)
+ {
+ if (cl.time < cl.mtime[1] || cl.time > cl.mtime[0])
+ cl.time = cl.mtime[1];
+ }
+ else if (cl_nettimesyncmode.integer == 1)
+ cl.time = cl.mtime[1];
+ // this packet probably contains a player entity update, so we will need
+ // to update the prediction
+ cl.movement_needupdate = true;
+ // this may get updated later in parsing by svc_clientdata
+ cl.onground = false;
+ // if true the cl.viewangles are interpolated from cl.mviewangles[]
+ // during this frame
+ // (makes spectating players much smoother and prevents mouse movement from turning)
+ cl.fixangle[1] = cl.fixangle[0];
+ cl.fixangle[0] = false;
+ if (!cls.demoplayback)
+ VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
+}
+
#define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s\n", msg_readcount-1, x);
//[515]: csqc
if (cls.protocol == PROTOCOL_QUAKEWORLD)
{
- cl.mtime[1] = cl.mtime[0];
- cl.mtime[0] = realtime; // qw has no clock
- cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]);
- cl.onground = false; // since there's no clientdata parsing, clear the onground flag here
- // if true the cl.viewangles are interpolated from cl.mviewangles[]
- // during this frame
- // (makes spectating players much smoother and prevents mouse movement from turning)
- cl.fixangle[1] = cl.fixangle[0];
- cl.fixangle[0] = false;
- if (!cls.demoplayback)
- VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
+ CL_NetworkTimeReceived(realtime); // qw has no clock
// slightly kill qw player entities each frame
for (i = 1;i < cl.maxclients;i++)
break;
case svc_time:
- cl.mtime[1] = cl.mtime[0];
- cl.mtime[0] = MSG_ReadFloat ();
- cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]);
- cl.movement_needupdate = true;
- // if true the cl.viewangles are interpolated from cl.mviewangles[]
- // during this frame
- // (makes spectating players much smoother and prevents mouse movement from turning)
- cl.fixangle[1] = cl.fixangle[0];
- cl.fixangle[0] = false;
- if (!cls.demoplayback)
- VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
+ CL_NetworkTimeReceived(MSG_ReadFloat());
break;
case svc_clientdata:
// server extension cvars set by commands issued from the server during connect
Cvar_RegisterVariable(&cl_serverextension_download);
+ Cvar_RegisterVariable(&cl_nettimesyncmode);
+
Cmd_AddCommand("nextul", QW_CL_NextUpload, "sends next fragment of current upload buffer (screenshot for example)");
Cmd_AddCommand("stopul", QW_CL_StopUpload, "aborts current upload (screenshot for example)");
Cmd_AddCommand("skins", QW_CL_Skins_f, "downloads missing qw skins from server");
// clients view of time, time should be between mtime[0] and mtime[1] to
// generate a lerp point for other data, oldtime is the previous frame's
// value of time, frametime is the difference between time and oldtime
+ // note: cl.time may be beyond cl.mtime[0] if packet loss is occuring, it
+ // is only forcefully limited when a packet is received
double time, oldtime;
// how long it has been since the previous client frame in real time
// (not game time, for that use cl.time - cl.oldtime)
extern cvar_t cl_shownet;
extern cvar_t cl_nolerp;
+extern cvar_t cl_nettimesyncmode;
extern cvar_t cl_pitchdriftspeed;
extern cvar_t lookspring;