using Unity.Netcode; using UnityEngine; namespace Northbound { /// /// 상호작용 대상 - 자원 채집 /// public class Resource : NetworkBehaviour, IInteractable { [Header("Resource Settings")] public int maxResources = 100; public int resourcesPerGathering = 10; public float gatheringCooldown = 2f; public string resourceName = "광석"; [Header("Resource Recharge")] public float rechargeInterval = 5f; // 충전 주기 (초) public int rechargeAmount = 10; // 주기당 충전량 [Header("Animation")] public string interactionAnimationTrigger = "Mining"; // 플레이어 애니메이션 트리거 [Header("Equipment")] public InteractionEquipmentData equipmentData = new InteractionEquipmentData { socketName = "RightHand", attachOnStart = true, detachOnEnd = true }; [Header("Visual")] public GameObject gatheringEffectPrefab; public Transform effectSpawnPoint; private NetworkVariable _currentResources = new NetworkVariable( 0, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server ); private float _lastGatheringTime; private float _lastRechargeTime; public override void OnNetworkSpawn() { if (IsServer) { _currentResources.Value = 0; _lastRechargeTime = Time.time; } } private void Update() { if (!IsServer) return; // 자원 충전 로직 if (Time.time - _lastRechargeTime >= rechargeInterval) { if (_currentResources.Value < maxResources) { int rechargeAmountToAdd = Mathf.Min(rechargeAmount, maxResources - _currentResources.Value); _currentResources.Value += rechargeAmountToAdd; Debug.Log($"{resourceName} {rechargeAmountToAdd} 충전됨. 현재: {_currentResources.Value}/{maxResources}"); } _lastRechargeTime = Time.time; } } public bool CanInteract(ulong playerId) { // 자원 노드에 자원이 없으면 상호작용 불가 if (_currentResources.Value <= 0) return false; // 쿨다운 확인 if (Time.time - _lastGatheringTime < gatheringCooldown) return false; // 플레이어 인벤토리 확인 if (NetworkManager.Singleton != null && NetworkManager.Singleton.ConnectedClients.TryGetValue(playerId, out var client)) { if (client.PlayerObject != null) { var playerInventory = client.PlayerObject.GetComponent(); if (playerInventory != null) { // 플레이어가 받을 수 있는 공간이 없으면 상호작용 불가 if (playerInventory.GetAvailableSpace() <= 0) return false; } } } return true; } public void Interact(ulong playerId) { if (!CanInteract(playerId)) return; GatherResourceServerRpc(playerId); } [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] private void GatherResourceServerRpc(ulong playerId) { if (!CanInteract(playerId)) return; // 플레이어의 인벤토리 확인 var playerObject = NetworkManager.Singleton.ConnectedClients[playerId].PlayerObject; if (playerObject == null) return; var playerInventory = playerObject.GetComponent(); if (playerInventory == null) { Debug.LogWarning($"플레이어 {playerId}에게 PlayerResourceInventory 컴포넌트가 없습니다."); return; } // 플레이어가 받을 수 있는 최대량 계산 int playerAvailableSpace = playerInventory.GetAvailableSpace(); // 자원 노드가 줄 수 있는 양과 플레이어가 받을 수 있는 양 중 작은 값 선택 int gatheredAmount = Mathf.Min( resourcesPerGathering, _currentResources.Value, playerAvailableSpace ); if (gatheredAmount <= 0) { Debug.Log($"플레이어 {playerId}의 인벤토리가 가득 찼습니다."); return; } // 자원 차감 _currentResources.Value -= gatheredAmount; _lastGatheringTime = Time.time; // 플레이어에게 자원 추가 playerInventory.AddResourceServerRpc(gatheredAmount); Debug.Log($"플레이어 {playerId}가 {gatheredAmount} {resourceName}을(를) 채집했습니다. 남은 자원: {_currentResources.Value}"); ShowGatheringEffectClientRpc(); } [Rpc(SendTo.ClientsAndHost)] private void ShowGatheringEffectClientRpc() { if (gatheringEffectPrefab != null && effectSpawnPoint != null) { GameObject effect = Instantiate(gatheringEffectPrefab, effectSpawnPoint.position, effectSpawnPoint.rotation); Destroy(effect, 2f); } } public string GetInteractionPrompt() { if (_currentResources.Value <= 0) return "자원 충전 중..."; return $"[E] {resourceName} 채집 ({_currentResources.Value}/{maxResources})"; } public string GetInteractionAnimation() { return interactionAnimationTrigger; } public InteractionEquipmentData GetEquipmentData() { return equipmentData; } public Transform GetTransform() { return transform; } } }