Add player controller telemetry functionality
This commit is contained in:
152
src/runtime-three/player-controller-telemetry.ts
Normal file
152
src/runtime-three/player-controller-telemetry.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import type {
|
||||
PlayerControllerTelemetry,
|
||||
RuntimeLocomotionState,
|
||||
RuntimeMovementTransitionSignals,
|
||||
RuntimePlayerMovementHooks
|
||||
} from "./navigation-controller";
|
||||
|
||||
const MOVING_SPEED_EPSILON = 0.05;
|
||||
|
||||
function hasWallContact(locomotionState: RuntimeLocomotionState | null): boolean {
|
||||
if (locomotionState === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
locomotionState.contact.collidedAxes.x ||
|
||||
locomotionState.contact.collidedAxes.z
|
||||
);
|
||||
}
|
||||
|
||||
export function createEmptyRuntimeMovementTransitionSignals(): RuntimeMovementTransitionSignals {
|
||||
return {
|
||||
jumpStarted: false,
|
||||
leftGround: false,
|
||||
startedFalling: false,
|
||||
landed: false,
|
||||
enteredWater: false,
|
||||
exitedWater: false,
|
||||
wallContactStarted: false,
|
||||
headBump: false
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveRuntimeMovementTransitionSignals(options: {
|
||||
previousLocomotionState: RuntimeLocomotionState | null;
|
||||
previousInWaterVolume: boolean;
|
||||
locomotionState: RuntimeLocomotionState;
|
||||
inWaterVolume: boolean;
|
||||
jumpStarted: boolean;
|
||||
headBump: boolean;
|
||||
}): RuntimeMovementTransitionSignals {
|
||||
const previousGrounded = options.previousLocomotionState?.grounded ?? false;
|
||||
const previousAirborneKind = options.previousLocomotionState?.airborneKind;
|
||||
const previousWallContact = hasWallContact(options.previousLocomotionState);
|
||||
const wallContact = hasWallContact(options.locomotionState);
|
||||
|
||||
return {
|
||||
jumpStarted: options.jumpStarted,
|
||||
leftGround: previousGrounded && !options.locomotionState.grounded,
|
||||
startedFalling:
|
||||
options.locomotionState.airborneKind === "falling" &&
|
||||
previousAirborneKind !== "falling",
|
||||
landed: !previousGrounded && options.locomotionState.grounded,
|
||||
enteredWater: !options.previousInWaterVolume && options.inWaterVolume,
|
||||
exitedWater: options.previousInWaterVolume && !options.inWaterVolume,
|
||||
wallContactStarted: !previousWallContact && wallContact,
|
||||
headBump: options.headBump
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveRuntimePlayerMovementHooks(options: {
|
||||
locomotionState: RuntimeLocomotionState;
|
||||
inWaterVolume: boolean;
|
||||
cameraSubmerged: boolean;
|
||||
signals: RuntimeMovementTransitionSignals;
|
||||
}): RuntimePlayerMovementHooks {
|
||||
const underwaterAmount = options.cameraSubmerged
|
||||
? 1
|
||||
: options.inWaterVolume
|
||||
? 0.55
|
||||
: 0;
|
||||
|
||||
return {
|
||||
camera: {
|
||||
jumping:
|
||||
options.signals.jumpStarted ||
|
||||
options.locomotionState.airborneKind === "jumping",
|
||||
falling:
|
||||
options.signals.startedFalling ||
|
||||
options.locomotionState.airborneKind === "falling",
|
||||
landing: options.signals.landed,
|
||||
swimming: options.locomotionState.locomotionMode === "swimming",
|
||||
underwaterAmount
|
||||
},
|
||||
audio: {
|
||||
underwaterAmount,
|
||||
enteredWater: options.signals.enteredWater,
|
||||
exitedWater: options.signals.exitedWater
|
||||
},
|
||||
animation: {
|
||||
locomotionMode: options.locomotionState.locomotionMode,
|
||||
airborneKind: options.locomotionState.airborneKind,
|
||||
gait: options.locomotionState.gait,
|
||||
moving: options.locomotionState.planarSpeed > MOVING_SPEED_EPSILON,
|
||||
movementAmount: Math.max(
|
||||
options.locomotionState.inputMagnitude,
|
||||
Math.min(1, options.locomotionState.planarSpeed)
|
||||
),
|
||||
grounded: options.locomotionState.grounded,
|
||||
crouched: options.locomotionState.crouched,
|
||||
sprinting: options.locomotionState.sprinting,
|
||||
inWater: options.inWaterVolume,
|
||||
signals: options.signals
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createPlayerControllerTelemetry(options: {
|
||||
feetPosition: PlayerControllerTelemetry["feetPosition"];
|
||||
eyePosition: PlayerControllerTelemetry["eyePosition"];
|
||||
grounded: boolean;
|
||||
locomotionState: RuntimeLocomotionState;
|
||||
movement: PlayerControllerTelemetry["movement"];
|
||||
inWaterVolume: boolean;
|
||||
cameraSubmerged: boolean;
|
||||
inFogVolume: boolean;
|
||||
pointerLocked: boolean;
|
||||
spawn: PlayerControllerTelemetry["spawn"];
|
||||
previousLocomotionState: RuntimeLocomotionState | null;
|
||||
previousInWaterVolume: boolean;
|
||||
jumpStarted: boolean;
|
||||
headBump: boolean;
|
||||
}): PlayerControllerTelemetry {
|
||||
const signals = resolveRuntimeMovementTransitionSignals({
|
||||
previousLocomotionState: options.previousLocomotionState,
|
||||
previousInWaterVolume: options.previousInWaterVolume,
|
||||
locomotionState: options.locomotionState,
|
||||
inWaterVolume: options.inWaterVolume,
|
||||
jumpStarted: options.jumpStarted,
|
||||
headBump: options.headBump
|
||||
});
|
||||
|
||||
return {
|
||||
feetPosition: options.feetPosition,
|
||||
eyePosition: options.eyePosition,
|
||||
grounded: options.grounded,
|
||||
locomotionState: options.locomotionState,
|
||||
movement: options.movement,
|
||||
inWaterVolume: options.inWaterVolume,
|
||||
cameraSubmerged: options.cameraSubmerged,
|
||||
inFogVolume: options.inFogVolume,
|
||||
pointerLocked: options.pointerLocked,
|
||||
spawn: options.spawn,
|
||||
signals,
|
||||
hooks: resolveRuntimePlayerMovementHooks({
|
||||
locomotionState: options.locomotionState,
|
||||
inWaterVolume: options.inWaterVolume,
|
||||
cameraSubmerged: options.cameraSubmerged,
|
||||
signals
|
||||
})
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user