using System; using System.Collections.Generic; using Cielonos.MainGame.Inventory; using Cielonos.MainGame.UI; using Sirenix.OdinInspector; using SLSUtilities.UI; using UniRx; using Unity.Cinemachine; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.Serialization; namespace Cielonos.MainGame.Characters { [RequireComponent(typeof(Player))] public partial class PlayerInputSubcontroller : SubcontrollerBase { public Player player => owner; public PlayerInput playerInput; public PlayerInputActions inputActions; public PlayerOperationSubcontroller operation; public Vector2 Move { get; private set; } public Vector2 Look { get; private set; } public bool JumpPressed { get; private set; } public bool JumpHeld { get; private set; } public bool IsMoving => Move != Vector2.zero; public bool IsWalking { get; private set; } public string CurrentScheme => playerInput.currentControlScheme; [ShowInInspector] public bool IsHoldingPrimary { get; private set; } [ShowInInspector] public bool IsHoldingSecondary { get; private set; } [ShowInInspector] public bool IsHoldingSpecialA { get; private set; } [ShowInInspector] public bool IsHoldingSpecialB { get; private set; } [ShowInInspector] public bool IsHoldingSpecialC { get; private set; } public BoolReactiveProperty isCursorLocked; public PlayerPreinputSubmodule preinputSubmodule; public override void Initialize() { base.Initialize(); playerInput = owner.GetComponent(); inputActions = new PlayerInputActions(); inputActions.Player.Enable(); operation = owner.operationSc; isCursorLocked = new BoolReactiveProperty(true); isCursorLocked.Subscribe(isLocked => { Cursor.lockState = isLocked ? CursorLockMode.Locked : CursorLockMode.None; Cursor.visible = !isLocked; Look = Vector2.zero; Move = Vector2.zero; // 同步禁用 Cinemachine 的自有输入控制器,防止 UI 打开时视角继续转动 var cinemachineInput = player.viewSc.freeLookCamera.GetComponent(); cinemachineInput.enabled = isLocked; }); player.inputSc.isCursorLocked.Value = false; preinputSubmodule = new PlayerPreinputSubmodule(this); InputBindingResolver.Initialize(inputActions.asset, "KeyboardMouse"); } private void Start() { RegisterActionsInputs(); RegisterMainWeaponInputs(); RegisterSupportEquipmentInputs(); RegisterFunctionInputs(); SceneManager.sceneLoaded += OnSceneLoaded; } private void Update() { if (isCursorLocked.Value) { Look = inputActions.Player.Look.ReadValue(); Move = inputActions.Player.Move.ReadValue().normalized; JumpPressed = inputActions.Player.Jump.WasPressedThisFrame(); JumpHeld = inputActions.Player.Jump.IsPressed(); } } private void OnDestroy() { inputActions.Disable(); inputActions.Dispose(); SceneManager.sceneLoaded -= OnSceneLoaded; } } public partial class PlayerInputSubcontroller { private void RegisterActionsInputs() { inputActions.Player.Interact.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { operation.Interact(); } }; inputActions.Player.Dash.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { if (IsMoving) { Vector3 inputDirection = new Vector3(Move.x, 0, Move.y); operation.Dash(inputDirection); preinputSubmodule.RegisterPreinputAction(() => operation.Dash(inputDirection), PlayerPreinputSubmodule.DashDodgePreinputPriority); } else { operation.Dodge(); preinputSubmodule.RegisterPreinputAction(() => operation.Dodge(), PlayerPreinputSubmodule.DashDodgePreinputPriority); } } }; inputActions.Player.LockonTarget.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { operation.LockonTarget(); } }; inputActions.Player.SelectLockonTarget.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { //Debug.Log("Value: " + ctx.ReadValue()); operation.SelectLockonTarget(ctx.ReadValue()); } }; inputActions.Player.Walk.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { IsWalking = true; operation.WalkPress(); } }; inputActions.Player.Walk.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { IsWalking = false; operation.WalkRelease(); } }; // 交互选项导航:滚轮向上 / ↑ = -1(向上),滚轮向下 / ↓ = +1(向下) // PassThrough + Axis 类型在松手/滚轮归零时也会触发 performed(raw = 0),需过滤 inputActions.Player.NavigateInteractionChoice.performed += ctx => { if (isCursorLocked.Value) { float raw = ctx.ReadValue(); if (Mathf.Approximately(raw, 0f)) return; int delta = raw > 0f ? -1 : 1; operation.NavigateInteractionChoice(delta); } }; } private MainWeaponBase currentMainWeapon => player.inventorySc.equipmentSm.currentMainWeapon; private List CaptureModifiers() { return InputModifier.Capture(IsHoldingSpecialA, IsHoldingSpecialB, IsHoldingSpecialC); } private void RegisterMainWeaponPreinput(PlayerEquipmentInputType inputType, List modifiers, Action action) { if (currentMainWeapon == null) return; var context = new PlayerEquipmentInputContext(inputType, modifiers); if (currentMainWeapon.TryGetPreinputPriority(context, out int priority)) { preinputSubmodule.RegisterPreinputAction(inputType.ToString(), action, priority); } } private void RegisterSupportEquipmentPreinput(int slotIndex, List modifiers, Action action) { SupportEquipmentBase equipment = GetSupportEquipment(slotIndex); if (equipment == null) return; PlayerEquipmentInputType inputType = slotIndex switch { 0 => PlayerEquipmentInputType.SupportEquipment0, 1 => PlayerEquipmentInputType.SupportEquipment1, 2 => PlayerEquipmentInputType.SupportEquipment2, 3 => PlayerEquipmentInputType.SupportEquipment3, _ => throw new ArgumentOutOfRangeException(nameof(slotIndex), slotIndex, null) }; var context = new PlayerEquipmentInputContext(inputType, modifiers, slotIndex); if (equipment.TryGetPreinputPriority(context, out int priority)) { preinputSubmodule.RegisterPreinputAction(inputType.ToString(), action, priority); } } private SupportEquipmentBase GetSupportEquipment(int slotIndex) { var equipments = player.inventorySc.equipmentSm.currentSupportEquipments; return equipments.Count > slotIndex ? equipments[slotIndex] : null; } private void RegisterMainWeaponInputs() { inputActions.Player.MainWeaponPrimary.started += ctx => { if (ctx.started && isCursorLocked.Value) { IsHoldingPrimary = true; List modifiers = CaptureModifiers(); operation.MainWeaponPrimaryPress(modifiers); RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponPrimary, modifiers, () => operation.MainWeaponPrimaryPress(modifiers)); } }; inputActions.Player.MainWeaponPrimary.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { IsHoldingPrimary = false; operation.MainWeaponPrimaryRelease(); } }; inputActions.Player.MainWeaponSecondary.started += ctx => { if (ctx.started && isCursorLocked.Value) { IsHoldingSecondary = true; List modifiers = CaptureModifiers(); operation.MainWeaponSecondaryPress(modifiers); RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponSecondary, modifiers, () => operation.MainWeaponSecondaryPress(modifiers)); } }; inputActions.Player.MainWeaponSecondary.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { IsHoldingSecondary = false; operation.MainWeaponSecondaryRelease(); } }; inputActions.Player.MainWeaponSpecialA.started += ctx => { if (ctx.started && isCursorLocked.Value) { IsHoldingSpecialA = true; List modifiers = CaptureModifiers(); operation.MainWeaponSpecialAPress(modifiers); RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponSpecialA, modifiers, () => operation.MainWeaponSpecialAPress(modifiers)); } }; inputActions.Player.MainWeaponSpecialA.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { IsHoldingSpecialA = false; operation.MainWeaponSpecialARelease(); } }; inputActions.Player.MainWeaponSpecialB.started += ctx => { if (ctx.started && isCursorLocked.Value) { IsHoldingSpecialB = true; List modifiers = CaptureModifiers(); operation.MainWeaponSpecialBPress(modifiers); RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponSpecialB, modifiers, () => operation.MainWeaponSpecialBPress(modifiers)); } }; inputActions.Player.MainWeaponSpecialB.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { IsHoldingSpecialB = false; operation.MainWeaponSpecialBRelease(); } }; inputActions.Player.MainWeaponSpecialC.started += ctx => { if (ctx.started && isCursorLocked.Value) { IsHoldingSpecialC = true; List modifiers = CaptureModifiers(); operation.MainWeaponSpecialCPress(modifiers); RegisterMainWeaponPreinput(PlayerEquipmentInputType.MainWeaponSpecialC, modifiers, () => operation.MainWeaponSpecialCPress(modifiers)); } }; inputActions.Player.MainWeaponSpecialC.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { IsHoldingSpecialC = false; operation.MainWeaponSpecialCRelease(); } }; inputActions.Player.SwitchPreviousMainWeapon.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { operation.SwitchMainWeapon(-1); } }; inputActions.Player.SwitchNextMainWeapon.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { operation.SwitchMainWeapon(1); } }; inputActions.Player.RouletteSwitchMainWeapon.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { operation.OpenMainWeaponRoulette(); } }; inputActions.Player.RouletteSwitchMainWeapon.canceled += ctx => { if (ctx.canceled) { operation.CloseMainWeaponRoulette(); } }; } private void RegisterSupportEquipmentInputs() { inputActions.Player.SupportEquipment0.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { List modifiers = CaptureModifiers(); operation.SupportEquipment0Press(modifiers); RegisterSupportEquipmentPreinput(0, modifiers, () => operation.SupportEquipment0Press(modifiers)); } }; inputActions.Player.SupportEquipment0.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { operation.SupportEquipment0Release(); } }; inputActions.Player.SupportEquipment1.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { List modifiers = CaptureModifiers(); operation.SupportEquipment1Press(modifiers); RegisterSupportEquipmentPreinput(1, modifiers, () => operation.SupportEquipment1Press(modifiers)); } }; inputActions.Player.SupportEquipment1.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { operation.SupportEquipment1Release(); } }; inputActions.Player.SupportEquipment2.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { List modifiers = CaptureModifiers(); operation.SupportEquipment2Press(modifiers); RegisterSupportEquipmentPreinput(2, modifiers, () => operation.SupportEquipment2Press(modifiers)); } }; inputActions.Player.SupportEquipment2.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { operation.SupportEquipment2Release(); } }; inputActions.Player.SupportEquipment3.performed += ctx => { if (ctx.performed && isCursorLocked.Value) { List modifiers = CaptureModifiers(); operation.SupportEquipment3Press(modifiers); RegisterSupportEquipmentPreinput(3, modifiers, () => operation.SupportEquipment3Press(modifiers)); } }; inputActions.Player.SupportEquipment3.canceled += ctx => { if (ctx.canceled && isCursorLocked.Value) { operation.SupportEquipment3Release(); } }; } private void RegisterFunctionInputs() { inputActions.Player.Inventory.performed += ctx => { var inventoryPage = PlayerCanvas.MainGamePages.inventoryPage; if (inventoryPage.IsOpen) { inventoryPage.Close(); } else { inventoryPage.Open(); } }; inputActions.Player.Map.performed += ctx => { var mapPage = PlayerCanvas.MainGamePages.mapPage; if (mapPage.IsOpen) mapPage.Close(); else mapPage.Open(); }; inputActions.Player.Escape.performed += ctx => { // 优先关闭栈顶页面(包括 Settings 覆盖在 Pause 之上的情况) if (UIPageManager.Instance != null && UIPageManager.Instance.HasOpenPages) { UIPageManager.Instance.CloseTopPage(); } else { PlayerCanvas.PauseUIPage.Open(); } }; } } public partial class PlayerInputSubcontroller { private void OnSceneLoaded(Scene a, LoadSceneMode b) { isCursorLocked.Value = true; } } }