further tweaks to prediction
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 28 May 2006 19:38:41 +0000 (19:38 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 28 May 2006 19:38:41 +0000 (19:38 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6401 d7cf8633-e32d-0410-b094-e92efae38249

cl_input.c
cl_main.c
client.h
server.h
sv_main.c
sv_phys.c
sv_user.c

index 7c6fec1..83f688a 100644 (file)
@@ -527,7 +527,7 @@ void CL_ClientMovement_InputQW(qw_usercmd_t *cmd)
                if (cl.movement_queue[i].sequence > cls.netcon->qw.incoming_sequence)
                        cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
                else if (i == 0)
-                       cl.movement_replay_canjump = !cl.movement_queue[i].jump;
+                       cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken
        }
        // add to input queue if there is room
        if (cl.movement_numqueue < (int)(sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0])))
@@ -551,7 +551,7 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
 {
        int i;
        int n;
-       double lasttime = cl.movement_numqueue >= 0 ? cl.movement_queue[cl.movement_numqueue - 1].time : 0;
+       double lasttime = (cls.protocol == PROTOCOL_DARKPLACES6 || cls.protocol == PROTOCOL_DARKPLACES7) ? cl.mtime[1] : (cl.movement_numqueue >= 0 ? cl.movement_queue[cl.movement_numqueue - 1].time : 0);
        // remove stale queue items
        n = cl.movement_numqueue;
        cl.movement_numqueue = 0;
@@ -562,7 +562,7 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
                        if (cl.movement_queue[i].sequence > cl.servermovesequence)
                                cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
                        else if (i == 0)
-                               cl.movement_replay_canjump = !cl.movement_queue[i].jump;
+                               cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken
                }
        }
        else
@@ -572,7 +572,7 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
                        if (cl.movement_queue[i].time >= cl.mtime[0] - cl_movement_latency.value / 1000.0 && cl.movement_queue[i].time <= cl.mtime[0])
                                cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
                        else if (i == 0)
-                               cl.movement_replay_canjump = !cl.movement_queue[i].jump;
+                               cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken
                }
        }
        // add to input queue if there is room
@@ -1072,7 +1072,8 @@ void CL_ClientMovement_Replay(void)
                s.movevars_stepheight = cl_movement_stepheight.value;
        }
 
