클라이언트 접속 전에 스폰되어 있는 오브젝트의 경우, Ownership이 Distributable일 경우 클라이언트 접속 시점에 Ownership을 호스트로부터 분배받는다. 서버만 데이터를 수정해야 하는 환경이기 때문에 대부분 Distributable 대신 None을 사용하면 된다.
144 lines
4.2 KiB
C#
144 lines
4.2 KiB
C#
using Unity.Netcode;
|
|
using UnityEngine;
|
|
|
|
namespace Northbound
|
|
{
|
|
/// <summary>
|
|
/// 일회용 자원 아이템 - 상호작용 시 자원 획득 후 사라짐
|
|
/// </summary>
|
|
public class ResourcePickup : NetworkBehaviour, IInteractable
|
|
{
|
|
[Header("Resource Settings")]
|
|
public int resourceAmount = 50; // 획득할 자원량
|
|
public string resourceName = "보급품";
|
|
|
|
[Header("Animation")]
|
|
public string interactionAnimationTrigger = "PickUp"; // 플레이어 애니메이션 트리거
|
|
|
|
[Header("Equipment")]
|
|
public EquipmentData equipmentData = new EquipmentData
|
|
{
|
|
socketName = "",
|
|
equipmentPrefab = null,
|
|
attachOnStart = false,
|
|
detachOnEnd = false
|
|
};
|
|
|
|
[Header("Visual")]
|
|
public GameObject pickupEffectPrefab;
|
|
public Transform effectSpawnPoint;
|
|
|
|
private bool _isCollected = false;
|
|
|
|
public bool CanInteract(ulong playerId)
|
|
{
|
|
if (_isCollected)
|
|
return false;
|
|
|
|
var resourceManager = ServerResourceManager.Instance;
|
|
if (resourceManager != null)
|
|
{
|
|
if (resourceManager.GetAvailableSpace(playerId) <= 0)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void Interact(ulong playerId)
|
|
{
|
|
if (!CanInteract(playerId))
|
|
return;
|
|
|
|
CollectResourceServerRpc(playerId);
|
|
}
|
|
|
|
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
|
private void CollectResourceServerRpc(ulong playerId)
|
|
{
|
|
if (!CanInteract(playerId))
|
|
return;
|
|
|
|
if (_isCollected)
|
|
return;
|
|
|
|
_isCollected = true;
|
|
|
|
var resourceManager = ServerResourceManager.Instance;
|
|
if (resourceManager == null)
|
|
{
|
|
Debug.LogWarning("ServerResourceManager 인스턴스를 찾을 수 없습니다.");
|
|
_isCollected = false;
|
|
return;
|
|
}
|
|
|
|
int playerAvailableSpace = resourceManager.GetAvailableSpace(playerId);
|
|
int collectedAmount = Mathf.Min(resourceAmount, playerAvailableSpace);
|
|
|
|
if (collectedAmount <= 0)
|
|
{
|
|
_isCollected = false;
|
|
return;
|
|
}
|
|
|
|
resourceManager.AddResource(playerId, collectedAmount);
|
|
UpdatePlayerResourcesClientRpc(playerId);
|
|
|
|
ShowPickupEffectClientRpc();
|
|
Invoke(nameof(DestroyPickup), 0.1f);
|
|
}
|
|
|
|
[Rpc(SendTo.Owner)]
|
|
private void UpdatePlayerResourcesClientRpc(ulong playerId)
|
|
{
|
|
var playerObject = NetworkManager.Singleton.ConnectedClients[playerId]?.PlayerObject;
|
|
if (playerObject == null)
|
|
return;
|
|
|
|
var playerInventory = playerObject.GetComponent<PlayerResourceInventory>();
|
|
playerInventory?.RequestResourceUpdateServerRpc();
|
|
}
|
|
|
|
[Rpc(SendTo.ClientsAndHost)]
|
|
private void ShowPickupEffectClientRpc()
|
|
{
|
|
if (pickupEffectPrefab != null)
|
|
{
|
|
Transform spawnPoint = effectSpawnPoint != null ? effectSpawnPoint : transform;
|
|
GameObject effect = Instantiate(pickupEffectPrefab, spawnPoint.position, spawnPoint.rotation);
|
|
Destroy(effect, 2f);
|
|
}
|
|
|
|
// 오브젝트를 즉시 비활성화하여 재상호작용 방지
|
|
gameObject.SetActive(false);
|
|
}
|
|
|
|
private void DestroyPickup()
|
|
{
|
|
if (IsServer && NetworkObject != null)
|
|
{
|
|
NetworkObject.Despawn(true);
|
|
}
|
|
}
|
|
|
|
public string GetInteractionPrompt()
|
|
{
|
|
return $"[E] {resourceName} Get (+{resourceAmount})";
|
|
}
|
|
|
|
public string GetInteractionAnimation()
|
|
{
|
|
return interactionAnimationTrigger;
|
|
}
|
|
|
|
public EquipmentData GetEquipmentData()
|
|
{
|
|
return equipmentData;
|
|
}
|
|
|
|
public Transform GetTransform()
|
|
{
|
|
return transform;
|
|
}
|
|
}
|
|
} |