using UnityEngine; using OctoCore.Components; using Unheimlich.Core; using Unheimlich.Features.Player.Data; using Unheimlich.Features.Dialogue; using Unheimlich.Core.Interaction; using Unheimlich.Features.DetectiveBoard; using Unheimlich.Features.Diapason; using Unheimlich.Features.OctoArms; using Unheimlich.World.CameraSystem; using InputManager = Unheimlich.Core.Input.InputManager; namespace Unheimlich.Features.Player { /// /// Central hub for all player systems. /// Exposes components and settings with zero Inspector refs needed for other scripts. /// [RequireComponent(typeof(OctoPlayer))] [RequireComponent(typeof(CharacterController))] public class PlayerController : Singleton { // Auto-found components (exposed publicly, found once in Awake) public OctoPlayer Movement { get; private set; } public CharacterController CharController { get; private set; } public Camera PlayerCamera { get; private set; } public Transform CameraTransform { get; private set; } public Transform CameraPivot { get; private set; } public CameraEffects CameraEffects { get; private set; } public CameraPanController CameraPanController { get; private set; } public DiapasonListeningHandlerV2 DiapasonHandler { get; private set; } public DiapasonEquipmentManager DiapasonEquipment { get; private set; } public PlayerInspectionHandler InspectionHandler { get; private set; } public DetectiveBoardController DetectiveBoardController { get; private set; } public OctoIkArmsImproved ArmsSystem { get; private set; } public InputManager Inputs => InputManager.Instance; // Cached sprint InputAction — resolved once in OnAwake to avoid per-frame foreach. private UnityEngine.InputSystem.InputAction _sprintAction; /// /// True when the character is physically moving (based on CharacterController velocity, /// not raw input — correctly synced with OctoPlayer's inertia). /// public bool IsMoving => CharController != null && CharController.velocity.magnitude > 0.1f; /// /// True while the sprint input is held and the player is moving. /// public bool IsRunning => _sprintAction != null && _sprintAction.IsPressed() && IsMoving; protected override void OnAwake() { // Auto-find all components once Movement = GetComponent(); CharController = GetComponent(); CameraEffects = GetComponent(); CameraPanController = GetComponent(); DiapasonHandler = GetComponent(); DiapasonEquipment = GetComponent(); InspectionHandler = GetComponent(); DetectiveBoardController = GetComponent(); PlayerCamera = GetComponentInChildren(); ArmsSystem = GetComponentInChildren(); if (PlayerCamera != null) { CameraTransform = PlayerCamera.transform; CameraPivot = CameraTransform.parent; } CacheSprintAction(); } /// /// Resolves the Sprint InputAction once from OctoCore to avoid per-frame foreach iteration. /// private void CacheSprintAction() { if (OctoCore.OctoCore.Instance?.Inputs?.Actions == null) return; foreach (var actionInfo in OctoCore.OctoCore.Instance.Inputs.Actions) { if (actionInfo.Name == "Sprint" && actionInfo.Reference != null) { _sprintAction = actionInfo.Reference.action; break; } } } // Teleport public void Teleport(Vector3 position, Quaternion rotation) { Movement.Teleport(position, rotation); PlayerEvents.TriggerTeleport(position, rotation); } // Helper methods public Vector3 GetForward() { if (PlayerCamera == null) return transform.forward; Vector3 forward = PlayerCamera.transform.forward; forward.y = 0; return forward.normalized; } public Vector3 GetRight() { if (PlayerCamera == null) return transform.right; Vector3 right = PlayerCamera.transform.right; right.y = 0; return right.normalized; } } }