From d83a177d3b84b0f286a21d86c1d3e34b13908e52 Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 12 Feb 2007 23:38:01 +0000 Subject: [PATCH] added cl_nettimesyncmode cvar to choose the method of synchronizing cl.time, it defaults to resetting the cl.time to the previous packet's time, but only when it is out of bounds (meaning it increases it if it is falling behind, and snaps it back to the previous packet time if it exceeds this packet's time, which eliminates accumulated error) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6836 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_main.c | 11 +++------- cl_parse.c | 59 ++++++++++++++++++++++++++++++++++-------------------- client.h | 3 +++ 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/cl_main.c b/cl_main.c index 6ed49857..89da9e65 100644 --- a/cl_main.c +++ b/cl_main.c @@ -500,14 +500,11 @@ static float CL_LerpPoint(void) { 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; @@ -769,7 +766,6 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit) { 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; @@ -995,7 +991,6 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit) // creates light and trails from an entity void CL_UpdateNetworkEntityTrail(entity_t *e) { - //matrix4x4_t dlightmatrix; effectnameindex_t trailtype; vec3_t origin; diff --git a/cl_parse.c b/cl_parse.c index e829ca6c..ef9805b2 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -166,6 +166,7 @@ cvar_t cl_sound_ric3 = {0, "cl_sound_ric3", "weapons/ric3.wav", "sound to play w 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); @@ -2495,6 +2496,38 @@ qboolean CL_ExaminePrintString(const char *text) 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 @@ -2545,17 +2578,7 @@ void CL_ParseServerMessage(void) 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++) @@ -2966,17 +2989,7 @@ void CL_ParseServerMessage(void) 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: @@ -3348,6 +3361,8 @@ void CL_Parse_Init(void) // 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"); diff --git a/client.h b/client.h index 711ad4e4..83dcffaa 100644 --- a/client.h +++ b/client.h @@ -750,6 +750,8 @@ typedef struct client_state_s // 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) @@ -957,6 +959,7 @@ extern cvar_t cl_autofire; extern cvar_t cl_shownet; extern cvar_t cl_nolerp; +extern cvar_t cl_nettimesyncmode; extern cvar_t cl_pitchdriftspeed; extern cvar_t lookspring; -- 2.39.2