From 1ded6e92a5bc0f457ca4d131e27ee6c73d7030e6 Mon Sep 17 00:00:00 2001 From: NaySurGithub <96527285+NaySurGithub@users.noreply.github.com> Date: Fri, 6 Nov 2026 23:50:44 +0100 Subject: [PATCH] fix(place): pick the block under the player when looking down past an edge Bedrock bridging works by looking down past the edge of the block you stand on: the ray hits nothing, yet the game targets that block. #64 removed Perlin's invented reach-around (and its made-up click), which left no way to place there at all. The game's pick (0x144E090C0) does it when nothing is in reach and the look direction's y is below -0.7: it clips blocks from the eye 2 blocks straight down, keeps that hit point, and sets the face from the look's dominant horizontal axis; the hit carries a flag (+0x84) that held repeats check before reusing it (0x14376B8D0). Perlin now does the same, so the outline shows and the click is mPos - BlockPos (top of the block) like the game's. --- src/client/PerlinInteraction.cpp | 16 ++++++++++++++++ src/client/player/HeldBuild.cpp | 2 +- src/client/player/HeldBuild.hpp | 1 + src/client/player/Interaction.hpp | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/client/PerlinInteraction.cpp b/src/client/PerlinInteraction.cpp index 655fe381..b960dcb8 100644 --- a/src/client/PerlinInteraction.cpp +++ b/src/client/PerlinInteraction.cpp @@ -75,6 +75,21 @@ namespace perlin { }, {camera.x, camera.y, camera.z}, glm::dvec3(targeting::ViewVector(camera.yaw, camera.pitch)), PickRange(creative, 1), EntityPickRange(creative)); + // looking down past an edge with nothing in reach (pick 0x144E090C0): clip 2 blocks straight down + // from the eye; that block becomes the target, on the face of the look's dominant horizontal axis + const glm::dvec3 look(targeting::ViewVector(camera.yaw, camera.pitch)); + if (aimHit.kind == AimHit::Kind::None && look.y < -0.7) { + const std::vector noEntities; + AimHit below = Raycast( + live ? live->NetLevel() : *previewLevel, &levelRenderer->Blocks(), noEntities, + [](const entity::Entity&) { return glm::vec2(0.0f); }, {camera.x, camera.y, camera.z}, + glm::dvec3(0.0, -1.0, 0.0), 2.0, 0.0); + if (below.kind == AimHit::Kind::Block) { + below.face = std::fabs(look.x) > std::fabs(look.z) ? (look.x < 0.0 ? 4 : 5) : (look.z < 0.0 ? 2 : 3); + below.buildAssist = true; + aimHit = below; + } + } } if (PERLIN_ENV("PERLIN_AIM_DEBUG")) Log("aim", "kind {} block {},{},{} face {} dist {}", static_cast(aimHit.kind), aimHit.bx, @@ -313,6 +328,7 @@ namespace perlin { if (bedrockBuild && inputManager.IsDown(Action::Use) && !inputManager.Pressed(Action::Use)) { heldbuild::Hit hit; hit.block = aimHit.kind == AimHit::Kind::Block; + hit.assist = aimHit.buildAssist; hit.target = {{aimHit.bx, aimHit.by, aimHit.bz}, aimHit.face}; hit.point = aimHit.kind != AimHit::Kind::None ? glm::vec3(aimHit.point) : buildEye + glm::normalize(camera.Direction()) * diff --git a/src/client/player/HeldBuild.cpp b/src/client/player/HeldBuild.cpp index 113c3634..3ef6e6cf 100644 --- a/src/client/player/HeldBuild.cpp +++ b/src/client/player/HeldBuild.cpp @@ -106,7 +106,7 @@ namespace perlin::heldbuild { if (!SegmentHitsCell(eye, hit.point, nextBuild)) return std::nullopt; click = {nextBuild - direction, continueFacing}; - } else if (hit.block) { + } else if (hit.block && !hit.assist) { click = hit.target; const float xy = velocity.x * velocity.x + velocity.y * velocity.y; if (lastSnappable && !hasDirection && hasLastBuilt && velocity.z * velocity.z + xy > 0.0099999998f) { diff --git a/src/client/player/HeldBuild.hpp b/src/client/player/HeldBuild.hpp index 24e01767..9f6d0e74 100644 --- a/src/client/player/HeldBuild.hpp +++ b/src/client/player/HeldBuild.hpp @@ -21,6 +21,7 @@ namespace perlin::heldbuild { struct Hit { bool block = false; // crosshair on a block (direct hit) + bool assist = false; // the block is the look-down pick under the player, not a ray hit Target target; glm::vec3 point{}; // where the ray stopped: hit point, or eye + look * reach without a hit }; diff --git a/src/client/player/Interaction.hpp b/src/client/player/Interaction.hpp index 0d793390..02d0d5fb 100644 --- a/src/client/player/Interaction.hpp +++ b/src/client/player/Interaction.hpp @@ -17,6 +17,8 @@ namespace perlin { uint64_t entity = 0; glm::dvec3 boxLo{0.0}, boxHi{0.0}; std::vector> shape; + // block under the player picked when looking down past an edge (HitResult +0x84): held repeats skip it + bool buildAssist = false; }; // world hit on the padded pick box, like HitResult::mPos: the game sends it as the entity click pos