using UnityEngine; using UnityEngine.InputSystem; using Unity.Netcode; using Colosseum.Skills; using Colosseum.Weapons; namespace Colosseum.Player { /// /// 플레이어 스킬 입력 처리. /// 논타겟 방식: 입력 시 즉시 스킬 시전 /// public class PlayerSkillInput : NetworkBehaviour { [Header("Skill Slots")] [Tooltip("각 슬롯에 등록할 스킬 데이터 (6개)")] [SerializeField] private SkillData[] skillSlots = new SkillData[6]; [Header("References")] [Tooltip("SkillController (없으면 자동 검색)")] [SerializeField] private SkillController skillController; [Tooltip("PlayerNetworkController (없으면 자동 검색)")] [SerializeField] private PlayerNetworkController networkController; [Tooltip("WeaponEquipment (없으면 자동 검색)")] [SerializeField] private WeaponEquipment weaponEquipment; private InputSystem_Actions inputActions; public SkillData[] SkillSlots => skillSlots; public override void OnNetworkSpawn() { if (!IsOwner) { enabled = false; return; } // SkillController 참조 확인 if (skillController == null) { skillController = GetComponent(); if (skillController == null) { Debug.LogError("PlayerSkillInput: SkillController not found!"); enabled = false; return; } } // PlayerNetworkController 참조 확인 if (networkController == null) { networkController = GetComponent(); } // WeaponEquipment 참조 확인 if (weaponEquipment == null) { weaponEquipment = GetComponent(); } InitializeInputActions(); } private void InitializeInputActions() { inputActions = new InputSystem_Actions(); inputActions.Player.Enable(); // 스킬 액션 콜백 등록 inputActions.Player.Skill1.performed += _ => OnSkillInput(0); inputActions.Player.Skill2.performed += _ => OnSkillInput(1); inputActions.Player.Skill3.performed += _ => OnSkillInput(2); inputActions.Player.Skill4.performed += _ => OnSkillInput(3); inputActions.Player.Skill5.performed += _ => OnSkillInput(4); inputActions.Player.Skill6.performed += _ => OnSkillInput(5); } public override void OnNetworkDespawn() { if (inputActions != null) { inputActions.Player.Skill1.performed -= _ => OnSkillInput(0); inputActions.Player.Skill2.performed -= _ => OnSkillInput(1); inputActions.Player.Skill3.performed -= _ => OnSkillInput(2); inputActions.Player.Skill4.performed -= _ => OnSkillInput(3); inputActions.Player.Skill5.performed -= _ => OnSkillInput(4); inputActions.Player.Skill6.performed -= _ => OnSkillInput(5); inputActions.Disable(); } } /// /// 스킬 입력 처리 /// private void OnSkillInput(int slotIndex) { if (slotIndex < 0 || slotIndex >= skillSlots.Length) return; SkillData skill = skillSlots[slotIndex]; if (skill == null) { Debug.Log($"Skill slot {slotIndex + 1} is empty"); return; } // 로컬 체크 (빠른 피드백용) if (skillController.IsExecutingSkill) { Debug.Log($"Already executing skill"); return; } if (skillController.IsOnCooldown(skill)) { Debug.Log($"Skill {skill.SkillName} is on cooldown"); return; } // 마나 비용 체크 (무기 배율 적용) float actualManaCost = GetActualManaCost(skill); if (networkController != null && networkController.Mana < actualManaCost) { Debug.Log($"Not enough mana for skill: {skill.SkillName}"); return; } // 서버에 스킬 실행 요청 RequestSkillExecutionRpc(slotIndex); } /// /// 서버에 스킬 실행 요청 /// [Rpc(SendTo.Server)] private void RequestSkillExecutionRpc(int slotIndex) { if (slotIndex < 0 || slotIndex >= skillSlots.Length) return; SkillData skill = skillSlots[slotIndex]; if (skill == null) return; // 서버에서 다시 검증 if (skillController.IsExecutingSkill || skillController.IsOnCooldown(skill)) return; // 마나 비용 체크 (무기 배율 적용) float actualManaCost = GetActualManaCost(skill); if (networkController != null && networkController.Mana < actualManaCost) return; // 마나 소모 (무기 배율 적용) if (networkController != null && actualManaCost > 0) { networkController.UseManaRpc(actualManaCost); } // 모든 클라이언트에 스킬 실행 전파 BroadcastSkillExecutionRpc(slotIndex); } /// /// 모든 클라이언트에 스킬 실행 전파 /// [Rpc(SendTo.ClientsAndHost)] private void BroadcastSkillExecutionRpc(int slotIndex) { if (slotIndex < 0 || slotIndex >= skillSlots.Length) return; SkillData skill = skillSlots[slotIndex]; if (skill == null) return; // 모든 클라이언트에서 스킬 실행 (애니메이션 포함) skillController.ExecuteSkill(skill); } /// /// 무기 마나 배율이 적용된 실제 마나 비용 계산 /// private float GetActualManaCost(SkillData skill) { if (skill == null) return 0f; float baseCost = skill.ManaCost; float multiplier = weaponEquipment != null ? weaponEquipment.ManaCostMultiplier : 1f; return baseCost * multiplier; } /// /// 스킬 슬롯 접근자 /// public SkillData GetSkill(int slotIndex) { if (slotIndex < 0 || slotIndex >= skillSlots.Length) return null; return skillSlots[slotIndex]; } /// /// 스킬 슬롯 변경 /// public void SetSkill(int slotIndex, SkillData skill) { if (slotIndex < 0 || slotIndex >= skillSlots.Length) return; skillSlots[slotIndex] = skill; } /// /// 남은 쿨타임 조회 /// public float GetRemainingCooldown(int slotIndex) { SkillData skill = GetSkill(slotIndex); if (skill == null) return 0f; return skillController.GetRemainingCooldown(skill); } /// /// 스킬 사용 가능 여부 /// public bool CanUseSkill(int slotIndex) { SkillData skill = GetSkill(slotIndex); if (skill == null) return false; return !skillController.IsOnCooldown(skill) && !skillController.IsExecutingSkill; } } }