]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
[04:31:11] <@LordHavoc> div0: 9179 (if (msecdelta <= 0) return;) wrecked connect...
[xonotic/darkplaces.git] / sv_phys.c
index e79f8441e78fe10f293bc9fcf72787f4af3da857..24b17ef7bd77dfe0423eec84a8967acbb3f0fbc8 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -82,15 +82,24 @@ int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
 SV_Move
 ==================
 */
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+#if COLLISIONPARANOID >= 1
+trace_t SV_Move_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
+#else
+trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
+#endif
+#else
 #if COLLISIONPARANOID >= 1
 trace_t SV_Move_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
 #else
 trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
 #endif
+#endif
 {
        vec3_t hullmins, hullmaxs;
        int i, bodysupercontents;
        int passedictprog;
+       float pitchsign = 1;
        qboolean pointtrace;
        prvm_edict_t *traceowner, *touch;
        trace_t trace;
@@ -111,6 +120,20 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
        // list of entities to test for collisions
        int numtouchedicts;
        prvm_edict_t *touchedicts[MAX_EDICTS];
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+       vec3_t end;
+       vec_t len = 0;
+
+       if(!VectorCompare(start, pEnd))
+       {
+               // TRICK: make the trace 1 qu longer!
+               VectorSubtract(pEnd, start, end);
+               len = VectorNormalizeLength(end);
+               VectorAdd(pEnd, end, end);
+       }
+       else
+               VectorCopy(pEnd, end);
+#endif
 
        VectorCopy(start, clipstart);
        VectorCopy(end, clipend);
@@ -128,7 +151,7 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
        if (cliptrace.startsolid || cliptrace.fraction < 1)
                cliptrace.ent = prog->edicts;
        if (type == MOVE_WORLDONLY)
-               return cliptrace;
+               goto finished;
 
        if (type == MOVE_MISSILE)
        {
@@ -218,9 +241,22 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
                        // if the modelindex is 0, it shouldn't be SOLID_BSP!
                        if (modelindex > 0 && modelindex < MAX_MODELS)
                                model = sv.models[(int)touch->fields.server->modelindex];
+                       //pitchsign = 1;
+                       if (
+                               ((modelindex = (int)touch->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[(int)touch->fields.server->modelindex]))
+                               ?
+                                       model->type == mod_alias
+                               :
+                                       (
+                                               (((unsigned char)PRVM_EDICTFIELDVALUE(touch, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC)
+                                               ||
+                                               ((gamemode == GAME_TENEBRAE) && ((unsigned int)touch->fields.server->effects & (16 | 32)))
+                                       )
+                       )
+                               pitchsign = -1;
                }
                if (model)
-                       Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+                       Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
                else
                        Matrix4x4_CreateTranslate(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2]);
                Matrix4x4_Invert_Simple(&imatrix, &matrix);
@@ -232,6 +268,11 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
                Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.server->solid == SOLID_BSP);
        }
 
+finished:
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+       if(!VectorCompare(start, pEnd))
+               Collision_ShortenTrace(&cliptrace, len / (len + 1), pEnd);
+#endif
        return cliptrace;
 }
 
@@ -484,11 +525,13 @@ returns true if the entity is in solid currently
 */
 static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
 {
+       int contents;
        vec3_t org;
        trace_t trace;
+       contents = SV_GenericHitSuperContentsMask(ent);
        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)
+       trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, contents);
+       if (trace.startsupercontents & contents)
                return true;
        else
        {
@@ -512,7 +555,7 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
                                v[0] = (i & 1) ? m2[0] : m1[0];
                                v[1] = (i & 2) ? m2[1] : m1[1];
                                v[2] = (i & 4) ? m2[2] : m1[2];
-                               if (SV_PointSuperContents(v) & SUPERCONTENTS_SOLID)
+                               if (SV_PointSuperContents(v) & contents)
                                        return true;
                        }
                }
@@ -526,7 +569,7 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
 #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);
+               trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, org, MOVE_NOMONSTERS, ent, contents);
                if(trace.startsolid)
                        Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
                else
@@ -684,14 +727,16 @@ qboolean SV_RunThink (prvm_edict_t *ent)
 SV_Impact
 
 Two entities have touched, so run their touch functions
+returns true if the impact kept the origin of the touching entity intact
 ==================
 */
 extern void VM_SetTraceGlobals(const trace_t *trace);
 extern sizebuf_t vm_tempstringsbuf;
-void SV_Impact (prvm_edict_t *e1, trace_t *trace)
+qboolean SV_Impact (prvm_edict_t *e1, trace_t *trace)
 {
        int restorevm_tempstringsbuf_cursize;
        int old_self, old_other;
+       vec3_t org;
        prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
        prvm_eval_t *val;
 
@@ -699,6 +744,8 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace)
        old_other = prog->globals.server->other;
        restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
 
+       VectorCopy(e1->fields.server->origin, org);
+
        VM_SetTraceGlobals(trace);
 
        prog->globals.server->time = sv.time;
