]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
reverted dresk's DP_SV_ALLOWTOUCHWITHOWNER patch as it adds unnecessary
[xonotic/darkplaces.git] / sv_phys.c
index 67578e7b6b7b6a6e5c9aacc7a2f9f05218e937fd..2948f2c9210e640aed513ed7c21525ac59be9fd8 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -459,9 +459,12 @@ SV_TestEntityPosition
 returns true if the entity is in solid currently
 ============
 */
-static int SV_TestEntityPosition (prvm_edict_t *ent)
+static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
 {
-       trace_t trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, SUPERCONTENTS_SOLID);
+       vec3_t org;
+       trace_t trace;
+       VectorAdd(ent->fields.server->origin, offset, org);
+       trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, SUPERCONTENTS_SOLID);
        if (trace.startsupercontents & SUPERCONTENTS_SOLID)
                return true;
        else
@@ -471,10 +474,11 @@ static int SV_TestEntityPosition (prvm_edict_t *ent)
                        // q1bsp/hlbsp use hulls and if the entity does not exactly match
                        // a hull size it is incorrectly tested, so this code tries to
                        // 'fix' it slightly...
+                       // FIXME: this breaks entities larger than the hull size
                        int i;
                        vec3_t v, m1, m2, s;
-                       VectorAdd(ent->fields.server->origin, ent->fields.server->mins, m1);
-                       VectorAdd(ent->fields.server->origin, ent->fields.server->maxs, m2);
+                       VectorAdd(org, ent->fields.server->mins, m1);
+                       VectorAdd(org, ent->fields.server->maxs, m2);
                        VectorSubtract(m2, m1, s);
 #define EPSILON (1.0f / 32.0f)
                        if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;}
@@ -489,8 +493,11 @@ static int SV_TestEntityPosition (prvm_edict_t *ent)
                                        return true;
                        }
                }
-               return false;
        }
+       // if the trace found a better position for the entity, move it there
+       if (VectorDistance2(trace.endpos, ent->fields.server->origin) >= 0.0001)
+               VectorCopy(trace.endpos, ent->fields.server->origin);
+       return false;
 }
 
 /*
@@ -515,7 +522,7 @@ void SV_CheckAllEnts (void)
                 || check->fields.server->movetype == MOVETYPE_NOCLIP)
                        continue;
 
-               if (SV_TestEntityPosition (check))
+               if (SV_TestEntityPosition (check, vec3_origin))
                        Con_Print("entity in invalid position\n");
        }
 }
@@ -1184,9 +1191,10 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                pusher->fields.server->solid = savesolid; // was SOLID_BSP
                //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
 
-               // this check is for items riding platforms that are passing under (or
-               // through) walls intended to knock the items off
-               if (trace.fraction < 1 && check->fields.server->movetype != MOVETYPE_WALK)
+               // this trace.fraction < 1 check causes items to fall off of pushers
+               // if they pass under or through a wall
+               // the groundentity check causes items to fall off of ledges
+               if (check->fields.server->movetype != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(check->fields.server->groundentity) != pusher))
                        check->fields.server->flags = (int)check->fields.server->flags & ~FL_ONGROUND;
 
                // if it is still inside the pusher, block
@@ -1303,6 +1311,36 @@ CLIENT MOVEMENT
 ===============================================================================
 */
 
+static float unstickoffsets[] =
+{
+       -1,  0,  0,
+        1,  0,  0,
+        0, -1,  0,
+        0,  1,  0,
+       -1, -1,  0,
+        1, -1,  0,
+       -1,  1,  0,
+        1,  1,  0,
+        0,  0,  -1,
+        0,  0,  1,
+        0,  0,  2,
+        0,  0,  3,
+        0,  0,  4,
+        0,  0,  5,
+        0,  0,  6,
+        0,  0,  7,
+        0,  0,  8,
+        0,  0,  9,
+        0,  0,  10,
+        0,  0,  11,
+        0,  0,  12,
+        0,  0,  13,
+        0,  0,  14,
+        0,  0,  15,
+        0,  0,  16,
+        0,  0,  17,
+};
+
 /*
 =============
 SV_CheckStuck
@@ -1313,71 +1351,54 @@ clipping hull.
 */
 void SV_CheckStuck (prvm_edict_t *ent)
 {
-       int i, j, z;
-       vec3_t org;
+       int i;
+       vec3_t offset;
 
-       if (!SV_TestEntityPosition(ent))
+       if (!SV_TestEntityPosition(ent, vec3_origin))
        {
                VectorCopy (ent->fields.server->origin, ent->fields.server->oldorigin);
                return;
        }
 
-       VectorCopy (ent->fields.server->origin, org);
-
-       for (z=-1 ; z< 18 ; z++)
-               for (i=-1 ; i <= 1 ; i++)
-                       for (j=-1 ; j <= 1 ; j++)
-                       {
-                               ent->fields.server->origin[0] = org[0] + i;
-                               ent->fields.server->origin[1] = org[1] + j;
-                               ent->fields.server->origin[2] = org[2] + z;
-                               if (!SV_TestEntityPosition(ent))
-                               {
-                                       Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), (float)i, (float)j, (float)z);
-                                       SV_LinkEdict (ent, true);
-                                       return;
-                               }
-                       }
+       for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
+       {
+               if (!SV_TestEntityPosition(ent, unstickoffsets + i))
+               {
+                       Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2]);
+                       SV_LinkEdict (ent, true);
+                       return;
+               }
+       }
 
