NS-23: unstuck bump top — descend steers xz to goal; doc abs(dy)

Server already allows downward steps via abs(ΔY) vs MaxVerticalStep; document
that explicitly.

Client: when authoritative goal Y is below the body, skip nav waypoints and
steer horizontally toward the goal only — mesh waypoints under the rim
gave ~no horizontal speed (felt like wrong collision).
pull/23/head
VinPropane 2026-04-05 01:29:31 -04:00
parent b8176f8fa1
commit e1beb82a75
2 changed files with 11 additions and 1 deletions

View File

@ -6,12 +6,15 @@ extends CharacterBody3D
## and steps comes from `move_and_slide` + floor_* on CharacterBody3D. Move **legality** (step,
## distance, bounds) is server MoveCommand only — not reimplemented here.
##
## NavigationAgent3D detours obstacles; steering uses target **xz** only.
## Nav detours except when goal Y is below us: then xz toward goal (waypoints sit under bump rims).
const MOVE_SPEED: float = 5.0
const ARRIVE_EPS: float = 0.35
const VERT_ARRIVE_EPS: float = 0.055
const DIRECT_APPROACH_RADIUS: float = 0.85
## Server goal clearly below us (descending). Nav mesh waypoints are often under the rim first;
## steering at next gives almost no horizontal speed — walk out on xz toward the authorized goal.
const DESCEND_GOAL_Y_MARGIN: float = 0.06
var _has_walk_goal: bool = false
var _auth_walk_goal: Vector3 = Vector3.ZERO
@ -73,6 +76,11 @@ func _physics_process(_delta: float) -> void:
move_and_slide()
return
if _auth_walk_goal.y < global_position.y - DESCEND_GOAL_Y_MARGIN:
_set_horizontal_velocity_toward(_auth_walk_goal)
move_and_slide()
return
if horiz_dist <= DIRECT_APPROACH_RADIUS:
_set_horizontal_velocity_toward(_auth_walk_goal)
else:

View File

@ -4,6 +4,8 @@ namespace NeonSprawl.Server.Game.PositionState;
/// <remarks>
/// <para><b>Precedence</b> when multiple rules fail: <see cref="MoveCommandReasonCodes.HorizontalStepExceeded"/>,
/// then <see cref="MoveCommandReasonCodes.VerticalStepExceeded"/>, then <see cref="MoveCommandReasonCodes.OutOfBounds"/>.</para>
/// <para>Vertical uses <c>abs(ΔY)</c>, so <b>descending</b> (target Y lower than current) is allowed when the
/// drop is within <see cref="MovementValidationOptions.MaxVerticalStep"/> — same as climbing.</para>
/// </remarks>
public static class MoveCommandValidation
{