/**
 * Drives a first-person camera + body from intent fields. See sibling
 * DESIGN.md for goals, architecture, and the five processing layers (L0..L4).
 *
 * - fixedUpdate runs L1 (locomotion), L2 (pose state), and L4 (events) so
 *   the simulation remains deterministic.
 * - update runs L3 (camera composition) at render rate so the eye is never
 *   smoother than the screen.
 *
 * The system itself integrates a simple flat-floor at y = `config.gravity.magnitude > 0
 * ? state.groundY : -Infinity` for the prototype. A real physics layer should
 * write `state.grounded`/`state.groundNormal` from outside instead; the
 * built-in resolver is just a convenience to keep the controller usable
 * without dependencies.
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export class FirstPersonPlayerControllerSystem extends System<any, any, any, any, any> {
    constructor();
    dependencies: (typeof Transform | typeof FirstPersonPlayerController)[];
    components_used: (ResourceAccessSpecification<typeof RigidBody> | ResourceAccessSpecification<typeof Transform> | ResourceAccessSpecification<typeof Camera>)[];
    /**
     * Per-entity runtime, keyed by entity id.
     * @type {Map<number, PerEntityRuntime>}
     */
    runtime: Map<number, PerEntityRuntime>;
    /**
     * If true, the system clamps body y >= groundY and writes
     * state.grounded itself. Turn off when wiring a real physics layer.
     * @type {boolean}
     */
    useBuiltInFlatGround: boolean;
    /**
     * The flat-ground y for the built-in resolver. Ignored when
     * useBuiltInFlatGround is false.
     * @type {number}
     */
    groundY: number;
    /**
     * Optional callback that returns the surface Y under the player
     * for ground resolution. Called each tick with the player's
     * current (x, y, z); returns the world-Y of the ground below,
     * or null if no ground is below (gap / void).
     *
     * Combines with `useBuiltInFlatGround`: the effective ground for
     * the tick is `max(this.groundY when enabled, resolver(...))`.
     * Set both off (`useBuiltInFlatGround=false`, `groundResolver=null`)
     * to defer to external physics entirely.
     *
     * Designed for prototypes / gyms that need elevated platforms
     * without a full physics layer. Production should wire a real
     * physics system instead.
     *
     * @type {((x:number, y:number, z:number) => number|null) | null}
     */
    groundResolver: (x: number, y: number, z: number) => number | null;
    /**
     * PhysicsSystem reference. Auto-acquired at startup; can be
     * overridden by the caller. When present, collision is resolved
     * by the {@link KinematicMover}; when null, the controller uses
     * the flat-ground integrator ({@link _moveFlatGround}) — useful
     * for spec setups that don't wire physics.
     * @type {PhysicsSystem|null}
     */
    physicsSystem: PhysicsSystem | null;
    /**
     * The collision solver — the authoritative move resolver whenever
     * a {@link PhysicsSystem} is present (recover + unified
     * sweep-and-slide + ground-categorize; see DESIGN_COLLISION.md).
     * Lazily built on first use. With no physics the controller falls
     * back to a flat-ground integrator ({@link _moveFlatGround}).
     * @private
     * @type {KinematicMover|null}
     */
    private _mover;
    /** @private Scratch velocity handed to the mover each tick. */
    private _moverVelocity;
    /** @private Scratch for the posture-headroom up-cast. */
    private _postureRay;
    /** @private @type {PhysicsSurfacePoint} */
    private _postureHit;
    startup(entityManager: any): Promise<void>;
    /**
     * @param {FirstPersonPlayerController} controller
     * @param {Transform} bodyTransform
     * @param {number} entity
     */
    link(controller: FirstPersonPlayerController, bodyTransform: Transform, entity: number): void;
    /**
     * @param {FirstPersonPlayerController} controller
     * @param {Transform} bodyTransform
     * @param {number} entity
     */
    unlink(controller: FirstPersonPlayerController, bodyTransform: Transform, entity: number): void;
    /**
     * Look up the per-entity runtime for an entity that has this
     * controller. Used by cross-system code (sensors system, future
     * ability-driven systems) to reach internal state without leaking
     * it onto the controller component itself.
     *
     * @param {number} entity
     * @returns {PerEntityRuntime|undefined}  undefined if entity is not linked
     */
    getRuntime(entity: number): PerEntityRuntime | undefined;
    _currentDt: number;
    _currentRenderDt: number;
    /**
     * @private
     * @param {FirstPersonPlayerController} controller
     * @param {number} entity
     */
    private _tickEntity;
    /**
     * @private
     * @param {FirstPersonPlayerController} controller
     * @param {PerEntityRuntime} runtime
     * @returns {boolean}
     */
    /**
     * Swap {@link Collider.shape} to the pre-built capsule that matches
     * the player's current posture. Cheap — just a reference swap when
     * the posture changed, no-op otherwise. The pre-built shapes live
     * on the runtime (see {@link PerEntityRuntime.colliderShapeStand}
     * etc.) so this method allocates nothing per tick.
     *
     * Hang posture reuses Stand: the player's body is full-extent,
     * hanging below the ledge — the rig handles the arms-up animation,
     * but the collision volume is unchanged. If a game ever wants a
     * narrower hang silhouette (e.g. wedging into a chimney) it can
     * add a `colliderShapeHang` and route here.
     *
     * @private
     */
    private _syncColliderShape;
    _resolveCrouchHeld(controller: any, runtime: any, bodyTransform: any): any;
    /**
     * Headroom probe for a posture change that GROWS the collider.
     * Sweeps `fromShape` (the shorter posture's capsule) straight up by
     * `growDelta` (the height the collider would gain). A hit means an
     * overhang occupies the space the taller posture needs, so the grow
     * is blocked. Returns true (clear) when no physics is wired or the
     * grow is non-positive.
     *
     * Why an up-cast rather than an overlap-test of the taller shape:
     * overlap would false-positive on a wall *beside* the player. The
     * up-cast sweeps parallel to (and, per the mover's skin clearance,
     * clear of) lateral walls so they aren't hit; the floor is below
     * the rising probe; the player's own body is filtered out. Only
     * genuine overhead geometry blocks the grow. Relies on the player
     * resting at `floor+skin` (the mover's stick-to-ground), so the
     * probe's bottom starts clear of the floor.
     *
     * @private
     */
    private _hasHeadroomToGrow;
    /**
     * Jump finite-state-machine: button-edge detection, buffer + coyote
     * grace, anticipation timer, impulse on completion. Variable-height
     * cut is captured here as a `state.isVariableJumpCut` flag that the
     * gravity step in `_integrateVerticalAndResolveGround` consumes.
     *
     * @private
     * @param {FirstPersonPlayerController} controller
     * @param {PerEntityRuntime} runtime
     * @param {Transform} bodyTransform
     * @param {number} dt
     */
    private _advanceJumpFsm;
    /**
     * The vertical + collision phase of one fixed step: apply gravity
     * (the motor), resolve the move against the world, then detect the
     * jump apex. Collision resolution is the {@link KinematicMover} when
     * a physics layer is present; otherwise a lightweight flat-ground
     * integrator for headless / unit-test scenes with no collidable
     * geometry. Land / leave-ground events flow identically from either.
     *
     * @private
     * @param {FirstPersonPlayerController} controller
     * @param {PerEntityRuntime} runtime
     * @param {Transform} bodyTransform
     * @param {number} dt
     */
    private _integrateVerticalAndResolveGround;
    /**
     * Resolve the current `runtime.velocity*` against the world — the
     * physics-backed {@link KinematicMover} (recover + sweep-and-slide +
     * ground-categorize) when a PhysicsSystem is present, else the no-physics
     * flat-ground fallback. Gravity is NOT applied here: the standard path
     * applies it in {@link _applyGravity} just before, and abilities with a
     * non-standard vertical model (WallRun's reduced gravity) apply their own
     * and then call this directly — so motion routes through one motor for
     * everyone (sweep-and-slide, anti-tunnel, land/leave events) rather than
     * a bespoke `position._add` + hand-rolled ground-catch.
     * @private
     */
    private _resolveMotion;
    /**
     * Motor: integrate gravity into `velocityY` with the fall / variable-
     * cut multipliers. The mover never invents motion, so gravity lives
     * here (callable by abilities that want standard gravity too).
     * @private
     */
    private _applyGravity;
    /**
     * Resolve the move against the world via {@link KinematicMover}
     * (recover + unified sweep-and-slide + ground-categorize), then map
     * the result back to controller state and land / leave events.
     * @private
     */
    private _moveViaMover;
    /**
     * No-physics fallback: integrate the velocity directly (there's no
     * collidable geometry to sweep against) and resolve the floor from
     * the built-in flat ground and/or the host `groundResolver`. For
     * headless scenes and control-layer unit tests. With both ground
     * sources off, an external physics layer is expected to own
     * `state.grounded`; we only advance timers.
     * @private
     */
    private _moveFlatGround;
    /**
     * Landing transition: dip / impact springs, exertion impulse, flag
     * resets, and the `onLand` signal (fired LAST so handlers see fully-
     * reacted state). Shared by both move paths. `impactVy` is the
     * downward speed at touchdown (positive).
     * @private
     */
    private _onLand;
    /**
     * Leave-ground transition: `onLeaveGround` signal + takeoff bookkeeping.
     * Shared by both move paths.
     * @private
     */
    private _onLeaveGround;
    /**
     * Fire `onJumpApex` once, when an in-progress jump stops rising.
     * @private
     */
    private _detectJumpApex;
    /**
     * Run the base (no-ability) L1 locomotion phases: speed selection,
     * desired-velocity computation, accel/decel, jump FSM, gravity, body
     * integration, ground resolution. Only invoked when no ability owns
     * the tick (see {@link AbilitySet.tick}).
     *
     * @private
     * @param {FirstPersonPlayerController} controller
     * @param {PerEntityRuntime} runtime
     * @param {Transform} bodyTransform
     * @param {number} dt
     * @param {boolean} isCrouchActive
     * @param {boolean} isSprintIntent
     * @param {boolean} isBackwardIntent
     */
    private _runBaseLocomotion;
    /**
     * Compute the natural camera lean for this tick: lat-accel-driven
     * roll into a turn, plus a yaw-rate look-lean contribution, both
     * clamped. The result is the target the lean spring chases each
     * tick when no ability has opinions.
     *
     * Pure-ish helper — reads `controller`, `runtime`, `dt`; returns a
     * number. Extracted so both base and any future ability that wants
     * to compose its lean on top of the natural value can call it.
     *
     * @private
     * @param {FirstPersonPlayerController} controller
     * @param {PerEntityRuntime} runtime
     * @param {number} dt
     * @returns {number} target roll in radians
     */
    private _computeNaturalLeanTarget;
    /**
     * Snapshot the per-tick "what is the body doing" information into the
     * pose channels for downstream consumption (skeleton, sound, AI).
     * Read-only with respect to controller state — this is purely a publish
     * step.
     *
     * @private
     * @param {FirstPersonPlayerController} controller
     * @param {PerEntityRuntime} runtime
     * @param {Transform} bodyTransform
     */
    private _publishPose;
    /**
     * Compose the eye transform from body + state-driven offsets.
     * @private
     * @param {FirstPersonPlayerController} controller
     * @param {number} entity
     */
    private _composeEye;
}
import { System } from "../../ecs/System.js";
import { Transform } from "../../ecs/transform/Transform.js";
import { FirstPersonPlayerController } from "./FirstPersonPlayerController.js";
import { RigidBody } from "../../physics/ecs/RigidBody.js";
import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js";
import { Camera } from "../../graphics/ecs/camera/Camera.js";
/**
 * Per-entity runtime state the system maintains internally — too transient
 * even for {@link FirstPersonPlayerController}'s `state` member, because it
 * encodes input-edge bookkeeping and timer values the public surface should
 * never see directly.
 */
