From 4b0a7e004b37e521e5708ee268b980f268420238 Mon Sep 17 00:00:00 2001 From: divverent Date: Mon, 3 Aug 2009 11:53:47 +0000 Subject: [PATCH] Collision: insert a really stupid workaround: make every trace 1qu longer, and retroactively shrink the trace when done. 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 | 48 +++++++++++++++++++++++++++++++++++++++++++++--- collision.c | 19 +++++++++++++++++++ collision.h | 7 +++++++ sv_phys.c | 29 ++++++++++++++++++++++++++++- 4 files changed, 99 insertions(+), 4 deletions(-) diff --git a/cl_collision.c b/cl_collision.c index 802b8adc..e9788fa5 100644 --- a/cl_collision.c +++ b/cl_collision.c @@ -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; } diff --git a/collision.c b/collision.c index 5694cdb4..31498891 100644 --- a/collision.c +++ b/collision.c @@ -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; + } +} diff --git a/collision.h b/collision.h index 339f1aaa..67b5eaa2 100644 --- a/collision.h +++ b/collision.h @@ -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 diff --git a/sv_phys.c b/sv_phys.c index 9c67efdb..d9cb5e6b 100644 --- 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; } -- 2.39.2