]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
rewrote entity unsticking to be safe from world fallthrough for small entities too...
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 22 Apr 2009 17:26:58 +0000 (17:26 +0000)
committerdivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 22 Apr 2009 17:26:58 +0000 (17:26 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@8937 d7cf8633-e32d-0410-b094-e92efae38249

sv_phys.c

index 2bcea7ff1f9dc41ab1dac6a6cd4e3100883c115e..434d08346b05f8a3b7312652782c3ee1a1dea0d5 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -1403,111 +1403,123 @@ CLIENT MOVEMENT
 
 static float unstickoffsets[] =
 {
+       // poutting -/+z changes first as they are least weird
+        0,  0,  -1,
+        0,  0,  1,
+        // x or y changes
        -1,  0,  0,
         1,  0,  0,
         0, -1,  0,
         0,  1,  0,
+        // x and y changes
        -1, -1,  0,
         1, -1,  0,
        -1,  1,  0,
         1,  1,  0,
-        0,  0,  -1,
-        0,  0,  1,
-        0,  0,  -2,
-        0,  0,  2,
-        0,  0,  -3,
-        0,  0,  3,
-        0,  0,  -4,
-        0,  0,  4,
-        0,  0,  -5,
-        0,  0,  5,
-        0,  0,  -6,
-        0,  0,  6,
-        0,  0,  -7,
-        0,  0,  7,
-        0,  0,  -8,
-        0,  0,  8,
-        0,  0,  -9,
-        0,  0,  9,
-        0,  0,  -10,
-        0,  0,  10,
-        0,  0,  -11,
-        0,  0,  11,
-        0,  0,  -12,
-        0,  0,  12,
-        0,  0,  -13,
-        0,  0,  13,
-        0,  0,  -14,
-        0,  0,  14,
-        0,  0,  -15,
-        0,  0,  15,
-        0,  0,  -16,
-        0,  0,  16,
-        0,  0,  -17,
-        0,  0,  17,
 };
 
-/*
-=============
-SV_CheckStuck
+typedef enum unstickresult_e
+{
+       UNSTICK_STUCK = 0,
+       UNSTICK_GOOD = 1,
+       UNSTICK_UNSTUCK = 2
+}
+unstickresult_t;
 
-This is a big hack to try and fix the rare case of getting stuck in the world
-clipping hull.
-=============
-*/
-void SV_CheckStuck (prvm_edict_t *ent)
+unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
 {
-       int i;
-       vec3_t offset;
+       int i, maxunstick;
 
+       // if not stuck in a bmodel, just return
        if (!SV_TestEntityPosition(ent, vec3_origin))
-       {
-               VectorCopy (ent->fields.server->origin, ent->fields.server->oldorigin);
-               return;
-       }
+               return UNSTICK_GOOD;
 
        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]);
+                       VectorCopy(unstickoffsets + i, offset);
                        SV_LinkEdict (ent, true);
-                       return;
+                       return UNSTICK_UNSTUCK;
                }
        }
 
-       VectorSubtract(ent->fields.server->oldorigin, ent->fields.server->origin, offset);
-       if (!SV_TestEntityPosition(ent, offset))
+       maxunstick = (int) ((ent->fields.server->maxs[2] - ent->fields.server->mins[2]) * 0.36);
+       // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
+
+       for(i = 2; i <= maxunstick; ++i)
        {
-               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;
+               VectorClear(offset);
+               offset[2] = -i;
+               if (!SV_TestEntityPosition(ent, offset))
+               {
+                       SV_LinkEdict (ent, true);
+                       return UNSTICK_UNSTUCK;
+               }
+               offset[2] = i;
+               if (!SV_TestEntityPosition(ent, offset))
+               {
+                       SV_LinkEdict (ent, true);
+                       return UNSTICK_UNSTUCK;
+               }
        }
 
-       Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname));
+       return UNSTICK_STUCK;
 }
 
 qboolean SV_UnstickEntity (prvm_edict_t *ent)
 {
-       int i;
-
-       // if not stuck in a bmodel, just return
-       if (!SV_TestEntityPosition(ent, vec3_origin))
-               return true;
-
-       for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
+       vec3_t offset;
+       switch(SV_UnstickEntityReturnOffset(ent, offset))
        {
-               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);
+               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(ent->fields.server->classname), offset[0], offset[1], offset[2]);
+                       return true;
+               case UNSTICK_STUCK:
+                       if (developer.integer >= 100)
+                               Con_Printf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname));
+                       return false;
+               default:
+                       Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
+                       return false;
        }
+}
 
-       if (developer.integer >= 100)
-               Con_Printf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname));
-       return false;
+/*
+=============
+SV_CheckStuck
+
+This is a big hack to try and fix the rare case of getting stuck in the world
+clipping hull.
+=============
+*/
+void SV_CheckStuck (prvm_edict_t *ent)
+{
+       vec3_t offset;
+
+       switch(SV_UnstickEntityReturnOffset(ent, offset))
+       {
+               case UNSTICK_GOOD:
+                       VectorCopy (ent->fields.server->origin, ent->fields.server->oldorigin);
+                       break;
+               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(ent->fields.server->classname), offset[0], offset[1], offset[2]);
+                       break;
+               case UNSTICK_STUCK:
+                       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);
+                       }
+                       else
+                               Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname));
+                       break;
+               default:
+                       Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
+       }
 }