]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
reworked prediction code to work better when riding lifts
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 8 Mar 2007 23:36:23 +0000 (23:36 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 8 Mar 2007 23:36:23 +0000 (23:36 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6943 d7cf8633-e32d-0410-b094-e92efae38249

cl_input.c
cl_main.c
client.h
clvm_cmds.c

index 47971a540a47a156f38fe389265c56ba6e0e3c9d..6ac140d6aa6b82808b66c8debaf41c9f6c39706c 100644 (file)
@@ -560,8 +560,6 @@ void CL_UpdatePrydonCursor(void)
        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;
@@ -594,7 +592,8 @@ void CL_ClientMovement_InputQW(void)
                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)
@@ -642,7 +641,8 @@ 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
@@ -1174,39 +1174,54 @@ void CL_ClientMovement_Replay(void)
        }
        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)
index 735660494ddec0951117c1b11584fed542005600..3a16b69f206ae60461d039f010c49148ea6bfe1a 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -760,7 +760,7 @@ extern void V_CalcViewBlend(void);
 extern void V_CalcRefdef(void);
 
 // note this is a recursive function, recursionlimit should be 32 or so on the initial call
-void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit)
+void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolate)
 {
        const matrix4x4_t *matrix;
        matrix4x4_t blendmatrix, tempmatrix, matrix2;
@@ -830,7 +830,7 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit)
                if (!t->state_current.active)
                        return;
                // update the parent first
-               CL_UpdateNetworkEntity(t, recursionlimit - 1);
+               CL_UpdateNetworkEntity(t, recursionlimit - 1, interpolate);
                // make relative to the entity
                matrix = &t->render.matrix;
                // some properties of the tag entity carry over
@@ -878,7 +878,7 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit)
                VectorLerp(cl.movement_oldorigin, lerp, cl.movement_origin, origin);
                VectorSet(angles, 0, cl.viewangles[1], 0);
        }
-       else if (e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1)
+       else if (interpolate && e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1)
        {
                // interpolate the origin and angles
                lerp = max(0, lerp);
@@ -1064,23 +1064,64 @@ void CL_UpdateNetworkEntityTrail(entity_t *e)
 
 /*
 ===============
-CL_UpdateEntities
+CL_UpdateViewEntities
 ===============
 */
-void CL_UpdateEntities(void)
+void CL_UpdateViewEntities(void)
+{
+       int i;
+       // update any RENDER_VIEWMODEL entities to use the new view matrix
+       for (i = 1;i < cl.num_entities;i++)
+       {
+               if (cl.entities_active[i])
+               {
+                       entity_t *ent = cl.entities + i;
+                       if ((ent->render.flags & RENDER_VIEWMODEL) || ent->state_current.tagentity)
+                               CL_UpdateNetworkEntity(ent, 32, true);
+               }
+       }
+       // and of course the engine viewmodel needs updating as well
+       CL_UpdateNetworkEntity(&cl.viewent, 32, true);
+}
+
+/*
+===============
+CL_UpdateNetworkCollisionEntities
+===============
+*/
+void CL_UpdateNetworkCollisionEntities(void)
 {
        entity_t *ent;
        int i;
 
-       // process network entities
-       // first link the player
-       CL_UpdateNetworkEntity(cl.entities + cl.viewentity, 32);
+       // start on the entity after the world
+       cl.num_brushmodel_entities = 0;
+       for (i = 1;i < cl.num_entities;i++)
+       {
+               if (cl.entities_active[i])
+               {
+                       ent = cl.entities + i;
+                       if (ent->state_current.active && ent->render.model && ent->render.model->name[0] == '*' && ent->render.model->TraceBox)
+                       {
+                               // do not interpolate the bmodels for this
+                               CL_UpdateNetworkEntity(ent, 32, false);
+                               cl.brushmodel_entities[cl.num_brushmodel_entities++] = ent->state_current.number;
+                       }
+               }
+       }
+}
 
-       // set up the view
-       V_CalcRefdef();
+/*
+===============
+CL_UpdateNetworkEntities
+===============
+*/
+void CL_UpdateNetworkEntities(void)
+{
+       entity_t *ent;
+       int i;
 
        // start on the entity after the world
-       // skip the player entity because it was already processed
        for (i = 1;i < cl.num_entities;i++)
        {
                if (cl.entities_active[i])
@@ -1088,18 +1129,20 @@ void CL_UpdateEntities(void)
                        ent = cl.entities + i;
                        if (ent->state_current.active)
                        {
-                               CL_UpdateNetworkEntity(ent, 32);
+                               CL_UpdateNetworkEntity(ent, 32, true);
                                // view models should never create light/trails
                                if (!(ent->render.flags & RENDER_VIEWMODEL))
                                        CL_UpdateNetworkEntityTrail(ent);
-                               if (ent->render.model && ent->render.model->name[0] == '*' && ent->render.model->TraceBox)
-                                       cl.brushmodel_entities[cl.num_brushmodel_entities++] = ent->state_current.number;
                        }
                        else
                                cl.entities_active[i] = false;
                }
        }
+}
 
