diff --git a/client/scripts/player.gd b/client/scripts/player.gd index 2f7435f..064670e 100644 --- a/client/scripts/player.gd +++ b/client/scripts/player.gd @@ -154,7 +154,13 @@ func _step_assist_can_raise_by(dy: float) -> bool: func _try_walk_step_assist() -> bool: - if not _has_walk_goal or _auth_walk_goal.y < global_position.y + 0.025: + if not _has_walk_goal: + return false + # Use actual capsule bottom (cylindrical half-height + hemisphere radius) so the guard + # triggers whenever the goal surface is meaningfully above the player's feet — not the + # capsule centre, which sits ~0.9 m above the floor. + var actual_feet_y: float = global_position.y - CAPSULE_HALF_HEIGHT - PLAYER_CAPSULE_RADIUS + if _auth_walk_goal.y < actual_feet_y + 0.025: return false if not _step_assist_has_support(): return false @@ -166,8 +172,9 @@ func _try_walk_step_assist() -> bool: var vel_h: Vector3 = Vector3(velocity.x, 0.0, velocity.z) if not _step_assist_wallish_blocks(want) or vel_h.dot(want) > WALK_STEP_ASSIST_MAX_FORWARD_DOT: return false - var lift: float = minf(WALK_STEP_ASSIST_DELTA, _auth_walk_goal.y - global_position.y + 0.45) - lift = minf(lift, maxf(0.0, _auth_walk_goal.y + 0.55 - global_position.y)) + # Target capsule centre once standing on the goal surface. + var target_center_y: float = _auth_walk_goal.y + CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS + var lift: float = clampf(target_center_y - global_position.y, 0.0, WALK_STEP_ASSIST_DELTA) if lift <= 0.002 or not _step_assist_can_raise_by(lift): return false global_position.y += lift diff --git a/docs/plans/NEON-29-implementation-plan.md b/docs/plans/NEON-29-implementation-plan.md index 1415701..1f677fe 100644 --- a/docs/plans/NEON-29-implementation-plan.md +++ b/docs/plans/NEON-29-implementation-plan.md @@ -105,6 +105,7 @@ No new automated GDScript tests are added for this story — there is no new GDS ## Decisions - **No horizontal step limit (resolved):** The server's `MaxHorizontalStep = 18 m` was too restrictive for the expanded 45 × 45 m floor (diagonal ≈ 63 m). Added `HorizontalStepEnabled` bool to `MovementValidationOptions` (defaults `false`), matching the `DistrictBoundsEnabled` pattern. The horizontal check is now skipped by default; the property remains available to opt back in via config. `MoveRejectFarPad` no longer exercises a horizontal range reject; it retains its walkable surface for vertical-step regression only. +- **Step assist guard/lift bug fixed (resolved):** `_try_walk_step_assist` in `player.gd` compared the goal's surface Y against the **capsule centre** (`global_position.y ≈ 0.9`) instead of the actual capsule bottom (`global_position.y − CAPSULE_HALF_HEIGHT − PLAYER_CAPSULE_RADIUS = 0.0`). This disabled the assist for any surface below ≈ 0.925 m — including all three terrace platforms. The lift formula used offsets of 0.45/0.55 instead of the full total half-height (0.9), giving zero or negative lift. Fixed: guard now uses `actual_feet_y`; lift targets `goal.y + CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS` via `clampf`. ## Open questions / risks