diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 9c3f9751..c343f16e 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -1730,11 +1730,20 @@ namespace MinecraftClient int sx = (int)Math.Floor(location.X); int sy = (int)Math.Floor(location.Y); int sz = (int)Math.Floor(location.Z); + + // If floored Y lands inside a solid block (e.g. player on top of it), step up + if (!ctx.CanWalkThrough(sx, sy, sz) && ctx.CanWalkThrough(sx, sy + 1, sz)) + sy++; + int gx = (int)Math.Floor(goal.X); int gy = (int)Math.Floor(goal.Y); int gz = (int)Math.Floor(goal.Z); - Log.Info($"[Goto] A* search from ({sx},{sy},{sz}) to ({gx},{gy},{gz})..."); + if (!ctx.CanWalkThrough(gx, gy, gz) && ctx.CanWalkThrough(gx, gy + 1, gz)) + gy++; + + Log.Info($"[Goto] A* search from ({sx},{sy},{sz}) to ({gx},{gy},{gz}) " + + $"[raw pos=({location.X:F2},{location.Y:F2},{location.Z:F2})]"); using var cts = new CancellationTokenSource(); var result = finder.Calculate(ctx, sx, sy, sz, @@ -3293,12 +3302,20 @@ namespace MinecraftClient /// /// Check if the player has approximately reached a waypoint. + /// Uses both horizontal and vertical distance for climb/descend waypoints. /// private bool ReachedWaypoint(Location target) { double dx = target.X - location.X; double dz = target.Z - location.Z; - return dx * dx + dz * dz < 0.25; // within ~0.5 blocks horizontally + double dy = target.Y - location.Y; + double horizDistSq = dx * dx + dz * dz; + + // Vertical waypoint (climbing/falling): require reaching target Y level + if (horizDistSq < 0.5 && Math.Abs(dy) > 0.8) + return false; + + return horizDistSq < 0.25 && Math.Abs(dy) < 0.8; } /// @@ -3312,7 +3329,41 @@ namespace MinecraftClient double dy = target.Y - location.Y; double distSqr = dx * dx + dz * dz; - if (distSqr < 0.01) return; // Close enough horizontally + // Climbing: target is above/below with small horizontal offset + if (playerPhysics.OnClimbable && Math.Abs(dy) > 0.5 && distSqr < 1.0) + { + if (dy > 0) + { + physicsInput.Jump = true; + // Push against the wall for HorizontalCollision-triggered climbing + if (distSqr > 0.01) + { + float yaw = (float)(-Math.Atan2(dx, dz) / Math.PI * 180.0); + if (yaw < 0) yaw += 360; + playerPhysics.Yaw = yaw; + playerYaw = yaw; + physicsInput.Forward = true; + } + else + { + physicsInput.Forward = true; + } + } + else + { + physicsInput.Sneak = false; + } + return; + } + + // Non-climbing vertical jump + if (distSqr < 0.1 && dy > 0.5 && playerPhysics.OnGround) + { + physicsInput.Jump = true; + return; + } + + if (distSqr < 0.01) return; // Calculate yaw to face target float targetYaw = (float)(-Math.Atan2(dx, dz) / Math.PI * 180.0); diff --git a/MinecraftClient/Pathing/Moves/MoveHelper.cs b/MinecraftClient/Pathing/Moves/MoveHelper.cs index 8bb6108f..e925bc6f 100644 --- a/MinecraftClient/Pathing/Moves/MoveHelper.cs +++ b/MinecraftClient/Pathing/Moves/MoveHelper.cs @@ -19,6 +19,10 @@ namespace MinecraftClient.Pathing.Moves return true; if (mat.IsLiquid()) return false; + if (mat.CanBeClimbedOn()) + return true; + if (IsOpenGate(mat)) + return true; if (mat.IsSolid()) return false; if (mat.CanHarmPlayers()) @@ -38,6 +42,10 @@ namespace MinecraftClient.Pathing.Moves return false; if (mat.CanHarmPlayers()) return false; + if (mat.CanBeClimbedOn()) + return false; + if (IsOpenGate(mat)) + return false; return mat.IsSolid(); } @@ -65,5 +73,19 @@ namespace MinecraftClient.Pathing.Moves { return mat == Material.Water; } + + /// + /// Conservative check for gate-type blocks. Since we cannot read block state + /// (open/closed) during planning, treat all fence gates as passable. + /// + private static bool IsOpenGate(Material mat) + { + return mat is Material.AcaciaFenceGate or Material.BirchFenceGate + or Material.CrimsonFenceGate or Material.DarkOakFenceGate + or Material.JungleFenceGate or Material.MangroveWood + or Material.OakFenceGate or Material.SpruceFenceGate + or Material.WarpedFenceGate or Material.CherryFenceGate + or Material.BambooFenceGate or Material.PaleOakFenceGate; + } } }