-       VectorCopy (ent->fields.server->oldorigin, ent->fields.server->origin);
-       if (!SV_TestEntityPosition(ent))
+       VectorSubtract(ent->fields.server->oldorigin, ent->fields.server->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(ent->fields.server->classname));
                SV_LinkEdict (ent, true);
                return;
        }
 
-       VectorCopy (org, ent->fields.server->origin);
        Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname));
 }
 
 static void SV_UnstickEntity (prvm_edict_t *ent)
 {
-       int i, j, z;
-       vec3_t org;
+       int i;
 
        // if not stuck in a bmodel, just return
-       if (!SV_TestEntityPosition(ent))
+       if (!SV_TestEntityPosition(ent, vec3_origin))
                return;
 
-       VectorCopy (ent->fields.server->origin, org);
-
-       for (z=-1 ; z< 18 ; z += 6)
-               for (i=-1 ; i <= 1 ; i++)
-                       for (j=-1 ; j <= 1 ; j++)
-                       {
-                               ent->fields.server->origin[0] = org[0] + i;
-                               ent->fields.server->origin[1] = org[1] + j;
-                               ent->fields.server->origin[2] = org[2] + z;
-                               if (!SV_TestEntityPosition(ent))
-                               {
-                                       Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), (float)i, (float)j, (float)z);
-                                       SV_LinkEdict (ent, true);
-                                       return;
-                               }
-                       }
+       for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
+       {
+               if (!SV_TestEntityPosition(ent, unstickoffsets + i))
+               {
+                       Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2]);
+                       SV_LinkEdict (ent, true);
+                       return;
+               }
+       }
 
-       VectorCopy (org, ent->fields.server->origin);
        if (developer.integer >= 100)
                Con_Printf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname));
 }
@@ -2003,10 +2024,56 @@ void SV_Physics_ClientMove(void)
 {
        prvm_edict_t *ent;
        ent = host_client->edict;
+
+       // call player physics, this needs the proper frametime
+       prog->globals.server->frametime = sv.frametime;
+       SV_ClientThink();
+
+       // call standard client pre-think, with frametime = 0
+       prog->globals.server->time = sv.time;
+       prog->globals.server->frametime = 0;
+       prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
+       PRVM_ExecuteProgram (prog->globals.server->PlayerPreThink, "QC function PlayerPreThink is missing");
+       prog->globals.server->frametime = sv.frametime;
+
+       // make sure the velocity is sane (not a NaN)
+       SV_CheckVelocity(ent);
+       // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
+       // player_run/player_stand1 does not horribly malfunction if the
+       // velocity becomes a number that is both == 0 and != 0
+       // (sounds to me like NaN but to be absolutely safe...)
+       if (DotProduct(ent->fields.server->velocity, ent->fields.server->velocity) < 0.0001)
+               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;
+       prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
+       PRVM_ExecuteProgram (prog->globals.server->PlayerPostThink, "QC function PlayerPostThink is missing");
+       prog->globals.server->frametime = sv.frametime;
+
+       if(ent->fields.server->fixangle)
+       {
+               // angle fixing was requested by physics code...
+               // so store the current angles for later use
+               memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
+               host_client->fixangle_angles_set = TRUE;
+
+               // and clear fixangle for the next frame
+               ent->fields.server->fixangle = 0;
+       }
 }
 
 void SV_Physics_ClientEntity(prvm_edict_t *ent)
@@ -2018,7 +2085,9 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
                return;
        }
 
-       SV_ClientThink();
+       // don't run physics here if running asynchronously
+       if (host_client->clmovement_skipphysicsframes <= 0)
+               SV_ClientThink();
 
        // make sure the velocity is sane (not a NaN)
        SV_CheckVelocity(ent);
@@ -2028,6 +2097,7 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
        // (sounds to me like NaN but to be absolutely safe...)
        if (DotProduct(ent->fields.server->velocity, ent->fields.server->velocity) < 0.0001)
                VectorClear(ent->fields.server->velocity);
+
        // call standard client pre-think
        prog->globals.server->time = sv.time;
        prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
@@ -2061,7 +2131,12 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
                SV_RunThink (ent);
                // don't run physics here if running asynchronously
                if (host_client->clmovement_skipphysicsframes <= 0)
-                       SV_Physics_ClientMove();
+               {
+                       if (!SV_CheckWater (ent) && ! ((int)ent->fields.server->flags & FL_WATERJUMP) )
+                               SV_AddGravity (ent);
+                       SV_CheckStuck (ent);
+                       SV_WalkMove (ent);
+               }
                break;
        case MOVETYPE_TOSS:
        case MOVETYPE_BOUNCE:
@@ -2088,11 +2163,11 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
 
        SV_CheckVelocity (ent);
 
-       // call standard player post-think
        SV_LinkEdict (ent, true);
 
        SV_CheckVelocity (ent);
 
+       // call standard player post-think
        prog->globals.server->time = sv.time;
        prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
        PRVM_ExecuteProgram (prog->globals.server->PlayerPostThink, "QC function PlayerPostThink is missing");