@@ -731,6 +778,8 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace)
        prog->globals.server->self = old_self;
        prog->globals.server->other = old_other;
        vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+
+       return VectorCompare(e1->fields.server->origin, org);
 }
 
 
@@ -766,11 +815,12 @@ Returns the clipflags if the velocity was modified (hit something solid)
 1 = floor
 2 = wall / step
 4 = dead stop
+8 = teleported by touch method
 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
 ============
 */
 static float SV_Gravity (prvm_edict_t *ent);
-static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
+static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
 // LordHavoc: increased from 5 to 32
 #define MAX_CLIP_PLANES 32
 static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask)
@@ -813,13 +863,11 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
 #if 0
                VectorAdd(ent->fields.server->origin, push, end);
 #endif
-               trace = SV_PushEntity(ent, push, false, false); // the caller calls SV_LinkEntity on the own later
-
-               if(!VectorCompare(trace.endpos, ent->fields.server->origin))
+               if(!SV_PushEntity(&trace, ent, push, false, false))
                {
                        // we got teleported by a touch function
                        // let's abort the move
-                       Con_DPrintf("we got teleported\n");
+                       blocked |= 8;
                        break;
                }
 
@@ -1004,7 +1052,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
        */
 
        // 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))
+       if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP) && !(blocked & 8))
                VectorCopy(primal_velocity, ent->fields.server->velocity);
        if (applygravity && !((int)ent->fields.server->flags & FL_ONGROUND))
                ent->fields.server->velocity[2] -= gravity;
@@ -1044,12 +1092,13 @@ PUSHMOVE
 SV_PushEntity
 
 Does not change the entities velocity at all
+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 trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
+static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
 {
        int type;
-       trace_t trace;
        vec3_t end;
        qboolean impact;
 
@@ -1062,23 +1111,31 @@ static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmo
        else
                type = MOVE_NORMAL;
 
-       trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
-       if (trace.bmodelstartsolid && failonbmodelstartsolid)
-               return trace;
+       *trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
+       if (trace->bmodelstartsolid && failonbmodelstartsolid)
+               return true;
+
+       VectorCopy (trace->endpos, ent->fields.server->origin);
 
-       VectorCopy (trace.endpos, ent->fields.server->origin);
+#if 0
+       if(!trace->startsolid)
+       if(SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid)
+       {
+               Con_Printf("something eeeeevil happened\n");
+       }
+#endif
 
-       impact = (ent->fields.server->solid >= SOLID_TRIGGER && trace.ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace.ent)));
+       impact = (ent->fields.server->solid >= SOLID_TRIGGER && trace->ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace->ent)));
 
        if(impact)
        {
                SV_LinkEdict (ent, dolink);
-               SV_Impact (ent, &trace);
+               return SV_Impact (ent, trace);
        }
        else if(dolink)
                SV_LinkEdict (ent, true);
 
-       return trace;
+       return true;
 }
 
 
@@ -1100,7 +1157,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
        int numcheckentities;
        static prvm_edict_t *checkentities[MAX_EDICTS];
        dp_model_t *pushermodel;
-       trace_t trace;
+       trace_t trace, trace2;
        matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
        unsigned short moved_edicts[MAX_EDICTS];
 
@@ -1281,7 +1338,13 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
 
                // try moving the contacted entity
                pusher->fields.server->solid = SOLID_NOT;
-               trace = SV_PushEntity (check, move, true, true);
+               if(!SV_PushEntity (&trace, check, move, true, true))
+               {
+                       // entity "check" got teleported
+                       check->fields.server->angles[1] += trace.fraction * moveangle[1];
+                       pusher->fields.server->solid = savesolid; // was SOLID_BSP
+                       continue; // pushed enough
+               }
                // FIXME: turn players specially
                check->fields.server->angles[1] += trace.fraction * moveangle[1];
                pusher->fields.server->solid = savesolid; // was SOLID_BSP
@@ -1303,7 +1366,11 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                        VectorScale(move, 1.1, move2);
                        VectorCopy (check->priv.server->moved_from, check->fields.server->origin);
                        VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles);
-                       SV_PushEntity (check, move2, true, true);
+                       if(!SV_PushEntity (&trace2, check, move2, true, true))
+                       {
+                               // entity "check" got teleported
+                               continue;
+                       }
                        pusher->fields.server->solid = savesolid;
                        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)
@@ -1313,7 +1380,11 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                                VectorScale(move, 0.9, move2);
                                VectorCopy (check->priv.server->moved_from, check->fields.server->origin);
                                VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles);
-                               SV_PushEntity (check, move2, true, true);
+                               if(!SV_PushEntity (&trace2, check, move2, true, true))
+                               {
+                                       // entity "check" got teleported
+                                       continue;
+                               }
                                pusher->fields.server->solid = savesolid;
                                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)
