This commit is contained in:
BoyongHwang
2026-02-26 03:18:35 +09:00
4 changed files with 126 additions and 65 deletions

View File

@@ -34,7 +34,6 @@ namespace Northbound
private int currentRotation = 0; // 0-3 private int currentRotation = 0; // 0-3
private Material[] originalMaterials; private Material[] originalMaterials;
private Renderer[] previewRenderers; private Renderer[] previewRenderers;
private PlayerInputActions _inputActions;
// 드래그 건설 관련 // 드래그 건설 관련
private bool isDragging = false; private bool isDragging = false;
@@ -53,35 +52,35 @@ namespace Northbound
{ {
_playerController = GetComponent<NetworkPlayerController>(); _playerController = GetComponent<NetworkPlayerController>();
// 지연 초기화 - 다음 프레임에 체크 if (_playerController != null)
StartCoroutine(InitializeAfterOwnerSet()); {
_playerController.OnInputInitialized += TryInitializeInput;
} }
private System.Collections.IEnumerator InitializeAfterOwnerSet() // 이미 로컬 플레이어면 입력 초기화 시도
{ TryInitializeInput();
// _ownerPlayerId가 설정될 때까지 대기 (최대 1초)
float timeout = 1f;
while (_playerController != null && _playerController.OwnerPlayerId == ulong.MaxValue && timeout > 0)
{
yield return null;
timeout -= Time.deltaTime;
} }
// 로컬 플레이어인지 확인 private void Start()
if (_playerController == null || !_playerController.IsLocalPlayer)
{ {
yield break; // Start에서 다시 한번 확인 (이벤트 타이밍 문제 해결)
TryInitializeInput();
} }
private void TryInitializeInput()
{
if (_isInitialized) return; // 이미 초기화됨
if (_playerController == null || !_playerController.IsLocalPlayer) return;
if (_playerController.InputActions == null) return;
_isInitialized = true; _isInitialized = true;
_inputActions = new PlayerInputActions(); var inputActions = _playerController.InputActions;
_inputActions.Player.ToggleBuildMode.performed += OnToggleBuildMode; inputActions.Player.ToggleBuildMode.performed += OnToggleBuildMode;
_inputActions.Player.Rotate.performed += OnRotate; inputActions.Player.Rotate.performed += OnRotate;
_inputActions.Player.Build.performed += OnBuildPressed; inputActions.Player.Build.performed += OnBuildPressed;
_inputActions.Player.Build.canceled += OnBuildReleased; inputActions.Player.Build.canceled += OnBuildReleased;
_inputActions.Player.Cancel.performed += OnCancel; inputActions.Player.Cancel.performed += OnCancel;
_inputActions.Enable();
// Create default materials if not assigned // Create default materials if not assigned
if (validMaterial == null) if (validMaterial == null)
@@ -144,15 +143,19 @@ namespace Northbound
public override void OnNetworkDespawn() public override void OnNetworkDespawn()
{ {
if (_isInitialized && _inputActions != null) if (_playerController != null)
{ {
_inputActions.Player.ToggleBuildMode.performed -= OnToggleBuildMode; _playerController.OnInputInitialized -= TryInitializeInput;
_inputActions.Player.Rotate.performed -= OnRotate;
_inputActions.Player.Build.performed -= OnBuildPressed; if (_isInitialized && _playerController.InputActions != null)
_inputActions.Player.Build.canceled -= OnBuildReleased; {
_inputActions.Player.Cancel.performed -= OnCancel; var inputActions = _playerController.InputActions;
_inputActions.Disable(); inputActions.Player.ToggleBuildMode.performed -= OnToggleBuildMode;
_inputActions.Dispose(); inputActions.Player.Rotate.performed -= OnRotate;
inputActions.Player.Build.performed -= OnBuildPressed;
inputActions.Player.Build.canceled -= OnBuildReleased;
inputActions.Player.Cancel.performed -= OnCancel;
}
} }
ClearDragPreviews(); ClearDragPreviews();

View File

@@ -65,9 +65,15 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl
public ulong OwnerPlayerId => _ownerPlayerId.Value; public ulong OwnerPlayerId => _ownerPlayerId.Value;
// 중앙 집중식 입력 관리 - 다른 컴포넌트에서 참조
public PlayerInputActions InputActions => _inputActions;
// 소유자 변경 이벤트 // 소유자 변경 이벤트
public event Action<ulong> OnOwnerChanged; public event Action<ulong> OnOwnerChanged;
// 입력 시스템 초기화 완료 이벤트
public event Action OnInputInitialized;
void Awake() void Awake()
{ {
_controller = GetComponent<CharacterController>(); _controller = GetComponent<CharacterController>();
@@ -141,6 +147,9 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl
_inputActions = new PlayerInputActions(); _inputActions = new PlayerInputActions();
_inputActions.Enable(); _inputActions.Enable();
// 입력 초기화 완료 이벤트 발생
OnInputInitialized?.Invoke();
} }
/// <summary> /// <summary>
@@ -152,6 +161,28 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl
_ownerPlayerId.Value = ownerPlayerId; _ownerPlayerId.Value = ownerPlayerId;
} }
/// <summary>
/// 입력 강제 복구 (입력이 멈췄을 때 호출)
/// </summary>
public void ForceRecoverInput()
{
if (!IsLocalPlayer) return;
// InputActions가 없으면 초기화 시도
if (_inputActions == null)
{
TryInitializeLocalPlayer();
return;
}
// InputActions가 있지만 비활성화되어 있으면 활성화
if (!_inputActions.Player.enabled && _currentHealth.Value > 0)
{
_inputActions.Enable();
Debug.Log("[NetworkPlayerController] 입력 강제 복구 완료");
}
}
public override void OnNetworkDespawn() public override void OnNetworkDespawn()
{ {
_currentHealth.OnValueChanged -= OnHealthChanged; _currentHealth.OnValueChanged -= OnHealthChanged;
@@ -173,6 +204,10 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl
// 서버 측 이동 입력 저장 // 서버 측 이동 입력 저장
private Vector2 _serverMoveInput; private Vector2 _serverMoveInput;
// 입력 복구 체크
private float _inputRecoveryCheckInterval = 1f; // 1초마다 체크
private float _inputRecoveryCheckTimer;
void Update() void Update()
{ {
// 서버에서 체력 자연 회복 처리 // 서버에서 체력 자연 회복 처리
@@ -184,8 +219,24 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl
// 로컬 플레이어만 입력 처리 // 로컬 플레이어만 입력 처리
if (!IsLocalPlayer) return; if (!IsLocalPlayer) return;
// 입력 시스템이 초기화되지 않았으면 스킵 // 입력 시스템이 초기화되지 않았으면 초기화 시도
if (_inputActions == null) return; if (_inputActions == null)
{
TryInitializeLocalPlayer();
return;
}
// 주기적으로 입력 상태 확인 및 자동 복구 (살아있는데 입력이 비활성화된 경우)
_inputRecoveryCheckTimer += Time.deltaTime;
if (_inputRecoveryCheckTimer >= _inputRecoveryCheckInterval)
{
_inputRecoveryCheckTimer = 0f;
if (_currentHealth.Value > 0 && !_inputActions.Player.enabled)
{
Debug.LogWarning("[NetworkPlayerController] 입력이 비활성화되어 있음 - 자동 복구");
_inputActions.Enable();
}
}
// 죽었으면 이동 불가 // 죽었으면 이동 불가
if (_currentHealth.Value <= 0) return; if (_currentHealth.Value <= 0) return;

View File

@@ -17,11 +17,11 @@ namespace Northbound
[Header("Animation")] [Header("Animation")]
public bool playAnimations = true; public bool playAnimations = true;
private PlayerInputActions _inputActions;
private Dictionary<string, IAction> _actions = new Dictionary<string, IAction>(); private Dictionary<string, IAction> _actions = new Dictionary<string, IAction>();
private Animator _animator; private Animator _animator;
private NetworkAnimator _networkAnimator; private NetworkAnimator _networkAnimator;
private NetworkPlayerController _networkPlayerController; private NetworkPlayerController _networkPlayerController;
private bool _isInputInitialized = false;
// 로컬 플레이어인지 확인 // 로컬 플레이어인지 확인
private bool IsLocalPlayer => _networkPlayerController != null && _networkPlayerController.IsLocalPlayer; private bool IsLocalPlayer => _networkPlayerController != null && _networkPlayerController.IsLocalPlayer;
@@ -49,12 +49,19 @@ namespace Northbound
if (_networkPlayerController != null) if (_networkPlayerController != null)
{ {
_networkPlayerController.OnOwnerChanged += OnOwnerPlayerIdChanged; _networkPlayerController.OnOwnerChanged += OnOwnerPlayerIdChanged;
_networkPlayerController.OnInputInitialized += TryInitializeInput;
} }
// 이미 로컬 플레이어면 입력 초기화 // 이미 로컬 플레이어면 입력 초기화
TryInitializeInput(); TryInitializeInput();
} }
private void Start()
{
// Start에서 다시 한번 확인 (이벤트 타이밍 문제 해결)
TryInitializeInput();
}
private void OnOwnerPlayerIdChanged(ulong newOwnerId) private void OnOwnerPlayerIdChanged(ulong newOwnerId)
{ {
TryInitializeInput(); TryInitializeInput();
@@ -63,11 +70,11 @@ namespace Northbound
private void TryInitializeInput() private void TryInitializeInput()
{ {
if (!IsLocalPlayer) return; if (!IsLocalPlayer) return;
if (_inputActions != null) return; if (_isInputInitialized) return; // 이미 초기화됨
if (_networkPlayerController.InputActions == null) return; // 아직 InputActions가 없음
_inputActions = new PlayerInputActions(); _isInputInitialized = true;
_inputActions.Player.Attack.performed += OnAttack; _networkPlayerController.InputActions.Player.Attack.performed += OnAttack;
_inputActions.Enable();
} }
public override void OnNetworkDespawn() public override void OnNetworkDespawn()
@@ -75,13 +82,13 @@ namespace Northbound
if (_networkPlayerController != null) if (_networkPlayerController != null)
{ {
_networkPlayerController.OnOwnerChanged -= OnOwnerPlayerIdChanged; _networkPlayerController.OnOwnerChanged -= OnOwnerPlayerIdChanged;
} _networkPlayerController.OnInputInitialized -= TryInitializeInput;
if (_inputActions != null) // 입력 이벤트 해제
if (_networkPlayerController.InputActions != null)
{ {
_inputActions.Player.Attack.performed -= OnAttack; _networkPlayerController.InputActions.Player.Attack.performed -= OnAttack;
_inputActions.Disable(); }
_inputActions.Dispose();
} }
} }
@@ -126,11 +133,7 @@ namespace Northbound
override public void OnDestroy() override public void OnDestroy()
{ {
if (_inputActions != null) // 입력 정리는 NetworkPlayerController에서 담당
{
_inputActions.Dispose();
}
base.OnDestroy(); base.OnDestroy();
} }
} }

View File

@@ -33,7 +33,6 @@ namespace Northbound
[Header("Worker")] [Header("Worker")]
public Worker assignedWorker; public Worker assignedWorker;
private PlayerInputActions _inputActions;
private IInteractable _currentInteractable; private IInteractable _currentInteractable;
private IInteractable _unavailableInteractable; private IInteractable _unavailableInteractable;
private Camera _mainCamera; private Camera _mainCamera;
@@ -48,6 +47,7 @@ namespace Northbound
private NetworkPlayerController _networkPlayerController; private NetworkPlayerController _networkPlayerController;
private PlayerStats _playerStats; private PlayerStats _playerStats;
private bool _isInputInitialized = false;
public bool IsInteracting => _isInteracting; public bool IsInteracting => _isInteracting;
public float WorkPower => _playerStats?.GetManpower() ?? 10f; public float WorkPower => _playerStats?.GetManpower() ?? 10f;
@@ -77,12 +77,19 @@ namespace Northbound
if (_networkPlayerController != null) if (_networkPlayerController != null)
{ {
_networkPlayerController.OnOwnerChanged += OnOwnerPlayerIdChanged; _networkPlayerController.OnOwnerChanged += OnOwnerPlayerIdChanged;
_networkPlayerController.OnInputInitialized += TryInitializeInput;
} }
// 이미 로컬 플레이어면 입력 초기화 // 이미 로컬 플레이어면 입력 초기화
TryInitializeInput(); TryInitializeInput();
} }
private void Start()
{
// Start에서 다시 한번 확인 (이벤트 타이밍 문제 해결)
TryInitializeInput();
}
private void OnOwnerPlayerIdChanged(ulong newOwnerId) private void OnOwnerPlayerIdChanged(ulong newOwnerId)
{ {
TryInitializeInput(); TryInitializeInput();
@@ -91,12 +98,12 @@ namespace Northbound
private void TryInitializeInput() private void TryInitializeInput()
{ {
if (!IsLocalPlayer) return; if (!IsLocalPlayer) return;
if (_inputActions != null) return; if (_isInputInitialized) return; // 이미 초기화됨
if (_networkPlayerController.InputActions == null) return; // 아직 InputActions가 없음
_isInputInitialized = true;
_mainCamera = Camera.main; _mainCamera = Camera.main;
_inputActions = new PlayerInputActions(); _networkPlayerController.InputActions.Player.Interact.performed += OnInteract;
_inputActions.Player.Interact.performed += OnInteract;
_inputActions.Enable();
} }
public override void OnNetworkDespawn() public override void OnNetworkDespawn()
@@ -104,13 +111,13 @@ namespace Northbound
if (_networkPlayerController != null) if (_networkPlayerController != null)
{ {
_networkPlayerController.OnOwnerChanged -= OnOwnerPlayerIdChanged; _networkPlayerController.OnOwnerChanged -= OnOwnerPlayerIdChanged;
} _networkPlayerController.OnInputInitialized -= TryInitializeInput;
if (_inputActions != null) // 입력 이벤트 해제
if (_networkPlayerController.InputActions != null)
{ {
_inputActions.Player.Interact.performed -= OnInteract; _networkPlayerController.InputActions.Player.Interact.performed -= OnInteract;
_inputActions.Disable(); }
_inputActions.Dispose();
} }
} }
@@ -402,10 +409,7 @@ namespace Northbound
public override void OnDestroy() public override void OnDestroy()
{ {
if (_inputActions != null) // 입력 정리는 NetworkPlayerController에서 담당
{
_inputActions.Dispose();
}
} }
} }
} }