]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
fix entity reuse of the very last entity before the entity reuse timer expires.
[xonotic/darkplaces.git] / sv_phys.c
index bcd461dc41bcd0511d657d23bd7073c78c2c2f60..2bcea7ff1f9dc41ab1dac6a6cd4e3100883c115e 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -225,9 +225,9 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
                        Matrix4x4_CreateTranslate(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2]);
                Matrix4x4_Invert_Simple(&imatrix, &matrix);
                if ((int)touch->fields.server->flags & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->fields.server->frame, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
+                       Collision_ClipToGenericEntity(&trace, model, (int) touch->fields.server->frame, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
                else
-                       Collision_ClipToGenericEntity(&trace, model, touch->fields.server->frame, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
+                       Collision_ClipToGenericEntity(&trace, model, (int) touch->fields.server->frame, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
 
                Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.server->solid == SOLID_BSP);
        }
@@ -519,7 +519,20 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
        }
        // if the trace found a better position for the entity, move it there
        if (VectorDistance2(trace.endpos, ent->fields.server->origin) >= 0.0001)
+       {
+#if 0
+               // please switch back to this code when trace.endpos sometimes being in solid bug is fixed
                VectorCopy(trace.endpos, ent->fields.server->origin);
+#else
+               // verify if the endpos is REALLY outside solid
+               VectorCopy(trace.endpos, org);
+               trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, org, MOVE_NOMONSTERS, ent, SUPERCONTENTS_SOLID);
+               if(trace.startsolid)
+                       Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
+               else
+                       VectorCopy(org, ent->fields.server->origin);
+#endif
+       }
        return false;
 }
 
@@ -756,17 +769,32 @@ Returns the clipflags if the velocity was modified (hit something solid)
 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
 ============
 */
+static float SV_Gravity (prvm_edict_t *ent);
 // LordHavoc: increased from 5 to 32
 #define MAX_CLIP_PLANES 32
-int SV_FlyMove (prvm_edict_t *ent, float time, float *stepnormal, int hitsupercontentsmask)
+static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask)
 {
        int blocked, bumpcount;
        int i, j, impact, numplanes;
-       float d, time_left;
+       float d, time_left, gravity;
        vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
        trace_t trace;
        if (time <= 0)
                return 0;
+       gravity = 0;
+       if (applygravity)
+       {
+               if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
+               {
+                       gravity = SV_Gravity(ent) * 0.5f;
+                       ent->fields.server->velocity[2] -= gravity;
+               }
+               else
+               {
+                       applygravity = false;
+                       ent->fields.server->velocity[2] -= SV_Gravity(ent);
+               }
+       }
        blocked = 0;
        VectorCopy(ent->fields.server->velocity, original_velocity);
        VectorCopy(ent->fields.server->velocity, primal_velocity);
@@ -980,16 +1008,18 @@ int SV_FlyMove (prvm_edict_t *ent, float time, float *stepnormal, int hitsuperco
        // LordHavoc: this came from QW and allows you to get out of water more easily
        if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP))
                VectorCopy(primal_velocity, ent->fields.server->velocity);
+       if (applygravity && !((int)ent->fields.server->flags & FL_ONGROUND))
+               ent->fields.server->velocity[2] -= gravity;
        return blocked;
 }
 
 /*
 ============
-SV_AddGravity
+SV_Gravity
 
 ============
 */
-void SV_AddGravity (prvm_edict_t *ent)
+static float SV_Gravity (prvm_edict_t *ent)
 {
        float ent_gravity;
        prvm_eval_t *val;
@@ -999,7 +1029,7 @@ void SV_AddGravity (prvm_edict_t *ent)
                ent_gravity = val->_float;
        else
                ent_gravity = 1.0;
-       ent->fields.server->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
+       return ent_gravity * sv_gravity.value * sv.frametime;
 }
 
 
