]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
sys: work around incomplete POSIX support in MacOS
[xonotic/darkplaces.git] / sv_phys.c
index 77c3bacfc71058bb7a66e957ded188571f8be71a..a61bc2f893a999c25f0d8ce30d55b884ee9965c3 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -1041,12 +1041,12 @@ void SV_CheckVelocity (prvm_edict_t *ent)
 //
        for (i=0 ; i<3 ; i++)
        {
-               if (PRVM_IS_NAN(PRVM_serveredictvector(ent, velocity)[i]))
+               if (isnan(PRVM_serveredictvector(ent, velocity)[i]))
                {
                        Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
                        PRVM_serveredictvector(ent, velocity)[i] = 0;
                }
-               if (PRVM_IS_NAN(PRVM_serveredictvector(ent, origin)[i]))
+               if (isnan(PRVM_serveredictvector(ent, origin)[i]))
                {
                        Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
                        PRVM_serveredictvector(ent, origin)[i] = 0;
@@ -1112,15 +1112,18 @@ static qbool SV_RunThink (prvm_edict_t *ent)
 SV_Impact
 
 Two entities have touched, so run their touch functions
+Returns true if the push did not result in the entity being teleported by QC code.
 ==================
 */
-static void SV_Impact (prvm_edict_t *e1, trace_t *trace)
+static qbool SV_Impact (prvm_edict_t *e1, trace_t *trace)
 {
        prvm_prog_t *prog = SVVM_prog;
        int restorevm_tempstringsbuf_cursize;
        int old_self, old_other;
        prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
 
+       e1->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
+
        old_self = PRVM_serverglobaledict(self);
        old_other = PRVM_serverglobaledict(other);
        restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
@@ -1154,6 +1157,22 @@ static void SV_Impact (prvm_edict_t *e1, trace_t *trace)
        PRVM_serverglobaledict(self) = old_self;
        PRVM_serverglobaledict(other) = old_other;
        prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+
+       if(e1->priv.required->mark == PRVM_EDICT_MARK_SETORIGIN_CAUGHT)
+       {
+               e1->priv.required->mark = 0;
+               return false;
+       }
+       else if(e1->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
+       {
+               e1->priv.required->mark = 0;
+               return true;
+       }
+       else
+       {
+               Con_Printf(CON_ERROR "The edict mark had been overwritten! Please debug this.\n");
+               return true;
+       }
 }
 
 
@@ -1194,13 +1213,12 @@ If stepnormal is not NULL, the plane normal of any vertical wall hit will be sto
 ============
 */
 static float SV_Gravity (prvm_edict_t *ent);
-static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dolink, qbool checkstuck);
+static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dotouch, qbool checkstuck);
 #define MAX_CLIP_PLANES 5
 static int SV_FlyMove (prvm_edict_t *ent, float time, qbool applygravity, float *stepnormal, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float stepheight)
 {
        prvm_prog_t *prog = SVVM_prog;
-       int blocked, bumpcount;
-       int i, j, numplanes;
+       unsigned int i, j, numplanes, blocked, bumpcount;
        float d, time_left, gravity;
        vec3_t dir, push, planes[MAX_CLIP_PLANES];
        prvm_vec3_t primal_velocity, original_velocity, new_velocity, restore_velocity;
@@ -1238,7 +1256,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qbool applygravity, float
                        break;
 
                VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
-               if(!SV_PushEntity(&trace, ent, push, false, true))
+               if(!SV_PushEntity(&trace, ent, push, sv_gameplayfix_impactbeforeonground.integer, true))
                {
                        // we got teleported by a touch function
                        // let's abort the move
@@ -1248,7 +1266,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qbool applygravity, float
 
                // this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity
                // abort move if we're stuck in the world (and didn't make it out)
-               if (trace.worldstartsolid && trace.allsolid && trace.startdepth < 0)
+               if (trace.worldstartsolid && trace.allsolid)
                {
                        VectorCopy(restore_velocity, PRVM_serveredictvector(ent, velocity));
                        return 3;
@@ -1333,12 +1351,19 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qbool applygravity, float
                                VectorCopy(trace.plane.normal, stepnormal);
                }
 
-               // Unlike some other movetypes Quake's SV_FlyMove calls SV_Impact only after setting ONGROUND which id1 fiends rely on.
-               // If we stepped up (sv_gameplayfix_stepmultipletimes) this will impact the steptrace2 plane instead of the original.
-               if (PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace.ent)
-                       SV_Impact(ent, &trace);
-               if (ent->free)
-                       return blocked; // removed by the impact function
+               if (!sv_gameplayfix_impactbeforeonground.integer)
+               {
+                       // Unlike some other movetypes Quake's SV_FlyMove calls SV_Impact only after setting ONGROUND which id1 fiends rely on.
+                       // If we stepped up (sv_gameplayfix_stepmultipletimes) this will impact the steptrace2 plane instead of the original.
+                       if (PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace.ent)
+                               if (!SV_Impact(ent, &trace))
+                               {
+                                       blocked |= 8;
+                                       break;
+                               }
+                       if (ent->free)
+                               return blocked; // removed by the impact function
+               }
 
                if (trace.fraction >= 0.001)
                {
@@ -1560,7 +1585,7 @@ The trace struct is filled with the trace that has been done.
 Returns true if the push did not result in the entity being teleported by QC code.
 ============
 */
-static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dolink, qbool checkstuck)
+static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dotouch, qbool checkstuck)
 {
        prvm_prog_t *prog = SVVM_prog;
        int solid;
@@ -1588,41 +1613,21 @@ static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboo
                type = MOVE_NORMAL;
 
        *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
-       // abort move if we're stuck in the world (and didn't make it out)
-       if (trace->worldstartsolid && trace->allsolid && trace->startdepth < 0 && checkstuck)
+       if (trace->allsolid && checkstuck)
        {
-               // checking startdepth eliminates many false positives on Q1BSP with mod_q1bsp_polygoncollisions 0
-               // but it's still not guaranteed that we're stuck in a bmodel at this point
-               if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
+               if (SV_UnstickEntity(ent))
                {
-                       switch (PHYS_NudgeOutOfSolid(prog, ent))
-                       {
-                               case 0:
-                                       Con_Printf(CON_WARN "NudgeOutOfSolid couldn't fix stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
-                                       return true; // definitely stuck in a bmodel
-                               case 1:
-                                       Con_DPrintf("NudgeOutOfSolid fixed stuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), PRVM_serveredictvector(ent, origin)[0] - start[0], PRVM_serveredictvector(ent, origin)[1] - start[1], PRVM_serveredictvector(ent, origin)[2] - start[2]);
-                                       VectorCopy(PRVM_serveredictvector(ent, origin), start);
-                                       VectorAdd(start, push, end);
-                                       *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
-
-                               // definitely not stuck in a bmodel, move may proceed
-                       }
-               }
-               else if (sv_gameplayfix_unstickentities.integer && SV_UnstickEntity(ent))
-               {
-                       // bones_was_here: pretty sure we can deprecate sv_gameplayfix_unstickentities, sv_gameplayfix_nudgeoutofsolid is much nicer
                        VectorCopy(PRVM_serveredictvector(ent, origin), start);
                        VectorAdd(start, push, end);
                        *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
                }
-               else
-                       return true; // assuming stuck, bones_was_here TODO: always use PHYS_NudgeOutOfSolid (remove sv_gameplayfix_nudgeoutofsolid)?
+               // abort move if we're stuck in the world (and didn't make it out)
+               else if (trace->worldstartsolid)
+                       return true;
        }
 
        VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
-
-       ent->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
+       VectorCopy(trace->endpos, PRVM_serveredictvector(ent, oldorigin)); // for SV_UnstickEntity()
 
        SV_LinkEdict(ent);
 
@@ -1634,29 +1639,15 @@ static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboo
        }
 #endif
 
-       if (dolink)
+       if (dotouch)
        {
                SV_LinkEdict_TouchAreaGrid(ent);
 
                if((PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace->ent && (!((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) || PRVM_serveredictedict(ent, groundentity) != PRVM_EDICT_TO_PROG(trace->ent))))
-                       SV_Impact (ent, trace);
+                       return SV_Impact (ent, trace);
        }
 
-       if(ent->priv.required->mark == PRVM_EDICT_MARK_SETORIGIN_CAUGHT)
-       {
-               ent->priv.required->mark = 0;
-               return false;
-       }
-       else if(ent->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
-       {
-               ent->priv.required->mark = 0;
-               return true;
-       }
-       else
-       {
-               Con_Printf("The edict mark had been overwritten! Please debug this.\n");
-               return true;
-       }
+       return true;
 }
 
 
@@ -2035,9 +2026,10 @@ static float unstickoffsets[] =
 
 typedef enum unstickresult_e
 {
+       // matching the DP_QC_NUDGEOUTOFSOLID return values
        UNSTICK_STUCK = 0,
-       UNSTICK_GOOD = 1,
-       UNSTICK_UNSTUCK = 2
+       UNSTICK_GOOD = -1, ///< didn't need to be unstuck
+       UNSTICK_UNSTUCK = 1
 }
 unstickresult_t;
 
@@ -2055,8 +2047,6 @@ static unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t o
                if (!SV_TestEntityPosition(ent, unstickoffsets + i))
                {
                        VectorCopy(unstickoffsets + i, offset);
-                       SV_LinkEdict(ent);
-                       //SV_LinkEdict_TouchAreaGrid(ent);
                        return UNSTICK_UNSTUCK;
                }
        }
@@ -2069,44 +2059,15 @@ static unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t o
                VectorClear(offset);
                offset[2] = -i;
                if (!SV_TestEntityPosition(ent, offset))
-               {
-                       SV_LinkEdict(ent);
-                       //SV_LinkEdict_TouchAreaGrid(ent);
                        return UNSTICK_UNSTUCK;
-               }
                offset[2] = i;
                if (!SV_TestEntityPosition(ent, offset))
-               {
-                       SV_LinkEdict(ent);
-                       //SV_LinkEdict_TouchAreaGrid(ent);
                        return UNSTICK_UNSTUCK;
-               }
        }
 
        return UNSTICK_STUCK;
 }
 
-qbool SV_UnstickEntity (prvm_edict_t *ent)
-{
-       prvm_prog_t *prog = SVVM_prog;
-       vec3_t offset;
-       switch(SV_UnstickEntityReturnOffset(ent, offset))
-       {
-               case UNSTICK_GOOD:
-                       return true;
-               case UNSTICK_UNSTUCK:
-                       Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
-                       return true;
-               case UNSTICK_STUCK:
-                       if (developer_extra.integer)
-                               Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
-                       return false;
-               default:
-                       Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
-                       return false;
-       }
-}
-
 /*
 =============
 SV_CheckStuck
@@ -2115,32 +2076,54 @@ This is a big hack to try and fix the rare case of getting stuck in the world
 clipping hull.
 =============
 */
-static void SV_CheckStuck (prvm_edict_t *ent)
+qbool SV_UnstickEntity (prvm_edict_t *ent)
 {
        prvm_prog_t *prog = SVVM_prog;
        vec3_t offset;
 
+       if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0
+       && sv.worldmodel->TraceBox == Mod_CollisionBIH_TraceBox) // Mod_Q1BSP_TraceBox doesn't support startdepth
+       {
+               VectorCopy(PRVM_serveredictvector(ent, origin), offset);
+               switch (PHYS_NudgeOutOfSolid(prog, ent))
+               {
+                       case UNSTICK_GOOD:
+                               return true;
+                       case UNSTICK_UNSTUCK:
+                               VectorSubtract(PRVM_serveredictvector(ent, origin), offset, offset);
+                               Con_DPrintf("NudgeOutOfSolid fixed stuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
+                               return true;
+                       case UNSTICK_STUCK:
+                               Con_DPrintf(CON_WARN "NudgeOutOfSolid couldn't fix stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
+                               return false;
+                       default:
+                               Con_Printf("NudgeOutOfSolid returned a value outside its enum.\n");
+                               return false;
+               }
+       }
+
+       if (!(PRVM_NUM_FOR_EDICT(ent) <= svs.maxclients ? sv_gameplayfix_unstickplayers : sv_gameplayfix_unstickentities).integer)
+               return false;
+
        switch(SV_UnstickEntityReturnOffset(ent, offset))
        {
                case UNSTICK_GOOD:
-                       VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
-                       break;
+                       return true;
                case UNSTICK_UNSTUCK:
-                       Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
-                       break;
+                       Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
+                       return true;
                case UNSTICK_STUCK:
                        VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
                        if (!SV_TestEntityPosition(ent, offset))
                        {
-                               Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
-                               SV_LinkEdict(ent);
-                               //SV_LinkEdict_TouchAreaGrid(ent);
+                               Con_DPrintf("Unstuck entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
+                               return true;
                        }
-                       else
-                               Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
-                       break;
+                       Con_DPrintf(CON_WARN "Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
+                       return false;
                default:
                        Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
+                       return false;
        }
 }
 
@@ -2311,9 +2294,6 @@ static void SV_WalkMove (prvm_edict_t *ent)
        if (sv.frametime <= 0)
                return;
 
-       if (sv_gameplayfix_unstickplayers.integer)
-               SV_CheckStuck (ent);
-
        applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
 
        SV_CheckVelocity(ent);