declare class PerEntityRuntime {
    /**
     * Co-attached kinematic body. Set by {@link FirstPersonPlayerControllerSystem.link}
     * after asserting it's present. The controller writes Transform.position
     * directly (existing motion logic); physics derives the body's velocity
     * from the per-step delta. Other physics systems (raycasts, contact
     * events) see the player through this body.
     * @type {RigidBody|null}
     */
    rigidBody: RigidBody | null;
    /**
     * Co-attached collider, cached at link. Same source the physics
     * narrowphase uses, so move-and-slide casts the player's
     * actual collision shape against the world.
     * @type {Collider|null}
     */
    collider: Collider | null;
    /**
     * Pre-built capsule colliders, one per posture. Cached at link
     * from `config.body.{height, crouchHeight, proneHeight, radius}`
     * so {@link _syncColliderShape} can swap the collider's shape on
     * a posture change with zero per-tick allocation. Hang reuses
     * Stand (the player's body is full-extent, just hanging below
     * the ledge — the rig animates the arms-up pose). Sentinel
     * `lastPosture = -1` forces a sync on the first tick after
     * link, so the initial shape always matches Stand.
     * @private
     * @type {TransformedShape3D|null}
     */
    private colliderShapeStand;
    /** @private @type {TransformedShape3D|null} */
    private colliderShapeCrouch;
    /** @private @type {TransformedShape3D|null} */
    private colliderShapeProne;
    /** @private */
    private lastPosture;
    /** Eye pitch in radians, clamped to config.look limits. */
    eyePitch: number;
    /** Body yaw in radians (around world up). */
    bodyYaw: number;
    /** Yaw rate (rad/s) computed in look consumption — for evaluators. */
    yawRateRadPerSec: number;
    /** Horizontal+vertical velocity. We integrate these inside the system
     *  when no external physics layer is attached. */
    velocityX: number;
    velocityY: number;
    velocityZ: number;
    /** Previous-tick jump intent — for rising/falling edge detection. */
    prevJumpHeld: boolean;
    /** Previous-tick crouch intent — for toggle-mode edge detection. */
    prevCrouchHeld: boolean;
    /** True while crouch toggle is latched on (used only in toggle mode). */
    crouchLatched: boolean;
    /** Remaining time in jump anticipation, or <= 0 if not anticipating. */
    anticipationRemaining: number;
    /** Cached derived gravity (m/s^2) from peakHeight + timeToApex. */
    gravity: number;
    /** Cached derived jump impulse (m/s upward), post-mass-scaling. */
    jumpInitialVy: number;
    /**
     * Cached mass scaling factors — computed once at link. See
     * {@link computeMassRatios}. Heavier ⇒ lower jumpV0Scale, lower
     * groundAccelScale, higher landingDipScale + exertionRiseScale.
     */
    massRatios: any;
    /** Spring for landing dip (under-damped → rings after impact). */
    landSpring: Spring;
    /** Spring for FOV (critically damped). */
    fovSpring: Spring;
    /** Spring for eye height (crouch transition). */
    eyeHeightSpring: Spring;
    /** Spring for lean roll (radians) — banks into lateral acceleration. */
    leanSpring: Spring;
    /**
     * Lean target this tick (radians). Always set; L2.f spring-steps
     * toward this value. Whoever owned motion this tick wrote it:
     * base writes the lat-accel + look-lean derived value at the end
     * of {@link _runBaseLocomotion}; abilities that want to override
     * (WallRun → tilt-into-wall, Slide/Mantle/LedgeGrab → zero) write
     * their own value in tick. Uniform channel — no null sentinel.
     */
    leanTargetRad: number;
    /** Previous horizontal velocity — for lateral acceleration → lean. */
    prevVelocityX: number;
    prevVelocityZ: number;
    /** Previous-tick grounded for edge detection. */
    prevGrounded: boolean;
    /** Vertical speed at moment of last "leave ground". */
    takeoffVy: number;
    /** Max vertical position since last takeoff — for jump apex detection. */
    peakAltitude: number;
    /** Set true once a jump has been launched; cleared on land. */
    midJump: boolean;
    /** Apex already fired for this airborne segment? */
    apexFired: boolean;
    /** Stride phase from previous fixed step — for footstep edge detection. */
    prevStridePhase: number;
    /** Breath phase from previous fixed step — for inhale/exhale edge detection. */
    prevBreathPhase: number;
    /** Which foot fires next — flipped on each footstep signal. */
    nextFootSide: string;
    /**
     * Which foot is currently bearing the body's weight (the foot that
     * most recently landed). Drives the lateral-bob direction: at R
     * midstance the COM is over the right foot, so the head shifts
     * laterally toward screen-right; at L midstance the opposite.
     * Coupled to the same signal the footstep emits, so anything that
     * listens to onFootStep.side will see the bob agree.
     * Initialized "L" so the very first footstep fires "R" and the
     * standingFoot updates to "R" — putting the head laterally right
     * during the first half-stride, as expected.
     */
    standingFoot: string;
    /**
     * [0..1] How "backward" the player is currently moving. Derived in
     * fixedUpdate from velocity · screen-forward, normalized to sprint
     * speed. Drives the gait wobble amplifier on the L3 camera-composition
     * pass. Stored on runtime (rather than state) because it's a render-
     * side input — downstream observers should look at velocity directly.
     */
    backwardness: number;
    /**
     * Smoothed bob amplitude envelope. Target = max(speedNormalized,
     * backwardness) when grounded, 0 airborne. Spring decay prevents
     * the whiplash where stopping motion would snap the bob to neutral.
     */
    bobIntensitySpring: Spring;
    /**
     * Vertical impact spring — kicked downward at each footfall, decays
     * with a slight under-damped overshoot. Produces the impact-arrest +
     * leg-push curve. value units: meters (added directly to eyeLocal.y).
     */
    verticalImpactSpring: Spring;
    /**
     * Sprint-posture spring — eye pitches forward as the player commits
     * to a sprint, returns to neutral when they slow. Value is in
     * radians; slower half-life than other springs so it feels like
     * a posture change rather than an input twitch. See cfg.posture.
     */
    sprintPostureSpring: Spring;
    /**
     * Head-droop spring — additional forward pitch as exertion rises.
     * Sells fatigue subtly. Target tracks exertion-driven max droop
     * angle; spring lag keeps the transition slow and physical.
     */
    headDroopSpring: Spring;
    /**
     * [0..1] sprintness — how much of the walk→sprint speed range the
     * body is currently in. Computed in fixedUpdate, read by L3 for FOV
     * and the sprint-posture pitch / forward-shift offset.
     */
    sprintness: number;
    /**
     * Cached sin/cos of current body yaw — written once per fixedUpdate
     * after look intent is consumed, read by every downstream step
     * (locomotion, backwardness, lean look-rate, pose channels). Avoids
     * recomputing the trig 3+ times per tick.
     */
    sinYaw: number;
    cosYaw: number;
    /** Cached horizontal speed (m/s) for this tick — written in derived-state. */
    horizSpeed: number;
    /** Cached stride frequency (Hz) for this tick — written in breath block, read by stride. */
    strideFreqHz: number;
    /**
     * Additive accumulator for body-local eye-position offsets. The
     * system pushes its own contributions (bob, breath, landing,
     * sprint posture) each render frame; external systems can push
     * recoil/shake/knockback contributions via the same interface.
     */
    eyeOffsetStack: EyeOffsetStack;
    /**
     * Spatial-query results populated by {@link FirstPersonSensorsSystem}
     * (when present). Abilities and the locomotion FSM read this.
     * Lives on runtime so other systems can populate it without
     * touching the controller component's public surface.
     */
    sensors: FirstPersonSensors;
    /** Cached eye entity ID. -1 until link assigns it. */
    eyeEntity: number;
}
import { PhysicsSystem } from "../../physics/ecs/PhysicsSystem.js";
import { Collider } from "../../physics/ecs/Collider.js";
import { Spring } from "./math/Spring.js";
import { EyeOffsetStack } from "./composer/EyeOffsetStack.js";
import { FirstPersonSensors } from "./sensors/FirstPersonSensors.js";
export {};
//# sourceMappingURL=FirstPersonPlayerControllerSystem.d.ts.map