+void CL_UpdateViewModel(void)
+{
+       entity_t *ent;
        ent = &cl.viewent;
        ent->state_previous = ent->state_current;
        ent->state_current = defaultstate;
@@ -1128,7 +1171,7 @@ void CL_UpdateEntities(void)
                ent->render.frame1time = ent->render.frame2time = cl.time;
                ent->render.framelerp = 1;
        }
-       CL_UpdateNetworkEntity(ent, 32);
+       CL_UpdateNetworkEntity(ent, 32, true);
 }
 
 // note this is a recursive function, but it can never get in a runaway loop (because of the delayedlink flags)
@@ -1640,8 +1683,28 @@ int CL_ReadFromServer(void)
                V_DriftPitch();
                V_FadeViewFlashs();
 
-               // now update all the network entities and the view matrix
-               CL_UpdateEntities();
+               if (cl.movement_predicted)
+               {
+                       // if prediction is enabled we have to update all the collidable
+                       // network entities before the prediction code can be run
+                       CL_UpdateNetworkCollisionEntities();
+               }
+
+               // now update the player prediction
+               CL_ClientMovement_Replay();
+
+               // update the player entity (which may be predicted)
+               CL_UpdateNetworkEntity(cl.entities + cl.viewentity, 32, true);
+
+               // now update the view (which depends on that player entity)
+               V_CalcRefdef();
+
+               // now update all the network entities and create particle trails
+               // (some entities may depend on the view)
+               CL_UpdateNetworkEntities();
+
+               // update the engine-based viewmodel
+               CL_UpdateViewModel();
 
                CL_RelinkLightFlashes();
                CSQC_RelinkAllEntities(ENTMASK_ENGINE | ENTMASK_ENGINEVIEWMODELS);
index 31018173fa80ff352f1057c04876638af56c5c91..5e9df7ded5479e1bda54879fb580813c3e3fca5b 100644 (file)
--- a/client.h
+++ b/client.h
@@ -717,6 +717,8 @@ typedef struct client_state_s
        // these fields are only updated by CL_ClientMovement (called by CL_SendMove after parsing each network packet)
        // set by CL_ClientMovement_Replay functions
        qboolean movement_predicted;
+       // if true the CL_ClientMovement_Replay function will update origin, etc
+       qboolean movement_replay;
        // this is set true by svc_time parsing and causes a new movement to be
        // queued for prediction purposes
        qboolean movement_needupdate;
@@ -1032,7 +1034,7 @@ void CL_Disconnect (void);
 void CL_Disconnect_f (void);
 
 void CL_UpdateRenderEntity(entity_render_t *ent);
-void CL_UpdateEntities(void);
+void CL_UpdateViewEntities(void);
 
 //
 // cl_input
@@ -1058,6 +1060,7 @@ void CL_ParseTEnt (void);
 void CL_NewBeam (int ent, vec3_t start, vec3_t end, model_t *m, int lightning);
 void CL_RelinkBeams (void);
 void CL_Beam_CalculatePositions (const beam_t *b, vec3_t start, vec3_t end);
+void CL_ClientMovement_Replay(void);
 
 void CL_ClearTempEntities (void);
 entity_t *CL_NewTempEntity (void);
index f11af64d559bede5462c545c8bb2b2273567c6cd..03f3fe911b626e10c727dcaecd21697307a501b1 100644 (file)
@@ -758,25 +758,13 @@ static void VM_CL_R_SetView (void)
        PRVM_G_FLOAT(OFS_RETURN) = 1;
 }
 
-extern void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit);
 //#304 void() renderscene (EXT_CSQC)
 static void VM_CL_R_RenderScene (void)
 {
-       int i;
        VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
        // we need to update any RENDER_VIEWMODEL entities at this point because
        // csqc supplies its own view matrix
-       for (i = 1;i < cl.num_entities;i++)
-       {
-               if (cl.entities_active[i])
-               {
-                       entity_t *ent = cl.entities + i;
-                       if ((ent->render.flags & RENDER_VIEWMODEL) || ent->state_current.tagentity)
-                               CL_UpdateNetworkEntity(ent, 32);
-               }
-       }
-       // and of course the engine viewmodel needs updating as well
-       CL_UpdateNetworkEntity(&cl.viewent, 32);
+       CL_UpdateViewEntities();
        // now draw stuff!
        R_RenderView();
 }