import { describe, expect, it } from "vitest"; import { FIRST_PERSON_PLAYER_SHAPE } from "../../src/runtime-three/player-collision"; import { resolvePlayerLedgeGrabTarget, resolvePlayerEdgeAssistTopOut, shouldAttemptPlayerEdgeAssist } from "../../src/runtime-three/player-edge-assist"; describe("player edge assist", () => { it("only attempts edge assist for blocked airborne movement", () => { expect( shouldAttemptPlayerEdgeAssist({ enabled: true, pushToTopHeight: 0.55, inputMagnitude: 1, requestedPlanarSpeed: 4.5, planarSpeed: 0.2, collisionCount: 1, airborne: true }) ).toBe(true); expect( shouldAttemptPlayerEdgeAssist({ enabled: true, pushToTopHeight: 0.55, inputMagnitude: 1, requestedPlanarSpeed: 4.5, planarSpeed: 4.5, collisionCount: 0, airborne: true }) ).toBe(false); expect( shouldAttemptPlayerEdgeAssist({ enabled: true, pushToTopHeight: 0.55, inputMagnitude: 1, requestedPlanarSpeed: 4.5, planarSpeed: 0.2, collisionCount: 1, airborne: false }) ).toBe(false); }); it("resolves a forward and upward top-out candidate onto nearby ground", () => { const topY = 1.35; const result = resolvePlayerEdgeAssistTopOut({ feetPosition: { x: 0, y: 1, z: 0 }, shape: FIRST_PERSON_PLAYER_SHAPE, direction: { x: 0, y: 0, z: 1 }, pushToTopHeight: 0.55, canOccupyShape: (feetPosition) => feetPosition.y >= topY, probeGround: (feetPosition, _shape, maxDistance) => { const distance = feetPosition.y - topY; return distance >= 0 && distance <= maxDistance ? { grounded: true, distance, normal: { x: 0, y: 1, z: 0 }, slopeDegrees: 0 } : { grounded: false, distance: null, normal: null, slopeDegrees: null }; } }); expect(result).toMatchObject({ feetPosition: { y: topY } }); expect(result?.forwardDistance).toBeGreaterThan(0); expect(result?.lift).toBeCloseTo(0.35); }); it("does not top out onto ground that is not above the current feet", () => { const result = resolvePlayerEdgeAssistTopOut({ feetPosition: { x: 0, y: 1, z: 0 }, shape: FIRST_PERSON_PLAYER_SHAPE, direction: { x: 0, y: 0, z: 1 }, pushToTopHeight: 0.55, canOccupyShape: () => true, probeGround: (feetPosition) => ({ grounded: true, distance: feetPosition.y - 1, normal: { x: 0, y: 1, z: 0 }, slopeDegrees: 0 }) }); expect(result).toBeNull(); }); it("resolves an upper-body ledge grab target above push-to-top height", () => { const topY = 2; const result = resolvePlayerLedgeGrabTarget({ feetPosition: { x: 0, y: 1, z: 0 }, shape: FIRST_PERSON_PLAYER_SHAPE, direction: { x: 0, y: 0, z: 1 }, pushToTopHeight: 0.55, canOccupyShape: (feetPosition) => feetPosition.z <= 0.08 || feetPosition.y >= topY, probeGround: (feetPosition, _shape, maxDistance) => { const distance = feetPosition.y - topY; return feetPosition.z > 0.1 && distance >= 0 && distance <= maxDistance ? { grounded: true, distance, normal: { x: 0, y: 1, z: 0 }, slopeDegrees: 0 } : { grounded: false, distance: null, normal: null, slopeDegrees: null }; } }); expect(result).not.toBeNull(); expect(result?.standFeetPosition.y).toBeCloseTo(topY); expect(result?.hangFeetPosition.y).toBeLessThan( result?.standFeetPosition.y ?? 0 ); expect(result?.topOutHeight).toBeGreaterThan(0.55); expect(result?.forwardDistance).toBeGreaterThan(0); }); it("does not turn the push-to-top height band into a ledge grab", () => { const topY = 1.35; const result = resolvePlayerLedgeGrabTarget({ feetPosition: { x: 0, y: 1, z: 0 }, shape: FIRST_PERSON_PLAYER_SHAPE, direction: { x: 0, y: 0, z: 1 }, pushToTopHeight: 0.55, canOccupyShape: () => true, probeGround: (feetPosition, _shape, maxDistance) => { const distance = feetPosition.y - topY; return distance >= 0 && distance <= maxDistance ? { grounded: true, distance, normal: { x: 0, y: 1, z: 0 }, slopeDegrees: 0 } : { grounded: false, distance: null, normal: null, slopeDegrees: null }; } }); expect(result).toBeNull(); }); });