Merge remote-tracking branch 'origin/develop' into feat/mission-2

# Conflicts:
#	package-lock.json
#	package.json
#	src/App.tsx
#	src/components/three/interaction/CentralObject.tsx
#	src/components/three/interaction/VillageoisHelperObject.tsx
#	src/managers/GameStepManager.ts
#	src/stateManager/AudioManager.ts
#	src/world/World.tsx
#	src/world/player/PlayerController.tsx
This commit is contained in:
Tom Boullay
2026-05-11 17:46:42 +02:00
945 changed files with 26164 additions and 1569 deletions
+90 -52
View File
@@ -11,7 +11,7 @@ import {
MOVE_LEFT_KEY,
MOVE_RIGHT_KEY,
PRIMARY_INTERACT_MOUSE_BUTTON,
} from "@/data/keybindings";
} from "@/data/input/keybindings";
import {
PLAYER_ACCELERATION_MULTIPLIER,
PLAYER_AIR_CONTROL_FACTOR,
@@ -22,10 +22,13 @@ import {
PLAYER_MAX_DELTA,
PLAYER_WALK_SPEED,
PLAYER_XZ_DAMPING_FACTOR,
} from "@/data/playerConfig";
import { InteractionManager } from "@/stateManager/InteractionManager";
import { useGameStore } from "@/stores/gameStore";
import type { Vector3Tuple } from "@/types/3d";
} from "@/data/player/playerConfig";
import { useRepairMovementLocked } from "@/hooks/gameplay/useRepairMovementLocked";
import { InteractionManager } from "@/managers/InteractionManager";
import { useGameStore } from "@/managers/stores/useGameStore";
import { useMissionFlowStore } from "@/managers/stores/useMissionFlowStore";
import { useSettingsStore } from "@/managers/stores/useSettingsStore";
import type { Vector3Tuple } from "@/types/three/three";
type Keys = {
forward: boolean;
@@ -55,16 +58,44 @@ const _up = new THREE.Vector3(0, 1, 0);
const _translateVec = new THREE.Vector3();
const _collisionCorrection = new THREE.Vector3();
function isPlayerInputLocked(): boolean {
return (
useSettingsStore.getState().isSettingsMenuOpen ||
useGameStore.getState().isCinematicPlaying
);
}
function setMovementKey(keys: Keys, key: string, pressed: boolean): boolean {
switch (key.toLowerCase()) {
case MOVE_FORWARD_KEY:
keys.forward = pressed;
return true;
case MOVE_BACKWARD_KEY:
keys.backward = pressed;
return true;
case MOVE_LEFT_KEY:
keys.left = pressed;
return true;
case MOVE_RIGHT_KEY:
keys.right = pressed;
return true;
default:
return false;
}
}
export function PlayerController({
octree,
spawnPosition,
}: PlayerControllerProps): null {
const camera = useThree((state) => state.camera);
const movementLocked = useRepairMovementLocked();
const movementLockedRef = useRef(movementLocked);
const keys = useRef<Keys>({ ...DEFAULT_KEYS });
const velocity = useRef(new THREE.Vector3());
const onFloor = useRef(false);
const wantsJump = useRef(false);
const canMove = useGameStore((state) => state.canMove);
const canMove = useMissionFlowStore((state) => state.canMove);
const capsule = useRef(
new Capsule(
@@ -87,58 +118,61 @@ export function PlayerController({
camera.position.copy(capsule.current.end);
}, [camera, spawnPosition]);
useEffect(() => {
movementLockedRef.current = movementLocked;
if (!movementLocked) return;
keys.current = { ...DEFAULT_KEYS };
wantsJump.current = false;
velocity.current.setX(0);
velocity.current.setZ(0);
}, [movementLocked]);
useEffect(() => {
const interaction = InteractionManager.getInstance();
const handleKeyDown = (event: KeyboardEvent): void => {
switch (event.key.toLowerCase()) {
case MOVE_FORWARD_KEY:
keys.current.forward = true;
break;
case MOVE_BACKWARD_KEY:
keys.current.backward = true;
break;
case MOVE_LEFT_KEY:
keys.current.left = true;
break;
case MOVE_RIGHT_KEY:
keys.current.right = true;
break;
case JUMP_KEY:
wantsJump.current = true;
break;
case INTERACT_KEY:
if (interaction.getState().focused?.kind === "trigger") {
interaction.pressInteract();
}
break;
default:
return;
if (isPlayerInputLocked()) return;
if (setMovementKey(keys.current, event.key, true)) {
if (movementLockedRef.current) {
keys.current = { ...DEFAULT_KEYS };
}
event.preventDefault();
return;
}
if (event.key === JUMP_KEY) {
if (movementLockedRef.current) {
wantsJump.current = false;
event.preventDefault();
return;
}
wantsJump.current = true;
event.preventDefault();
return;
}
if (event.key.toLowerCase() === INTERACT_KEY) {
if (interaction.getState().focused?.kind === "trigger") {
interaction.pressInteract();
}
event.preventDefault();
}
event.preventDefault();
};
const handleKeyUp = (event: KeyboardEvent): void => {
switch (event.key.toLowerCase()) {
case MOVE_FORWARD_KEY:
keys.current.forward = false;
break;
case MOVE_BACKWARD_KEY:
keys.current.backward = false;
break;
case MOVE_LEFT_KEY:
keys.current.left = false;
break;
case MOVE_RIGHT_KEY:
keys.current.right = false;
break;
default:
return;
if (isPlayerInputLocked()) return;
if (setMovementKey(keys.current, event.key, false)) {
event.preventDefault();
}
event.preventDefault();
};
const handleMouseDown = (event: MouseEvent): void => {
if (isPlayerInputLocked()) return;
if (event.button !== PRIMARY_INTERACT_MOUSE_BUTTON) return;
if (interaction.getState().focused?.kind === "grab") {
interaction.pressInteract();
@@ -146,6 +180,7 @@ export function PlayerController({
};
const handleMouseUp = (event: MouseEvent): void => {
if (isPlayerInputLocked()) return;
if (event.button !== PRIMARY_INTERACT_MOUSE_BUTTON) return;
if (interaction.getState().holding) {
interaction.releaseInteract();
@@ -167,9 +202,10 @@ export function PlayerController({
}, []);
useFrame((_, delta) => {
if (!canMove) {
if (isPlayerInputLocked() || !canMove) {
keys.current = { ...DEFAULT_KEYS };
velocity.current.set(0, 0, 0);
camera.position.copy(capsule.current.end);
wantsJump.current = false;
return;
}
@@ -183,10 +219,12 @@ export function PlayerController({
}
_wishDir.set(0, 0, 0);
if (keys.current.forward) _wishDir.add(_forward);
if (keys.current.backward) _wishDir.sub(_forward);
if (keys.current.left) _wishDir.sub(_right);
if (keys.current.right) _wishDir.add(_right);
if (!movementLocked) {
if (keys.current.forward) _wishDir.add(_forward);
if (keys.current.backward) _wishDir.sub(_forward);
if (keys.current.left) _wishDir.sub(_right);
if (keys.current.right) _wishDir.add(_right);
}
if (_wishDir.lengthSq() > 0) _wishDir.normalize();
const accel = onFloor.current