Collision: insert a really stupid workaround: make every trace 1qu longer, and retroa...
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 3 Aug 2009 11:53:47 +0000 (11:53 +0000)
committerdivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 3 Aug 2009 11:53:47 +0000 (11:53 +0000)
Bug this works around for: when doing a trace from A to B, B being just slightly inside solid, the trace ends "successfully" with fraction 1. However, a trace starting in B will be startsolid. This workaround removes this inconsistency, which sometimes causes map fallthrough, and should have no other side effects, not even a noticable performance impact.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9085 d7cf8633-e32d-0410-b094-e92efae38249

cl_collision.c
collision.c
collision.h
sv_phys.c

index 802b8ad..e9788fa 100644 (file)
@@ -2,7 +2,11 @@
 #include "quakedef.h"
 #include "cl_collision.h"
 
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+float CL_SelectTraceLine(const vec3_t start, const vec3_t pEnd, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent)
+#else
 float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent)
+#endif
 {
        float maxfrac, maxrealfrac;
        int n;
@@ -10,6 +14,20 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve
        float tracemins[3], tracemaxs[3];
        trace_t trace;
        float tempnormal[3], starttransformed[3], endtransformed[3];
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+       vec3_t end;
+       vec_t len;
+
+       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
 
        memset (&trace, 0 , sizeof(trace_t));
        trace.fraction = 1;
@@ -53,11 +71,12 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve
                Matrix4x4_Transform(&ent->inversematrix, start, starttransformed);
                Matrix4x4_Transform(&ent->inversematrix, end, endtransformed);
                Collision_ClipTrace_Box(&trace, ent->model->normalmins, ent->model->normalmaxs, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID, SUPERCONTENTS_SOLID, 0, NULL);
+               if(!VectorCompare(start, pEnd))
+                       Collision_ShortenTrace(&trace, len / (len + 1), pEnd);
                if (maxrealfrac < trace.realfraction)
                        continue;
 
-               //if (ent->model && ent->model->TraceBox)
-                       ent->model->TraceBox(ent->model, ent->frameblend[0].subframe, &trace, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID);
+               ent->model->TraceBox(ent->model, ent->frameblend[0].subframe, &trace, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID);
 
                if (maxrealfrac > trace.realfraction)
                {
@@ -205,7 +224,11 @@ int CL_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
 CL_Move
 ==================
 */
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+trace_t CL_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, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities)
+#else
 trace_t CL_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, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities)
+#endif
 {
        vec3_t hullmins, hullmaxs;
        int i, bodysupercontents;
@@ -230,6 +253,20 @@ trace_t CL_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;
+
+       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
 
        if (hitnetworkentity)
                *hitnetworkentity = 0;
@@ -250,7 +287,7 @@ trace_t CL_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
        if (cliptrace.startsolid || cliptrace.fraction < 1)
                cliptrace.ent = prog ? prog->edicts : NULL;
        if (type == MOVE_WORLDONLY)
-               return cliptrace;
+               goto finished;
 
        if (type == MOVE_MISSILE)
        {
@@ -427,5 +464,10 @@ skipnetworkplayers:
                Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.client->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;
 }
index 5694cdb..3149889 100644 (file)
@@ -1602,3 +1602,22 @@ void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *tou
        }
        cliptrace->startsupercontents |= trace->startsupercontents;
 }
+
+void Collision_ShortenTrace(trace_t *trace, float shorten_factor, const vec3_t end)
+{
+       // now undo our moving end 1 qu farther...
+       trace->fraction = bound(trace->fraction, trace->fraction / shorten_factor - 1e-6, 1); // we subtract 1e-6 to guard for roundoff errors
+       trace->realfraction = bound(trace->realfraction, trace->realfraction / shorten_factor - 1e-6, 1); // we subtract 1e-6 to guard for roundoff errors
+       if(trace->fraction >= 1) // trace would NOT hit if not expanded!
+       {
+               trace->fraction = 1;
+               trace->realfraction = 1;
+               VectorCopy(end, trace->endpos);
+               memset(&trace->plane, 0, sizeof(trace->plane));
+               trace->ent = NULL;
+               trace->hitsupercontentsmask = 0;
+               trace->hitsupercontents = 0;
+               trace->hitq3surfaceflags = 0;
+               trace->hittexture = NULL;
+       }
+}
index 339f1aa..67b5eaa 100644 (file)
@@ -138,6 +138,9 @@ void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start
 // updates fraction, endpos, plane and surface info if new fraction is shorter
 void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *touch, qboolean isbmodel);
 
+// shorten a trace by the given factor
+void Collision_ShortenTrace(trace_t *trace, float shorten_factor, const vec3_t end);
+
 // this enables rather large debugging spew!
 // settings:
 // 0 = no spew
@@ -146,4 +149,8 @@ void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *tou
 // 3 = spew detailed trace flow (bsp tree recursion info)
 #define COLLISIONPARANOID 0
 
+// make every trace 1qu longer, and shorten the result, to work around a stupid bug somewhere
+#define COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+
+
 #endif
index 9c67efd..d9cb5e6 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -82,11 +82,19 @@ 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;
@@ -112,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;
+
+       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);
@@ -129,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)
        {
@@ -246,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;
 }