-       if (cl.movement)
+       cl.movement_predicted = (cl_movement.integer && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission) && ((cls.protocol != PROTOCOL_DARKPLACES6 && cls.protocol != PROTOCOL_DARKPLACES7) || cl.servermovesequence);
+       if (cl.movement_predicted)
        {
                //Con_Printf("%f: ", cl.mtime[0]);
 
@@ -1182,7 +1183,6 @@ void CL_SendMove(void)
        accumtotal++;
 #endif
 
-       cl.movement = cl_movement.integer && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission;
        if (cl_movement.integer && cls.signon == SIGNONS && cls.protocol != PROTOCOL_QUAKEWORLD)
        {
                if (!cl.movement_needupdate)
index d205895..e77ea64 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -913,7 +913,7 @@ void CL_LinkNetworkEntity(entity_t *e)
 
                // movement lerp
                // if it's the player entity, update according to client movement
-               if (e == cl.entities + cl.playerentity && cl.movement)// && !e->csqc)
+               if (e == cl.entities + cl.playerentity && cl.movement_predicted)// && !e->csqc)
                {
                        lerp = (cl.time - cl.movement_time[1]) / (cl.movement_time[0] - cl.movement_time[1]);
                        lerp = bound(0, lerp, 1);
index cfa3f3d..6fa4b32 100644 (file)
--- a/client.h
+++ b/client.h
@@ -657,7 +657,8 @@ typedef struct client_state_s
 
        // client movement simulation
        // these fields are only updated by CL_ClientMovement (called by CL_SendMove after parsing each network packet)
-       qboolean movement;
+       // set by CL_ClientMovement_Replay functions
+       qboolean movement_predicted;
        // this is set true by svc_time parsing and causes a new movement to be
        // queued for prediction purposes
        qboolean movement_needupdate;
@@ -671,7 +672,7 @@ typedef struct client_state_s
        vec3_t movement_velocity;
        // queue of proposed moves
        int movement_numqueue;
-       client_movementqueue_t movement_queue[64];
+       client_movementqueue_t movement_queue[256];
        int movesequence;
        int servermovesequence;
        // whether the replay should allow a jump at the first sequence
index d2e6c30..8371c75 100644 (file)
--- a/server.h
+++ b/server.h
@@ -137,7 +137,9 @@ typedef struct client_s
        float ping;
        
        // this is used by sv_clmovement_minping code
-       double clmovement_disable_minpingtimeout;
+       double clmovement_disabletimeout;
+       // this is used by sv_clmvoement_waitforinput code
+       int clmovement_skipphysicsframes;
 
 // spawn parms are carried from level to level
        float spawn_parms[NUM_SPAWN_PARMS];
index 5b8b7c4..2efbb88 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -57,6 +57,7 @@ cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat f
 extern cvar_t sv_clmovement_enable;
 extern cvar_t sv_clmovement_minping;
 extern cvar_t sv_clmovement_minping_disabletime;
+extern cvar_t sv_clmovement_waitforinput;
 
 server_t sv;
 server_static_t svs;
@@ -91,6 +92,7 @@ void SV_Init (void)
        Cvar_RegisterVariable (&sv_clmovement_enable);
        Cvar_RegisterVariable (&sv_clmovement_minping);
        Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
+       Cvar_RegisterVariable (&sv_clmovement_waitforinput);
        Cvar_RegisterVariable (&sv_idealpitchscale);
        Cvar_RegisterVariable (&sv_aim);
        Cvar_RegisterVariable (&sv_nostep);
index 1f50232..725aa88 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -57,6 +57,9 @@ cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables Qu
 cvar_t sv_sound_watersplash = {0, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"};
 cvar_t sv_sound_land = {0, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"};
 
+// TODO: move this extern to server.h
+extern cvar_t sv_clmovement_waitforinput;
+
 #define        MOVE_EPSILON    0.01
 
 void SV_Physics_Toss (prvm_edict_t *ent);
@@ -1668,7 +1671,9 @@ void SV_Physics (void)
                        if (!host_client->spawned)
                                memset(&host_client->cmd, 0, sizeof(host_client->cmd));
                        // don't run physics here if running asynchronously
-                       else if (!host_client->movesequence)
+                       else if (host_client->clmovement_skipphysicsframes > 0)
+                               host_client->clmovement_skipphysicsframes--;
+                       else
                                SV_Physics_ClientEntity(ent);
                }
        }
index d880a87..480c46a 100644 (file)
--- a/sv_user.c
+++ b/sv_user.c
@@ -31,6 +31,7 @@ cvar_t sv_wateraccelerate = {0, "sv_wateraccelerate", "-1", "rate at which a pla
 cvar_t sv_clmovement_enable = {0, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"};
 cvar_t sv_clmovement_minping = {0, "sv_clmovement_minping", "100", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"};
 cvar_t sv_clmovement_minping_disabletime = {0, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"};
+cvar_t sv_clmovement_waitforinput = {0, "sv_clmovement_waitforinput", "2", "when a client does not send input for this many frames, force them to move anyway (unlike QuakeWorld)"};
 
 static usercmd_t cmd;
 
@@ -533,8 +534,8 @@ qboolean SV_ReadClientMove (void)
 
        // disable clientside movement prediction in some cases
        if (ceil((move->receivetime - move->time) * 1000.0) < sv_clmovement_minping.integer)
-               host_client->clmovement_disable_minpingtimeout = realtime + sv_clmovement_minping_disabletime.value / 1000.0;
-       if (!sv_clmovement_enable.integer || host_client->clmovement_disable_minpingtimeout > realtime)
+               host_client->clmovement_disabletimeout = realtime + sv_clmovement_minping_disabletime.value / 1000.0;
+       if (!sv_clmovement_enable.integer || host_client->clmovement_disabletimeout > realtime)
                move->sequence = 0;
 
        if (!host_client->spawned)
@@ -554,7 +555,7 @@ qboolean SV_ReadClientMove (void)
        {
                // apply the latest accepted move to the entity fields
                host_client->movesequence = move->sequence;
-               if (host_client->movesequence)
+               if (host_client->movesequence && sv_clmovement_waitforinput.integer > 0)
                {
                        double frametime = bound(0, move->time - oldmovetime, 0.1);
                        double oldframetime = prog->globals.server->frametime;
@@ -563,6 +564,7 @@ qboolean SV_ReadClientMove (void)
                        prog->globals.server->frametime = frametime;
                        SV_Physics_ClientEntity(host_client->edict);
                        prog->globals.server->frametime = oldframetime;
+                       host_client->clmovement_skipphysicsframes = sv_clmovement_waitforinput.integer;
                }
        }
        return kickplayer;