@@ -1215,7 +1245,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                // final position, move it
                if (!((int)check->fields.server->flags & FL_ONGROUND) || PRVM_PROG_TO_EDICT(check->fields.server->groundentity) != pusher)
                {
-                       Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
+                       Collision_ClipToGenericEntity(&trace, pushermodel, (int) pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
                        //trace = SV_Move(check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, MOVE_NOMONSTERS, check, checkcontents);
                        if (!trace.startsolid)
                        {
@@ -1258,7 +1288,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                        check->fields.server->flags = (int)check->fields.server->flags & ~FL_ONGROUND;
 
                // if it is still inside the pusher, block
-               Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
+               Collision_ClipToGenericEntity(&trace, pushermodel, (int) pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
                if (trace.startsolid)
                {
                        // try moving the contacted entity a tiny bit further to account for precision errors
@@ -1269,7 +1299,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                        VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles);
                        SV_PushEntity (check, move2, true);
                        pusher->fields.server->solid = savesolid;
-                       Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
+                       Collision_ClipToGenericEntity(&trace, pushermodel, (int) pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
                        if (trace.startsolid)
                        {
                                // try moving the contacted entity a tiny bit less to account for precision errors
@@ -1279,7 +1309,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                                VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles);
                                SV_PushEntity (check, move2, true);
                                pusher->fields.server->solid = savesolid;
-                               Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
+                               Collision_ClipToGenericEntity(&trace, pushermodel, (int) pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
                                if (trace.startsolid)
                                {
                                        // still inside pusher, so it's really blocked
@@ -1628,12 +1658,17 @@ void SV_WalkMove (prvm_edict_t *ent)
        int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity, hitsupercontentsmask;
        vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
        trace_t downtrace;
+       qboolean applygravity;
 
        // if frametime is 0 (due to client sending the same timestamp twice),
        // don't move
        if (sv.frametime <= 0)
                return;
 
+       SV_CheckStuck (ent);
+
+       applygravity = !SV_CheckWater (ent) && ent->fields.server->movetype == MOVETYPE_WALK && ! ((int)ent->fields.server->flags & FL_WATERJUMP);
+
        hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
 
        SV_CheckVelocity(ent);
@@ -1644,13 +1679,14 @@ void SV_WalkMove (prvm_edict_t *ent)
        VectorCopy (ent->fields.server->origin, start_origin);
        VectorCopy (ent->fields.server->velocity, start_velocity);
 
-       clip = SV_FlyMove (ent, sv.frametime, NULL, hitsupercontentsmask);
+       clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask);
 
        // if the move did not hit the ground at any point, we're not on ground
        if (!(clip & 1))
                ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
 
        SV_CheckVelocity(ent);
+       SV_LinkEdict (ent, true);
 
        VectorCopy(ent->fields.server->origin, originalmove_origin);
        VectorCopy(ent->fields.server->velocity, originalmove_velocity);
@@ -1696,10 +1732,11 @@ void SV_WalkMove (prvm_edict_t *ent)
 
                // move forward
                ent->fields.server->velocity[2] = 0;
-               clip = SV_FlyMove (ent, sv.frametime, stepnormal, hitsupercontentsmask);
+               clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask);
                ent->fields.server->velocity[2] += start_velocity[2];
 
                SV_CheckVelocity(ent);
+               SV_LinkEdict (ent, true);
 
                // check for stuckness, possibly due to the limited precision of floats
                // in the clipping hulls
@@ -1763,6 +1800,7 @@ void SV_WalkMove (prvm_edict_t *ent)
        }
 
        SV_CheckVelocity(ent);
+       SV_LinkEdict (ent, true);
 }
 
 //============================================================================
@@ -1871,6 +1909,8 @@ void SV_Physics_Toss (prvm_edict_t *ent)
 {
        trace_t trace;
        vec3_t move;
+       vec_t movetime;
+       int bump;
 
 // if onground, return without moving
        if ((int)ent->fields.server->flags & FL_ONGROUND)
@@ -1900,27 +1940,30 @@ void SV_Physics_Toss (prvm_edict_t *ent)
 
 // add gravity
        if (ent->fields.server->movetype == MOVETYPE_TOSS || ent->fields.server->movetype == MOVETYPE_BOUNCE)
-               SV_AddGravity (ent);
+               ent->fields.server->velocity[2] -= SV_Gravity(ent);
 
 // move angles
        VectorMA (ent->fields.server->angles, sv.frametime, ent->fields.server->avelocity, ent->fields.server->angles);
 
-// move origin
-       VectorScale (ent->fields.server->velocity, sv.frametime, move);
-       trace = SV_PushEntity (ent, move, true);
-       if (ent->priv.server->free)
-               return;
-       if (trace.bmodelstartsolid)
+       movetime = sv.frametime;
+       for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
        {
-               // try to unstick the entity
-               SV_UnstickEntity(ent);
-               trace = SV_PushEntity (ent, move, false);
+       // move origin
+               VectorScale (ent->fields.server->velocity, movetime, move);
+               trace = SV_PushEntity (ent, move, true);
                if (ent->priv.server->free)
                        return;
-       }
-
-       if (trace.fraction < 1)
-       {
+               if (trace.bmodelstartsolid)
+               {
+                       // try to unstick the entity
+                       SV_UnstickEntity(ent);
+                       trace = SV_PushEntity (ent, move, false);
+                       if (ent->priv.server->free)
+                               return;
+               }
+               if (trace.fraction == 1)
+                       break;
+               movetime *= 1 - min(1, trace.fraction);
                if (ent->fields.server->movetype == MOVETYPE_BOUNCEMISSILE)
                {
                        ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 2.0);
@@ -1928,13 +1971,19 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                }
                else if (ent->fields.server->movetype == MOVETYPE_BOUNCE)
                {
-                       float d;
+                       float d, ent_gravity;
+                       prvm_eval_t *val;
                        ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1.5);
                        // LordHavoc: fixed grenades not bouncing when fired down a slope
+                       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity);
+                       if (val!=0 && val->_float)
+                               ent_gravity = val->_float;
+                       else
+                               ent_gravity = 1.0;
                        if (sv_gameplayfix_grenadebouncedownslopes.integer)
                        {
                                d = DotProduct(trace.plane.normal, ent->fields.server->velocity);
-                               if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
+                               if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * (60.0 / 800.0) * ent_gravity)
                                {
                                        ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
                                        ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
@@ -1946,7 +1995,7 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                        }
                        else
                        {
-                               if (trace.plane.normal[2] > 0.7 && ent->fields.server->velocity[2] < 60)
+                               if (trace.plane.normal[2] > 0.7 && ent->fields.server->velocity[2] < sv_gravity.value * (60.0 / 800.0) * ent_gravity)
                                {
                                        ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
                                        ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
@@ -1972,6 +2021,8 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                        else
                                ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
                }
+               if (!sv_gameplayfix_slidemoveprojectiles.integer || (ent->fields.server->movetype != MOVETYPE_BOUNCE && ent->fields.server->movetype == MOVETYPE_BOUNCEMISSILE) || ((int)ent->fields.server->flags & FL_ONGROUND))
+                       break;
        }
 
 // check for in water
@@ -2017,9 +2068,8 @@ void SV_Physics_Step (prvm_edict_t *ent)
                        if ((ent->fields.server->velocity[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer) || ent->fields.server->groundentity)
                        {
                                ent->fields.server->flags -= FL_ONGROUND;
-                               SV_AddGravity(ent);
                                SV_CheckVelocity(ent);
-                               SV_FlyMove(ent, sv.frametime, NULL, SV_GenericHitSuperContentsMask(ent));
+                               SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent));
                                SV_LinkEdict(ent, true);
                                ent->priv.server->waterposition_forceupdate = true;
                        }
@@ -2029,9 +2079,8 @@ void SV_Physics_Step (prvm_edict_t *ent)
                        // freefall if not onground
                        int hitsound = ent->fields.server->velocity[2] < sv_gravity.value * -0.1;
 
-                       SV_AddGravity(ent);
                        SV_CheckVelocity(ent);
-                       SV_FlyMove(ent, sv.frametime, NULL, SV_GenericHitSuperContentsMask(ent));
+                       SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent));
                        SV_LinkEdict(ent, true);
 
                        // just hit ground
