]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
fix buffer overruns in sv.model_precache
[xonotic/darkplaces.git] / sv_phys.c
index 7300cbd65b3a4399a56823ca4a52b4a5f15d5269..1b515b46315d9ab93023071c36374bc554f36f90 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -392,7 +392,7 @@ void SV_LinkEdict (prvm_edict_t *ent, qboolean touch_triggers)
        if (ent->fields.server->solid == SOLID_BSP)
        {
                int modelindex = (int)ent->fields.server->modelindex;
-               if (modelindex < 0 || modelindex > MAX_MODELS)
+               if (modelindex < 0 || modelindex >= MAX_MODELS)
                {
                        Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
                        modelindex = 0;
@@ -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;
 }
 
@@ -1390,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");
+       }
 }
 
 
@@ -1960,7 +1985,18 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                {
                        float d, ent_gravity;
                        prvm_eval_t *val;
-                       ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1.5);
+                       float bouncefactor = 0.5f;
+                       float bouncestop = 60.0f / 800.0f;
+
+                       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.bouncefactor);
+                       if (val!=0 && val->_float)
+                               bouncefactor = val->_float;
+
+                       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.bouncestop);
+                       if (val!=0 && val->_float)
+                               bouncestop = val->_float;
+
+                       ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1 + bouncefactor);
                        // LordHavoc: fixed grenades not bouncing when fired down a slope
                        val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity);
                        if (val!=0 && val->_float)
@@ -1970,7 +2006,7 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                        if (sv_gameplayfix_grenadebouncedownslopes.integer)
                        {
                                d = DotProduct(trace.plane.normal, ent->fields.server->velocity);
-                               if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * (60.0 / 800.0) * ent_gravity)
+                               if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * bouncestop * ent_gravity)
                                {
                                        ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
                                        ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
@@ -1982,7 +2018,7 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                        }
                        else
                        {
-                               if (trace.plane.normal[2] > 0.7 && ent->fields.server->velocity[2] < sv_gravity.value * (60.0 / 800.0) * ent_gravity)
+                               if (trace.plane.normal[2] > 0.7 && ent->fields.server->velocity[2] < sv_gravity.value * bouncestop * ent_gravity)
                                {
                                        ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
                                        ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
@@ -2008,7 +2044,7 @@ 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)
+               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;
        }
 
@@ -2225,7 +2261,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);
@@ -2272,7 +2308,7 @@ 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 (host_client->clmovement_inputtimeout <= 0)
                        SV_WalkMove (ent);
                break;
        case MOVETYPE_TOSS:
@@ -2294,8 +2330,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);
 
@@ -2372,7 +2410,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;