From 0e56f2c66008352113e68c7e586f9a9640bcbc45 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Sun, 29 Mar 2026 14:55:36 -0500 Subject: [PATCH] fix: regression in tile bounding box clip --- Minecraft.World/Blocks/Tile.cpp | 70 ++++++++++++++++----------------- Minecraft.World/Blocks/Tile.h | 6 +-- Minecraft.World/Util/AABB.cpp | 51 +++++++++++++----------- Minecraft.World/Util/AABB.h | 6 +-- 4 files changed, 67 insertions(+), 66 deletions(-) diff --git a/Minecraft.World/Blocks/Tile.cpp b/Minecraft.World/Blocks/Tile.cpp index d12283e69..e3416af3b 100644 --- a/Minecraft.World/Blocks/Tile.cpp +++ b/Minecraft.World/Blocks/Tile.cpp @@ -2010,7 +2010,7 @@ AABB Tile::getTileAABB(Level* level, int x, int y, int z) { // 4J Stu - Added this so that the TLS shape is correct for this tile if (tls->tileId != this->id) updateDefaultShape(); return AABB(x + tls->xx0, y + tls->yy0, z + tls->zz0, x + tls->xx1, - y + tls->yy1, z + tls->zz1); + y + tls->yy1, z + tls->zz1); } void Tile::addAABBs(Level* level, int x, int y, int z, AABB* box, @@ -2119,52 +2119,51 @@ float Tile::getExplosionResistance(std::shared_ptr source) { return explosionResistance / 5.0f; } -HitResult* Tile::clip(Level* level, int xt, int yt, int zt, Vec3* a, Vec3* b) { +HitResult* Tile::clip(Level* level, int xt, int yt, int zt, Vec3* a_, + Vec3* b_) { updateShape(level, xt, yt, zt); - *a = a->add(-xt, -yt, -zt); - *b = b->add(-xt, -yt, -zt); + Vec3 a = a_->add(-xt, -yt, -zt); + Vec3 b = b_->add(-xt, -yt, -zt); ThreadStorage* tls = m_tlsShape; - auto xh0 = a->clipX(*b, tls->xx0); - auto xh1 = a->clipX(*b, tls->xx1); - auto yh0 = a->clipY(*b, tls->yy0); - auto yh1 = a->clipY(*b, tls->yy1); + auto xh0 = a.clipX(b, tls->xx0); + auto xh1 = a.clipX(b, tls->xx1); - auto zh0 = a->clipZ(*b, tls->zz0); - auto zh1 = a->clipZ(*b, tls->zz1); + auto yh0 = a.clipY(b, tls->yy0); + auto yh1 = a.clipY(b, tls->yy1); + + auto zh0 = a.clipZ(b, tls->zz0); + auto zh1 = a.clipZ(b, tls->zz1); std::optional closest = std::nullopt; - if (xh0.has_value() and containsX(&*xh0) and - (!closest.has_value() or - a->distanceToSqr(*xh0) < a->distanceToSqr(*closest))) + // 4jcraft NOTE: containsX does a nullopt check and will short circuit so + // dereffing in distanceToSqr is fine. + + if (containsX(xh0) && (!closest.has_value() || + a.distanceToSqr(*xh0) < a.distanceToSqr(*closest))) closest = xh0; - if (xh1.has_value() and containsX(&*xh1) and - (!closest.has_value() or - a->distanceToSqr(*xh1) < a->distanceToSqr(*closest))) + if (containsX(xh1) && (!closest.has_value() || + a.distanceToSqr(*xh1) < a.distanceToSqr(*closest))) closest = xh1; - if (yh0.has_value() and containsY(&*yh0) and - (!closest.has_value() or - a->distanceToSqr(*yh0) < a->distanceToSqr(*closest))) + if (containsY(yh0) && (!closest.has_value() || + a.distanceToSqr(*yh0) < a.distanceToSqr(*closest))) closest = yh0; - if (yh1.has_value() and containsY(&*yh1) and - (!closest.has_value() or - a->distanceToSqr(*yh1) < a->distanceToSqr(*closest))) + if (containsY(yh1) && (!closest.has_value() || + a.distanceToSqr(*yh1) < a.distanceToSqr(*closest))) closest = yh1; - if (zh0.has_value() and containsZ(&*zh0) and - (!closest.has_value() or - a->distanceToSqr(*zh0) < a->distanceToSqr(*closest))) + if (containsZ(zh0) && (!closest.has_value() || + a.distanceToSqr(*zh0) < a.distanceToSqr(*closest))) closest = zh0; - if (zh1.has_value() and containsZ(&*zh1) and - (!closest.has_value() or - a->distanceToSqr(*zh1) < a->distanceToSqr(*closest))) + if (containsZ(zh1) && (!closest.has_value() || + a.distanceToSqr(*zh1) < a.distanceToSqr(*closest))) closest = zh1; if (!closest.has_value()) return nullptr; @@ -2178,12 +2177,11 @@ HitResult* Tile::clip(Level* level, int xt, int yt, int zt, Vec3* a, Vec3* b) { if (closest == zh0) face = Facing::NORTH; if (closest == zh1) face = Facing::SOUTH; - Vec3 res = closest->add(xt, yt, zt); - return new HitResult(xt, yt, zt, face, res); + return new HitResult(xt, yt, zt, face, closest->add(xt, yt, zt)); } -bool Tile::containsX(Vec3* v) { - if (v == NULL) return false; +bool Tile::containsX(const std::optional& v) { + if (!v.has_value()) return false; ThreadStorage* tls = m_tlsShape; // 4J Stu - Added this so that the TLS shape is correct for this tile @@ -2192,8 +2190,8 @@ bool Tile::containsX(Vec3* v) { v->z <= tls->zz1; } -bool Tile::containsY(Vec3* v) { - if (v == NULL) return false; +bool Tile::containsY(const std::optional& v) { + if (!v.has_value()) return false; ThreadStorage* tls = m_tlsShape; // 4J Stu - Added this so that the TLS shape is correct for this tile @@ -2202,8 +2200,8 @@ bool Tile::containsY(Vec3* v) { v->z <= tls->zz1; } -bool Tile::containsZ(Vec3* v) { - if (v == NULL) return false; +bool Tile::containsZ(const std::optional& v) { + if (!v.has_value()) return false; ThreadStorage* tls = m_tlsShape; // 4J Stu - Added this so that the TLS shape is correct for this tile diff --git a/Minecraft.World/Blocks/Tile.h b/Minecraft.World/Blocks/Tile.h index 2b94b9ffe..8c9d33566 100644 --- a/Minecraft.World/Blocks/Tile.h +++ b/Minecraft.World/Blocks/Tile.h @@ -668,9 +668,9 @@ public: Vec3* b); private: - virtual bool containsX(Vec3* v); - virtual bool containsY(Vec3* v); - virtual bool containsZ(Vec3* v); + virtual bool containsX(const std::optional& v); + virtual bool containsY(const std::optional& v); + virtual bool containsZ(const std::optional& v); public: virtual void wasExploded(Level* level, int x, int y, int z, diff --git a/Minecraft.World/Util/AABB.cpp b/Minecraft.World/Util/AABB.cpp index a31d27728..c9a58d1bb 100644 --- a/Minecraft.World/Util/AABB.cpp +++ b/Minecraft.World/Util/AABB.cpp @@ -184,37 +184,37 @@ HitResult* AABB::clip(const Vec3& a, const Vec3& b) const { auto zh0 = a.clipZ(b, z0); auto zh1 = a.clipZ(b, z1); - if (!(xh0.has_value() and containsX(*xh0))) xh0 = std::nullopt; - if (!(xh1.has_value() and containsX(*xh1))) xh1 = std::nullopt; - if (!(yh0.has_value() and containsY(*yh0))) yh0 = std::nullopt; - if (!(yh1.has_value() and containsY(*yh1))) yh1 = std::nullopt; - if (!(zh0.has_value() and containsZ(*zh0))) zh0 = std::nullopt; - if (!(zh1.has_value() and containsZ(*zh1))) zh1 = std::nullopt; + if (!containsX(xh0)) xh0 = std::nullopt; + if (!containsX(xh1)) xh1 = std::nullopt; + if (!containsY(yh0)) yh0 = std::nullopt; + if (!containsY(yh1)) yh1 = std::nullopt; + if (!containsZ(zh0)) zh0 = std::nullopt; + if (!containsZ(zh1)) zh1 = std::nullopt; std::optional closest = std::nullopt; - if (xh0.has_value() and (!closest.has_value() or - a.distanceToSqr(*xh0) < a.distanceToSqr(*closest))) + if (xh0.has_value() && (!closest.has_value() || + a.distanceToSqr(*xh0) < a.distanceToSqr(*closest))) closest = xh0; - if (xh1.has_value() and (!closest.has_value() or - a.distanceToSqr(*xh1) < a.distanceToSqr(*closest))) + if (xh1.has_value() && (!closest.has_value() || + a.distanceToSqr(*xh1) < a.distanceToSqr(*closest))) closest = xh1; - if (yh0.has_value() and (!closest.has_value() or - a.distanceToSqr(*yh0) < a.distanceToSqr(*closest))) + if (yh0.has_value() && (!closest.has_value() || + a.distanceToSqr(*yh0) < a.distanceToSqr(*closest))) closest = yh0; - if (yh1.has_value() and (!closest.has_value() or - a.distanceToSqr(*yh1) < a.distanceToSqr(*closest))) + if (yh1.has_value() && (!closest.has_value() || + a.distanceToSqr(*yh1) < a.distanceToSqr(*closest))) closest = yh1; - if (zh0.has_value() and (!closest.has_value() or - a.distanceToSqr(*zh0) < a.distanceToSqr(*closest))) + if (zh0.has_value() && (!closest.has_value() || + a.distanceToSqr(*zh0) < a.distanceToSqr(*closest))) closest = zh0; - if (zh1.has_value() and (!closest.has_value() or - a.distanceToSqr(*zh1) < a.distanceToSqr(*closest))) + if (zh1.has_value() && (!closest.has_value() || + a.distanceToSqr(*zh1) < a.distanceToSqr(*closest))) closest = zh1; if (!closest.has_value()) return nullptr; @@ -231,16 +231,19 @@ HitResult* AABB::clip(const Vec3& a, const Vec3& b) const { return new HitResult(0, 0, 0, face, *closest); } -bool AABB::containsX(const Vec3& v) const { - return v.y >= y0 && v.y <= y1 && v.z >= z0 && v.z <= z1; +bool AABB::containsX(const std::optional& v) const { + if (!v.has_value()) return false; + return v->y >= y0 && v->y <= y1 && v->z >= z0 && v->z <= z1; } -bool AABB::containsY(const Vec3& v) const { - return v.x >= x0 && v.x <= x1 && v.z >= z0 && v.z <= z1; +bool AABB::containsY(const std::optional& v) const { + if (!v.has_value()) return false; + return v->x >= x0 && v->x <= x1 && v->z >= z0 && v->z <= z1; } -bool AABB::containsZ(const Vec3& v) const { - return v.x >= x0 && v.x <= x1 && v.y >= y0 && v.y <= y1; +bool AABB::containsZ(const std::optional& v) const { + if (!v.has_value()) return false; + return v->x >= x0 && v->x <= x1 && v->y >= y0 && v->y <= y1; } std::wstring AABB::toString() const { diff --git a/Minecraft.World/Util/AABB.h b/Minecraft.World/Util/AABB.h index fb62056d8..83c32519a 100644 --- a/Minecraft.World/Util/AABB.h +++ b/Minecraft.World/Util/AABB.h @@ -28,8 +28,8 @@ public: double getSize() const; AABB shrink(double xa, double ya, double za) const; HitResult* clip(const Vec3& a, const Vec3& b) const; - bool containsX(const Vec3& v) const; - bool containsY(const Vec3& v) const; - bool containsZ(const Vec3& v) const; + bool containsX(const std::optional& v) const; + bool containsY(const std::optional& v) const; + bool containsZ(const std::optional& v) const; std::wstring toString() const; };