using Unity.Netcode; using UnityEngine; namespace Northbound { /// /// 플레이어가 자원을 건내받아 게임의 전역 자원으로 관리하는 중앙 허브 /// public class Core : NetworkBehaviour, IInteractable { [Header("Core Settings")] public int maxStorageCapacity = 1000; // 코어의 최대 저장 용량 public bool unlimitedStorage = false; // 무제한 저장소 [Header("Deposit Settings")] public bool depositAll = true; // true: 전부 건네기, false: 일부만 건네기 public int depositAmountPerInteraction = 10; // depositAll이 false일 때 한 번에 건네는 양 [Header("Animation")] public string interactionAnimationTrigger = "Deposit"; // 플레이어 애니메이션 트리거 [Header("Equipment")] public InteractionEquipmentData equipmentData = null; // 도구 필요 없음 [Header("Visual")] public GameObject depositEffectPrefab; public Transform effectSpawnPoint; private NetworkVariable _totalResources = new NetworkVariable( 0, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server ); public int TotalResources => _totalResources.Value; public int MaxStorageCapacity => maxStorageCapacity; public override void OnNetworkSpawn() { if (IsServer) { _totalResources.Value = 0; } } public bool CanInteract(ulong playerId) { // 저장소가 가득 찼는지 확인 (무제한이 아닐 때) if (!unlimitedStorage && _totalResources.Value >= maxStorageCapacity) 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) { // 플레이어가 자원을 가지고 있어야 함 return playerInventory.CurrentResourceAmount > 0; } } } return false; } public void Interact(ulong playerId) { if (!CanInteract(playerId)) return; DepositResourceServerRpc(playerId); } [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] private void DepositResourceServerRpc(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 playerResourceAmount = playerInventory.CurrentResourceAmount; if (playerResourceAmount <= 0) { Debug.Log($"플레이어 {playerId}가 건낼 자원이 없습니다."); return; } int depositAmount; if (depositAll) { // 전부 건네기 depositAmount = playerResourceAmount; } else { // 일부만 건네기 depositAmount = Mathf.Min(depositAmountPerInteraction, playerResourceAmount); } // 무제한 저장소가 아니면 용량 제한 확인 if (!unlimitedStorage) { int availableSpace = maxStorageCapacity - _totalResources.Value; depositAmount = Mathf.Min(depositAmount, availableSpace); } if (depositAmount <= 0) { Debug.Log($"코어의 저장 공간이 부족합니다."); return; } // 플레이어로부터 자원 차감 playerInventory.RemoveResourceServerRpc(depositAmount); // 코어에 자원 추가 _totalResources.Value += depositAmount; Debug.Log($"플레이어 {playerId}가 {depositAmount} 자원을 코어에 건넸습니다. 코어 총 자원: {_totalResources.Value}" + (unlimitedStorage ? "" : $"/{maxStorageCapacity}")); ShowDepositEffectClientRpc(); } [Rpc(SendTo.ClientsAndHost)] private void ShowDepositEffectClientRpc() { if (depositEffectPrefab != null && effectSpawnPoint != null) { GameObject effect = Instantiate(depositEffectPrefab, effectSpawnPoint.position, effectSpawnPoint.rotation); Destroy(effect, 2f); } } /// /// 게임 시스템이 코어의 자원을 사용 (건물 건설 등) /// [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] public void ConsumeResourceServerRpc(int amount) { if (amount <= 0) return; int actualAmount = Mathf.Min(amount, _totalResources.Value); _totalResources.Value -= actualAmount; Debug.Log($"코어에서 {actualAmount} 자원을 사용했습니다. 남은 자원: {_totalResources.Value}"); } /// /// 자원을 사용할 수 있는지 확인 /// public bool CanConsumeResource(int amount) { return _totalResources.Value >= amount; } /// /// 코어에 자원 추가 (디버그/관리자 기능) /// [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] public void AddResourceServerRpc(int amount) { if (amount <= 0) return; if (!unlimitedStorage) { int availableSpace = maxStorageCapacity - _totalResources.Value; amount = Mathf.Min(amount, availableSpace); } _totalResources.Value += amount; Debug.Log($"코어에 {amount} 자원이 추가되었습니다. 현재: {_totalResources.Value}"); } public string GetInteractionPrompt() { if (unlimitedStorage) { return depositAll ? $"[E] 자원 모두 건네기" : $"[E] 자원 건네기 ({depositAmountPerInteraction}개씩)"; } if (_totalResources.Value >= maxStorageCapacity) return "코어 저장소 가득 찼음"; return depositAll ? $"[E] 자원 모두 건네기 ({_totalResources.Value}/{maxStorageCapacity})" : $"[E] 자원 건네기 ({_totalResources.Value}/{maxStorageCapacity})"; } public string GetInteractionAnimation() { return interactionAnimationTrigger; } public InteractionEquipmentData GetEquipmentData() { return equipmentData; } public Transform GetTransform() { return transform; } } }