From 73a168a2cc80f8c36602f0558f71fe93fc89e849 Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Mon, 3 Oct 2022 08:05:54 +1000 Subject: [PATCH] Work around float precision problems with scaled model-based bboxes Fixes #2742 --- qcsrc/common/mapobjects/subs.qc | 2 +- qcsrc/common/monsters/sv_monsters.qc | 2 +- qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc | 3 ++- qcsrc/lib/vector.qh | 13 +++++++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/qcsrc/common/mapobjects/subs.qc b/qcsrc/common/mapobjects/subs.qc index c0b137404..afe3f9399 100644 --- a/qcsrc/common/mapobjects/subs.qc +++ b/qcsrc/common/mapobjects/subs.qc @@ -396,7 +396,7 @@ void ApplyMinMaxScaleAngles(entity e) e.mins_y = -e.maxs.x; } if(e.scale) - setsize(e, e.mins * e.scale, e.maxs * e.scale); + setsize(e, RoundPerfectVector(e.mins * e.scale), RoundPerfectVector(e.maxs * e.scale)); else setsize(e, e.mins, e.maxs); } diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index fc1681a91..e88b35f45 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -1428,7 +1428,7 @@ bool Monster_Spawn(entity this, bool check_appear, Monster mon) if((mon.spawnflags & MONSTER_SIZE_QUAKE) && autocvar_g_monsters_quake_resize && !(this.spawnflags & MONSTERFLAG_RESPAWNED)) this.scale *= 1.3; - setsize(this, mon.m_mins * this.scale, mon.m_maxs * this.scale); + setsize(this, RoundPerfectVector(mon.m_mins * this.scale), RoundPerfectVector(mon.m_maxs * this.scale)); this.view_ofs = '0 0 0.7' * (this.maxs_z * 0.5); this.ticrate = bound(sys_frametime, ((!this.ticrate) ? autocvar_g_monsters_think_delay : this.ticrate), 60); diff --git a/qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc b/qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc index 7188ae329..f3bf39f73 100644 --- a/qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc +++ b/qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc @@ -122,7 +122,8 @@ void sandbox_ObjectEdit_Scale(entity e, float f) { e.scale = bound(autocvar_g_sandbox_object_scale_min, e.scale, autocvar_g_sandbox_object_scale_max); _setmodel(e, e.model); // reset mins and maxs based on mesh - setsize(e, e.mins * e.scale, e.maxs * e.scale); // adapt bounding box size to model size + // apply object scaling and prevent any float precision issues like #2742 + setsize(e, RoundPerfectVector(e.mins * e.scale), RoundPerfectVector(e.maxs * e.scale)); } } diff --git a/qcsrc/lib/vector.qh b/qcsrc/lib/vector.qh index 23bfdf055..d2d83ff65 100644 --- a/qcsrc/lib/vector.qh +++ b/qcsrc/lib/vector.qh @@ -196,4 +196,17 @@ vector NearestPointOnBoundingBox(vector mi, vector ma, vector org) bound(mi.z, org.z, ma.z) ); } + +// bones_was_here: rounding bbox to nearest perfect floats prevents obscure collision bugs like #2742 +// FIXME: QC shouldn't need to work around tracebox potentially returning a tiny trace_fraction when the move should have been blocked. +// Tiny values are valid in some situations and can't simply be ignored. +#define PFLOAT (1/1024) // 1/32 1/64 etc also work +#define RPFLOAT(a) (a=rint(a/PFLOAT)*PFLOAT) +ERASEABLE +vector RoundPerfectVector(vector v) +{ + RPFLOAT(v.x); RPFLOAT(v.y); RPFLOAT(v.z); + return v; +} + #endif -- 2.39.2