@@ -1638,7 +1709,7 @@ int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
                        case 7: dir[0] = -2; dir[1] = -2; break;
                }
 
-               SV_PushEntity (ent, dir, false, true);
+               SV_PushEntity (&trace, ent, dir, false, true);
 
                // retry the original move
                ent->fields.server->velocity[0] = oldvel[0];
@@ -1675,7 +1746,7 @@ 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;
+       trace_t downtrace, trace;
        qboolean applygravity;
 
        // if frametime is 0 (due to client sending the same timestamp twice),
@@ -1706,11 +1777,8 @@ void SV_WalkMove (prvm_edict_t *ent)
        SV_CheckVelocity(ent);
        SV_LinkEdict (ent, true);
 
-       VectorCopy(ent->fields.server->origin, originalmove_origin);
-       VectorCopy(ent->fields.server->velocity, originalmove_velocity);
-       originalmove_clip = clip;
-       originalmove_flags = (int)ent->fields.server->flags;
-       originalmove_groundentity = ent->fields.server->groundentity;
+       if(clip & 8) // teleport
+               return;
 
        if ((int)ent->fields.server->flags & FL_WATERJUMP)
                return;
@@ -1718,6 +1786,12 @@ void SV_WalkMove (prvm_edict_t *ent)
        if (sv_nostep.integer)
                return;
 
+       VectorCopy(ent->fields.server->origin, originalmove_origin);
+       VectorCopy(ent->fields.server->velocity, originalmove_velocity);
+       originalmove_clip = clip;
+       originalmove_flags = (int)ent->fields.server->flags;
+       originalmove_groundentity = ent->fields.server->groundentity;
+
        // if move didn't block on a step, return
        if (clip & 2)
        {
@@ -1745,12 +1819,22 @@ void SV_WalkMove (prvm_edict_t *ent)
                // move up
                VectorClear (upmove);
                upmove[2] = sv_stepheight.value;
-               SV_PushEntity(ent, upmove, false, false);
+               if(!SV_PushEntity(&trace, ent, upmove, false, true))
+               {
+                       // we got teleported when upstepping... must abort the move
+                       return;
+               }
 
                // move forward
                ent->fields.server->velocity[2] = 0;
                clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask);
                ent->fields.server->velocity[2] += start_velocity[2];
+               if(clip & 8)
+               {
+                       // we got teleported when upstepping... must abort the move
+                       // note that z velocity handling may not be what QC expects here, but we cannot help it
+                       return;
+               }
 
                SV_CheckVelocity(ent);
                SV_LinkEdict (ent, true);
@@ -1786,7 +1870,11 @@ void SV_WalkMove (prvm_edict_t *ent)
        // move down
        VectorClear (downmove);
        downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
-       downtrace = SV_PushEntity (ent, downmove, false, false);
+       if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
+       {
+               // we got teleported when downstepping... must abort the move
+               return;
+       }
 
        if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
        {
@@ -1947,7 +2035,8 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                        // and groundentity is now freed, set groundentity to 0 (world)
                        // which leaves it suspended in the air
                        ent->fields.server->groundentity = 0;
-                       return;
+                       if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
+                               return;
                }
        }
        ent->priv.server->suspendedinairflag = false;
@@ -1966,14 +2055,16 @@ void SV_Physics_Toss (prvm_edict_t *ent)
        {
        // move origin
                VectorScale (ent->fields.server->velocity, movetime, move);
-               trace = SV_PushEntity (ent, move, true, true);
+               if(!SV_PushEntity (&trace, ent, move, true, true))
+                       return; // teleported
                if (ent->priv.server->free)
                        return;
                if (trace.bmodelstartsolid)
                {
                        // try to unstick the entity
                        SV_UnstickEntity(ent);
-                       trace = SV_PushEntity (ent, move, false, true);
+                       if(!SV_PushEntity (&trace, ent, move, false, true))
+                               return; // teleported
                        if (ent->priv.server->free)
                                return;
                }
@@ -2161,7 +2252,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
        //  ents in the first frame regardless)
        qboolean runmove = ent->priv.server->move;
        ent->priv.server->move = true;
-       if (!runmove && sv_gameplayfix_delayprojectiles.integer)
+       if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
                return;
        switch ((int) ent->fields.server->movetype)
        {
@@ -2397,9 +2488,17 @@ void SV_Physics (void)
 
        // run physics on all the non-client entities
        if (!sv_freezenonclients.integer)
+       {
                for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
                        if (!ent->priv.server->free)
                                SV_Physics_Entity(ent);
+               // make a second pass to see if any ents spawned this frame and make
+               // sure they run their move/think
+               if (sv_gameplayfix_delayprojectiles.integer < 0)
+                       for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
+                               if (!ent->priv.server->move && !ent->priv.server->free)
+                                       SV_Physics_Entity(ent);
+       }
 
        if (prog->globals.server->force_retouch > 0)
                prog->globals.server->force_retouch = max(0, prog->globals.server->force_retouch - 1);