From 3e041f81c8d187a3027db204c9a1e6006ead27fe Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Fri, 1 May 2026 16:24:14 +0200 Subject: [PATCH] auto-git: [change] src/runtime-three/first-person-navigation-controller.ts --- .../first-person-navigation-controller.ts | 85 +++++++++++++++++-- 1 file changed, 78 insertions(+), 7 deletions(-) diff --git a/src/runtime-three/first-person-navigation-controller.ts b/src/runtime-three/first-person-navigation-controller.ts index 781a98e6..35eeeb37 100644 --- a/src/runtime-three/first-person-navigation-controller.ts +++ b/src/runtime-three/first-person-navigation-controller.ts @@ -21,6 +21,10 @@ import { shouldExitClimbing, type RuntimePlayerClimbSurface } from "./player-climbing"; +import { + resolvePlayerEdgeAssistTopOut, + shouldAttemptPlayerEdgeAssist +} from "./player-edge-assist"; import { createIdleRuntimeLocomotionState, stepPlayerLocomotion @@ -363,18 +367,85 @@ export class FirstPersonNavigationController implements NavigationController { return; } - this.feetPosition = locomotionStep.feetPosition; + const previousFeetPosition = this.feetPosition; + const edgeInputDirection = resolveClimbPlanarInputDirection( + inputState, + this.yawRadians + ); + const edgeAssist = + edgeInputDirection.direction !== null && + shouldAttemptPlayerEdgeAssist({ + enabled: playerMovement.edgeAssist.enabled, + pushToTopHeight: playerMovement.edgeAssist.pushToTopHeight, + inputMagnitude: locomotionStep.locomotionState.inputMagnitude, + requestedPlanarSpeed: + locomotionStep.locomotionState.requestedPlanarSpeed, + planarSpeed: locomotionStep.locomotionState.planarSpeed, + collisionCount: locomotionStep.locomotionState.contact.collisionCount, + airborne: locomotionStep.locomotionState.locomotionMode === "airborne" + }) + ? resolvePlayerEdgeAssistTopOut({ + feetPosition: locomotionStep.feetPosition, + shape: locomotionStep.activeShape, + direction: edgeInputDirection.direction, + pushToTopHeight: playerMovement.edgeAssist.pushToTopHeight, + canOccupyShape: (feetPosition, shape) => + this.context?.canOccupyPlayerShape?.(feetPosition, shape) ?? + true, + probeGround: (feetPosition, shape, maxDistance) => + this.context?.probePlayerGround?.( + feetPosition, + shape, + maxDistance + ) ?? { + grounded: false, + distance: null, + normal: null, + slopeDegrees: null + } + }) + : null; + const nextFeetPosition = + edgeAssist === null ? locomotionStep.feetPosition : edgeAssist.feetPosition; + const nextLocomotionState = + edgeAssist === null + ? locomotionStep.locomotionState + : { + ...locomotionStep.locomotionState, + locomotionMode: "grounded" as const, + airborneKind: null, + gait: "walk" as const, + grounded: true, + verticalVelocity: 0, + contact: { + ...locomotionStep.locomotionState.contact, + groundNormal: { x: 0, y: 1, z: 0 }, + groundDistance: 0, + slopeDegrees: 0 + } + }; + + this.feetPosition = nextFeetPosition; this.activePlayerShape = locomotionStep.activeShape; - this.verticalVelocity = locomotionStep.verticalVelocity; + this.verticalVelocity = + edgeAssist === null ? locomotionStep.verticalVelocity : 0; this.jumpBufferRemainingMs = locomotionStep.jumpBufferRemainingMs; this.coyoteTimeRemainingMs = locomotionStep.coyoteTimeRemainingMs; - this.jumpHoldRemainingMs = locomotionStep.jumpHoldRemainingMs; + this.jumpHoldRemainingMs = + edgeAssist === null ? locomotionStep.jumpHoldRemainingMs : 0; this.jumpPressed = locomotionStep.jumpPressed; this.latestJumpStarted = locomotionStep.jumpStarted; - this.latestHeadBump = locomotionStep.headBump; - this.locomotionState = locomotionStep.locomotionState; - this.previousPlanarDisplacement = locomotionStep.planarDisplacement; - this.grounded = locomotionStep.locomotionState.grounded; + this.latestHeadBump = edgeAssist === null ? locomotionStep.headBump : false; + this.locomotionState = nextLocomotionState; + this.previousPlanarDisplacement = + edgeAssist === null + ? locomotionStep.planarDisplacement + : { + x: this.feetPosition.x - previousFeetPosition.x, + y: 0, + z: this.feetPosition.z - previousFeetPosition.z + }; + this.grounded = nextLocomotionState.grounded; this.inWaterVolume = locomotionStep.inWaterVolume; this.inFogVolume = locomotionStep.inFogVolume; this.smoothedFeetY = smoothGroundedStairHeight({