@@ -2077,10 +2126,16 @@ void SV_Physics_Step (prvm_edict_t *ent)
 
 static void SV_Physics_Entity (prvm_edict_t *ent)
 {
-       // don't run a move on newly spawned projectiles as it messes up movement
-       // interpolation and rocket trails
+       // don't run think/move on newly spawned projectiles as it messes up
+       // movement interpolation and rocket trails, and is inconsistent with
+       // respect to entities spawned in the same frame
+       // (if an ent spawns a higher numbered ent, it moves in the same frame,
+       //  but if it spawns a lower numbered ent, it doesn't - this never moves
+       //  ents in the first frame regardless)
        qboolean runmove = ent->priv.server->move;
        ent->priv.server->move = true;
+       if (!runmove && sv_gameplayfix_delayprojectiles.integer)
+               return;
        switch ((int) ent->fields.server->movetype)
        {
        case MOVETYPE_PUSH:
@@ -2109,13 +2164,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
                break;
        case MOVETYPE_WALK:
                if (SV_RunThink (ent))
-               {
-                       if (!SV_CheckWater (ent) && ! ((int)ent->fields.server->flags & FL_WATERJUMP) )
-                               SV_AddGravity (ent);
-                       SV_CheckStuck (ent);
                        SV_WalkMove (ent);
-                       SV_LinkEdict (ent, true);
-               }
                break;
        case MOVETYPE_TOSS:
        case MOVETYPE_BOUNCE:
@@ -2123,7 +2172,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
        case MOVETYPE_FLYMISSILE:
        case MOVETYPE_FLY:
                // regular thinking
-               if (SV_RunThink (ent) && (runmove || !sv_gameplayfix_delayprojectiles.integer))
+               if (SV_RunThink (ent))
                        SV_Physics_Toss (ent);
                break;
        default:
@@ -2158,17 +2207,8 @@ void SV_Physics_ClientMove(void)
                VectorClear(ent->fields.server->velocity);
 
        // perform MOVETYPE_WALK behavior
-       if (!SV_CheckWater (ent) && ! ((int)ent->fields.server->flags & FL_WATERJUMP) )
-               SV_AddGravity (ent);
-       SV_CheckStuck (ent);
        SV_WalkMove (ent);
 
-       SV_CheckVelocity (ent);
-
-       SV_LinkEdict (ent, true);
-
-       SV_CheckVelocity (ent);
-
        // call standard player post-think, with frametime = 0
        prog->globals.server->time = sv.time;
        prog->globals.server->frametime = 0;
@@ -2198,7 +2238,7 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
        }
 
        // don't run physics here if running asynchronously
-       if (host_client->clmovement_skipphysicsframes <= 0)
+       if (host_client->clmovement_inputtimeout <= 0)
        {
                SV_ClientThink();
                //host_client->cmd.time = max(host_client->cmd.time, sv.time);
@@ -2245,13 +2285,8 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
        case MOVETYPE_WALK:
                SV_RunThink (ent);
                // don't run physics here if running asynchronously
-               if (host_client->clmovement_skipphysicsframes <= 0)
-               {
-                       if (!SV_CheckWater (ent) && ! ((int)ent->fields.server->flags & FL_WATERJUMP) )
-                               SV_AddGravity (ent);
-                       SV_CheckStuck (ent);
+               if (host_client->clmovement_inputtimeout <= 0)
                        SV_WalkMove (ent);
-               }
                break;
        case MOVETYPE_TOSS:
        case MOVETYPE_BOUNCE:
@@ -2263,7 +2298,6 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
                break;
        case MOVETYPE_FLY:
                SV_RunThink (ent);
-               SV_CheckWater (ent);
                SV_WalkMove (ent);
                break;
        default:
@@ -2273,8 +2307,10 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
 
        // decrement the countdown variable used to decide when to go back to
        // synchronous physics
-       if (host_client->clmovement_skipphysicsframes > 0)
-               host_client->clmovement_skipphysicsframes--;
+       if (host_client->clmovement_inputtimeout > sv.frametime)
+               host_client->clmovement_inputtimeout -= sv.frametime;
+       else
+               host_client->clmovement_inputtimeout = 0;
 
        SV_CheckVelocity (ent);
 
@@ -2351,7 +2387,7 @@ void SV_Physics (void)
        }
 
        // decrement prog->num_edicts if the highest number entities died
-       for (;PRVM_EDICT_NUM(prog->num_edicts - 1)->priv.server->free;prog->num_edicts--);
+       for (;PRVM_ED_CanAlloc(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
 
        if (!sv_freezenonclients.integer)
                sv.time += sv.frametime;