]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Work around float precision problems with scaled model-based bboxes 1078/head
authorbones_was_here <bones_was_here@xonotic.au>
Sun, 2 Oct 2022 22:05:54 +0000 (08:05 +1000)
committerbones_was_here <bones_was_here@xonotic.au>
Tue, 25 Oct 2022 16:57:43 +0000 (02:57 +1000)
Fixes #2742

qcsrc/common/mapobjects/subs.qc
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc
qcsrc/lib/vector.qh

index c0b137404c55956d1fa509f697a23e1452c6676e..afe3f9399e0b0a37c2946cec698c328bdf7072bf 100644 (file)
@@ -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);
 }
index fc1681a91410065817cabc8570873d299d7b4280..e88b35f4554aec593a5a922d09ebf0656e0de33a 100644 (file)
@@ -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);
index 7188ae3297cca37ac9ff8d568d424d8be2c75c13..f3bf39f73688280294a597d92db57201767597b4 100644 (file)
@@ -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));
        }
 }
 
index 23bfdf05593ff178f4f31c35d4319d4985d6626a..d2d83ff6595dca5a2642017702112745527eef1c 100644 (file)
@@ -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