140 lines
4.8 KiB
C#
140 lines
4.8 KiB
C#
using Unity.Netcode;
|
|
using Unity.Netcode.Components;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Northbound
|
|
{
|
|
/// <summary>
|
|
/// 상호작용 대상 없이 실행 가능한 액션들을 관리
|
|
/// </summary>
|
|
public class PlayerActionSystem : NetworkBehaviour
|
|
{
|
|
[Header("Actions")]
|
|
public List<MonoBehaviour> actionComponents = new List<MonoBehaviour>();
|
|
|
|
[Header("Animation")]
|
|
public bool playAnimations = true;
|
|
|
|
private Dictionary<string, IAction> _actions = new Dictionary<string, IAction>();
|
|
private Animator _animator;
|
|
private NetworkAnimator _networkAnimator;
|
|
private NetworkPlayerController _networkPlayerController;
|
|
private bool _isInputInitialized = false;
|
|
|
|
// 로컬 플레이어인지 확인
|
|
private bool IsLocalPlayer => _networkPlayerController != null && _networkPlayerController.IsLocalPlayer;
|
|
private ulong LocalPlayerId => _networkPlayerController != null ? _networkPlayerController.OwnerPlayerId : OwnerClientId;
|
|
|
|
private void Awake()
|
|
{
|
|
_animator = GetComponent<Animator>();
|
|
_networkAnimator = GetComponent<NetworkAnimator>();
|
|
_networkPlayerController = GetComponent<NetworkPlayerController>();
|
|
}
|
|
|
|
public override void OnNetworkSpawn()
|
|
{
|
|
// 액션 컴포넌트들을 딕셔너리에 등록 (모든 클라이언트에서)
|
|
foreach (var component in actionComponents)
|
|
{
|
|
if (component is IAction action)
|
|
{
|
|
_actions[action.GetActionName()] = action;
|
|
}
|
|
}
|
|
|
|
// _ownerPlayerId 변경 이벤트 구독
|
|
if (_networkPlayerController != null)
|
|
{
|
|
_networkPlayerController.OnOwnerChanged += OnOwnerPlayerIdChanged;
|
|
_networkPlayerController.OnInputInitialized += TryInitializeInput;
|
|
}
|
|
|
|
// 이미 로컬 플레이어면 입력 초기화
|
|
TryInitializeInput();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
// Start에서 다시 한번 확인 (이벤트 타이밍 문제 해결)
|
|
TryInitializeInput();
|
|
}
|
|
|
|
private void OnOwnerPlayerIdChanged(ulong newOwnerId)
|
|
{
|
|
TryInitializeInput();
|
|
}
|
|
|
|
private void TryInitializeInput()
|
|
{
|
|
if (!IsLocalPlayer) return;
|
|
if (_isInputInitialized) return; // 이미 초기화됨
|
|
if (_networkPlayerController.InputActions == null) return; // 아직 InputActions가 없음
|
|
|
|
_isInputInitialized = true;
|
|
_networkPlayerController.InputActions.Player.Attack.performed += OnAttack;
|
|
}
|
|
|
|
public override void OnNetworkDespawn()
|
|
{
|
|
if (_networkPlayerController != null)
|
|
{
|
|
_networkPlayerController.OnOwnerChanged -= OnOwnerPlayerIdChanged;
|
|
_networkPlayerController.OnInputInitialized -= TryInitializeInput;
|
|
|
|
// 입력 이벤트 해제
|
|
if (_networkPlayerController.InputActions != null)
|
|
{
|
|
_networkPlayerController.InputActions.Player.Attack.performed -= OnAttack;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnAttack(InputAction.CallbackContext context)
|
|
{
|
|
// UI가 열려있으면 액션 실행 안 함
|
|
if (UpgradeListPopup.IsOpen) return;
|
|
|
|
// 플레이어가 죽어있으면 액션 실행 안 함
|
|
if (_networkPlayerController != null && _networkPlayerController.IsDead()) return;
|
|
|
|
ExecuteAction("Attack");
|
|
}
|
|
|
|
public void ExecuteAction(string actionName)
|
|
{
|
|
if (_actions.TryGetValue(actionName, out IAction action))
|
|
{
|
|
if (action.CanExecute(LocalPlayerId))
|
|
{
|
|
string animTrigger = action.GetActionAnimation();
|
|
|
|
// 서버에서 애니메이션 실행 (동기화를 위해)
|
|
if (playAnimations && !string.IsNullOrEmpty(animTrigger))
|
|
{
|
|
PlayAnimationServerRpc(animTrigger);
|
|
}
|
|
|
|
action.Execute(LocalPlayerId);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Rpc(SendTo.Server)]
|
|
private void PlayAnimationServerRpc(string animTrigger)
|
|
{
|
|
if (_networkAnimator != null && !string.IsNullOrEmpty(animTrigger))
|
|
{
|
|
_networkAnimator.SetTrigger(animTrigger);
|
|
}
|
|
}
|
|
|
|
override public void OnDestroy()
|
|
{
|
|
// 입력 정리는 NetworkPlayerController에서 담당
|
|
base.OnDestroy();
|
|
}
|
|
}
|
|
} |