]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
cl_parse: Implement 7th mode for cl_nettimesyncboundmode; jitter compensated dynamic...
authorcloudwalk <cloudwalk@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 11 Apr 2021 16:46:15 +0000 (16:46 +0000)
committercloudwalk <cloudwalk@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 11 Apr 2021 16:46:15 +0000 (16:46 +0000)
This mode aims to prevent network jitter or other disturbances from
significantly affecting the client's timekeeping,
by correcting gradually (max 10% of mean error per tic).

The rolling harmonic mean gives large time error outliers low significance.

Correction rate is dynamic, determined by mean error size.
Time is correct within a few tics of connect/map start despite no hard bounding.

The adjustment approach is from mode 5 and can achieve
microsecond accuracy if client frametime is a multiple of server frametime.

Prevents 0ms move frame times with uncapped fps.

Smoothest mode esp for vsynced clients on servers with aggressive inputtimeout.

Authored by bones_was_here
https://gitlab.com/xonotic/darkplaces/-/merge_requests/112

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@13115 d7cf8633-e32d-0410-b094-e92efae38249

cl_parse.c
client.h

index cabcefe143d4dc40c1fd1c3d6a432aefe8cfb6b5..98c415ab1cfff6b225a6b61abc119d5def358ffd 100644 (file)
@@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "menu.h"
 #endif
 #include "cl_video.h"
+#include "float.h"
 
 const char *svc_strings[128] =
 {
@@ -186,7 +187,7 @@ cvar_t cl_sound_r_exp3 = {CF_CLIENT, "cl_sound_r_exp3", "weapons/r_exp3.wav", "s
 cvar_t cl_serverextension_download = {CF_CLIENT, "cl_serverextension_download", "0", "indicates whether the server supports the download command"};
 cvar_t cl_joinbeforedownloadsfinish = {CF_CLIENT | CF_ARCHIVE, "cl_joinbeforedownloadsfinish", "1", "if non-zero the game will begin after the map is loaded before other downloads finish"};
 cvar_t cl_nettimesyncfactor = {CF_CLIENT | CF_ARCHIVE, "cl_nettimesyncfactor", "0", "rate at which client time adapts to match server time, 1 = instantly, 0.125 = slowly, 0 = not at all (only applied in bound modes 0, 1, 2, 3)"};
-cvar_t cl_nettimesyncboundmode = {CF_CLIENT | CF_ARCHIVE, "cl_nettimesyncboundmode", "6", "method of restricting client time to valid values, 0 = no correction, 1 = tight bounding (jerky with packet loss), 2 = loose bounding (corrects it if out of bounds), 3 = leniant bounding (ignores temporary errors due to varying framerate), 4 = slow adjustment method from Quake3, 5 = slightly nicer version of Quake3 method, 6 = tight bounding + mode 5"};
+cvar_t cl_nettimesyncboundmode = {CF_CLIENT | CF_ARCHIVE, "cl_nettimesyncboundmode", "6", "method of restricting client time to valid values, 0 = no correction, 1 = tight bounding (jerky with packet loss), 2 = loose bounding (corrects it if out of bounds), 3 = leniant bounding (ignores temporary errors due to varying framerate), 4 = slow adjustment method from Quake3, 5 = slightly nicer version of Quake3 method, 6 = tight bounding + mode 5, 7 = jitter compensated dynamic adjustment rate"};
 cvar_t cl_nettimesyncboundtolerance = {CF_CLIENT | CF_ARCHIVE, "cl_nettimesyncboundtolerance", "0.25", "how much error is tolerated by bounding check, as a fraction of frametime, 0.25 = up to 25% margin of error tolerated, 1 = use only new time, 0 = use only old time (same effect as setting cl_nettimesyncfactor to 1) (only affects bound modes 2 and 3)"};
 cvar_t cl_iplog_name = {CF_CLIENT | CF_ARCHIVE, "cl_iplog_name", "darkplaces_iplog.txt", "name of iplog file containing player addresses for iplog_list command and automatic ip logging when parsing status command"};
 
@@ -3351,6 +3352,28 @@ static void CL_NetworkTimeReceived(double newtime)
                        cl.time = bound(cl.time - 0.002 * cl.movevars_timescale, cl.mtime[1], cl.time + 0.001 * cl.movevars_timescale);
                        break;
 
+               case 7:
+                       /* bones_was_here: this aims to prevent disturbances in the force from affecting cl.time
+                        * the rolling harmonic mean gives large time error outliers low significance
+                        * correction rate is dynamic and gradual (max 10% of mean error per tic)
+                        * time is correct within a few server frames of connect/map start
+                        * can achieve microsecond accuracy when cl.realframetime is a multiple of sv.frametime
+                        * prevents 0ms move frame times with uncapped fps
+                        * smoothest mode esp. for vsynced clients on servers with aggressive inputtimeout
+                        */
+                       {
+                               unsigned char i;
+                               float error;
+                               // in event of packet loss, cl.mtime[1] could be very old, so avoid if possible
+                               double target = cl.movevars_ticrate ? cl.mtime[0] - cl.movevars_ticrate : cl.mtime[1];
+                               cl.ts_error_stor[cl.ts_error_num] = 1.0f / max(fabs(cl.time - target), FLT_MIN);
+                               cl.ts_error_num = (cl.ts_error_num + 1) % NUM_TS_ERRORS;
+                               for (i = 0, error = 0.0f; i < NUM_TS_ERRORS; i++)
+                                       error += cl.ts_error_stor[i];
+                               error = 0.1f / (error / NUM_TS_ERRORS);
+                               cl.time = bound(cl.time - error, target, cl.time + error);
+                       }
+                       break;
                }
        }
        // this packet probably contains a player entity update, so we will need
index 67262d7c2990c2f3073497525b28b351e41dcf17..5335bb0a4cd958eb4fab19bdfd75fb85fcebb987 100644 (file)
--- a/client.h
+++ b/client.h
@@ -870,7 +870,12 @@ typedef struct client_state_s
        // how long it has been since the previous client frame in real time
        // (not game time, for that use cl.time - cl.oldtime)
        double realframetime;
-       
+
+       // used by cl_nettimesyncboundmode 7
+#define NUM_TS_ERRORS 32 // max 256
+       unsigned char ts_error_num;
+       float ts_error_stor[NUM_TS_ERRORS];
+
        // fade var for fading while dead
        float deathfade;