모든 네트워크 오브젝트의 소유권을 서버가 갖도록 함
Distributable -> None 관련 사이드 이펙트로 인한 버그 수정
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Unity.Netcode;
|
||||
using Unity.Netcode.Components;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
@@ -37,6 +38,7 @@ namespace Northbound
|
||||
private IInteractable _unavailableInteractable;
|
||||
private Camera _mainCamera;
|
||||
private Animator _animator;
|
||||
private NetworkAnimator _networkAnimator;
|
||||
private EquipmentSocket _equipmentSocket;
|
||||
|
||||
private EquipmentData _pendingEquipmentData;
|
||||
@@ -44,21 +46,51 @@ namespace Northbound
|
||||
private bool _isInteracting = false;
|
||||
private Coroutine _interactionTimeoutCoroutine;
|
||||
|
||||
private NetworkPlayerController _networkPlayerController;
|
||||
|
||||
public bool IsInteracting => _isInteracting;
|
||||
public float WorkPower => workPower;
|
||||
public IInteractable CurrentUnavailableInteractable => _unavailableInteractable;
|
||||
|
||||
// 로컬 플레이어인지 확인
|
||||
private bool IsLocalPlayer => _networkPlayerController != null && _networkPlayerController.IsLocalPlayer;
|
||||
private ulong LocalPlayerId => _networkPlayerController != null ? _networkPlayerController.OwnerPlayerId : OwnerClientId;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_networkPlayerController = GetComponent<NetworkPlayerController>();
|
||||
_networkAnimator = GetComponent<NetworkAnimator>();
|
||||
}
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
if (!IsOwner) return;
|
||||
|
||||
_mainCamera = Camera.main;
|
||||
_animator = GetComponent<Animator>();
|
||||
_equipmentSocket = GetComponent<EquipmentSocket>();
|
||||
|
||||
if (rayOrigin == null)
|
||||
rayOrigin = transform;
|
||||
|
||||
// _ownerPlayerId 변경 이벤트 구독
|
||||
if (_networkPlayerController != null)
|
||||
{
|
||||
_networkPlayerController.OnOwnerChanged += OnOwnerPlayerIdChanged;
|
||||
}
|
||||
|
||||
// 이미 로컬 플레이어면 입력 초기화
|
||||
TryInitializeInput();
|
||||
}
|
||||
|
||||
private void OnOwnerPlayerIdChanged(ulong newOwnerId)
|
||||
{
|
||||
TryInitializeInput();
|
||||
}
|
||||
|
||||
private void TryInitializeInput()
|
||||
{
|
||||
if (!IsLocalPlayer) return;
|
||||
if (_inputActions != null) return;
|
||||
|
||||
_mainCamera = Camera.main;
|
||||
_inputActions = new PlayerInputActions();
|
||||
_inputActions.Player.Interact.performed += OnInteract;
|
||||
_inputActions.Enable();
|
||||
@@ -66,7 +98,12 @@ namespace Northbound
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
if (IsOwner && _inputActions != null)
|
||||
if (_networkPlayerController != null)
|
||||
{
|
||||
_networkPlayerController.OnOwnerChanged -= OnOwnerPlayerIdChanged;
|
||||
}
|
||||
|
||||
if (_inputActions != null)
|
||||
{
|
||||
_inputActions.Player.Interact.performed -= OnInteract;
|
||||
_inputActions.Disable();
|
||||
@@ -76,12 +113,11 @@ namespace Northbound
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!IsOwner) return;
|
||||
if (!IsLocalPlayer) return;
|
||||
|
||||
// Check if current interactable is no longer valid (e.g., building completed)
|
||||
if (_isInteracting && _currentInteractable != null)
|
||||
{
|
||||
if (!_currentInteractable.CanInteract(OwnerClientId))
|
||||
if (!_currentInteractable.CanInteract(LocalPlayerId))
|
||||
{
|
||||
EndInteraction();
|
||||
}
|
||||
@@ -92,6 +128,13 @@ namespace Northbound
|
||||
|
||||
private void DetectInteractable()
|
||||
{
|
||||
// 카메라가 없으면 다시 시도
|
||||
if (_mainCamera == null)
|
||||
{
|
||||
_mainCamera = Camera.main;
|
||||
if (_mainCamera == null) return;
|
||||
}
|
||||
|
||||
Vector3 origin = rayOrigin.position;
|
||||
Vector3 direction = useForwardDirection ? transform.forward : _mainCamera.transform.forward;
|
||||
|
||||
@@ -112,7 +155,7 @@ namespace Northbound
|
||||
|
||||
if (interactable != null)
|
||||
{
|
||||
if (interactable.CanInteract(OwnerClientId))
|
||||
if (interactable.CanInteract(LocalPlayerId))
|
||||
{
|
||||
_currentInteractable = interactable;
|
||||
_unavailableInteractable = null;
|
||||
@@ -120,7 +163,6 @@ namespace Northbound
|
||||
}
|
||||
else
|
||||
{
|
||||
// CanInteract가 false인 경우 추적
|
||||
_currentInteractable = null;
|
||||
_unavailableInteractable = interactable;
|
||||
return;
|
||||
@@ -139,8 +181,14 @@ namespace Northbound
|
||||
|
||||
if (_currentInteractable != null)
|
||||
{
|
||||
// 상호작용 가능 여부 다시 확인 (NetworkVariable 동기화 지연 대응)
|
||||
if (!_currentInteractable.CanInteract(LocalPlayerId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool isResource = _currentInteractable is Resource;
|
||||
bool hasWorker = assignedWorker != null && assignedWorker.OwnerPlayerId == OwnerClientId;
|
||||
bool hasWorker = assignedWorker != null && assignedWorker.OwnerPlayerId == LocalPlayerId;
|
||||
bool isWorkerFollowing = hasWorker && (int)assignedWorker.CurrentState == 1;
|
||||
bool shouldPlayAnimation = !isResource || !hasWorker || !isWorkerFollowing;
|
||||
|
||||
@@ -150,9 +198,10 @@ namespace Northbound
|
||||
string animTrigger = _currentInteractable.GetInteractionAnimation();
|
||||
bool hasAnimation = !string.IsNullOrEmpty(animTrigger);
|
||||
|
||||
if (playAnimations && _animator != null && hasAnimation && shouldPlayAnimation)
|
||||
if (playAnimations && hasAnimation && shouldPlayAnimation)
|
||||
{
|
||||
_animator.SetTrigger(animTrigger);
|
||||
// 서버에서 애니메이션 실행 (동기화를 위해)
|
||||
PlayAnimationServerRpc(animTrigger);
|
||||
_interactionTimeoutCoroutine = StartCoroutine(InteractionTimeout(3f));
|
||||
}
|
||||
else
|
||||
@@ -173,13 +222,18 @@ namespace Northbound
|
||||
}
|
||||
}
|
||||
|
||||
_currentInteractable.Interact(OwnerClientId);
|
||||
_currentInteractable.Interact(LocalPlayerId);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Animation Event 함수들
|
||||
// ========================================
|
||||
[Rpc(SendTo.Server)]
|
||||
private void PlayAnimationServerRpc(string animTrigger)
|
||||
{
|
||||
if (_networkAnimator != null && !string.IsNullOrEmpty(animTrigger))
|
||||
{
|
||||
_networkAnimator.SetTrigger(animTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEquipTool()
|
||||
{
|
||||
@@ -207,7 +261,7 @@ namespace Northbound
|
||||
|
||||
public void OnInteractionComplete()
|
||||
{
|
||||
if (!IsOwner) return;
|
||||
if (!IsLocalPlayer) return;
|
||||
|
||||
if (_interactionTimeoutCoroutine != null)
|
||||
{
|
||||
@@ -217,10 +271,6 @@ namespace Northbound
|
||||
_isInteracting = false;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 내부 헬퍼 함수들
|
||||
// ========================================
|
||||
|
||||
private void AttachEquipment(string socketName = null)
|
||||
{
|
||||
if (_equipmentSocket == null || _pendingEquipmentData == null)
|
||||
@@ -283,7 +333,13 @@ namespace Northbound
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (!IsOwner) return;
|
||||
if (!IsLocalPlayer) return;
|
||||
|
||||
// 디버그: _mainCamera 상태 확인
|
||||
if (_mainCamera == null)
|
||||
{
|
||||
_mainCamera = Camera.main;
|
||||
}
|
||||
|
||||
GUIStyle style = new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
@@ -299,7 +355,7 @@ namespace Northbound
|
||||
prompt = _currentInteractable.GetInteractionPrompt();
|
||||
|
||||
bool isResource = _currentInteractable is Resource;
|
||||
if (isResource && assignedWorker != null && assignedWorker.OwnerPlayerId == OwnerClientId)
|
||||
if (isResource && assignedWorker != null && assignedWorker.OwnerPlayerId == LocalPlayerId)
|
||||
{
|
||||
prompt += " (워커 할당 가능)";
|
||||
}
|
||||
@@ -311,7 +367,7 @@ namespace Northbound
|
||||
}
|
||||
}
|
||||
|
||||
if (assignedWorker != null && assignedWorker.OwnerPlayerId == OwnerClientId)
|
||||
if (assignedWorker != null && assignedWorker.OwnerPlayerId == LocalPlayerId)
|
||||
{
|
||||
string workerStatus = assignedWorker.CurrentState switch
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user