using System; using System.Collections.Generic; using Unity.Netcode; using UnityEngine; public class PlayerInventory : NetworkBehaviour { [Header("Inventory Settings")] [Range(1, 10)] // 인스펙터에서 슬라이더로 조절 가능 public int slotCount = 5; public float maxWeight = 50f; [System.Serializable] public struct DefaultItem { public ItemData item; // 인스펙터에서 아이템 에셋 드래그 public int amount; // 초기 개수 } [Header("Starting Loadout")] [SerializeField] private List startingItems; // 기본 지급 아이템 리스트 // 1. 실제 데이터 저장소 (Private) private NetworkVariable _selectedSlotIndex = new NetworkVariable(0, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); // 2. 외부에서 읽기 전용으로 값에 접근 (기존 유지) public int SelectedSlotIndex => _selectedSlotIndex.Value; // 3. [핵심] 외부에서 이벤트에 함수를 등록(+=)할 수 있도록 델리게이트 노출 public NetworkVariable.OnValueChangedDelegate OnSlotChanged { get => _selectedSlotIndex.OnValueChanged; set => _selectedSlotIndex.OnValueChanged = value; } public struct InventorySlot : INetworkSerializable, IEquatable { public int ItemID; // string에서 int로 변경 public int Amount; public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter { serializer.SerializeValue(ref ItemID); serializer.SerializeValue(ref Amount); } public bool Equals(InventorySlot other) => ItemID == other.ItemID && Amount == other.Amount; } [Header("References")] [SerializeField] private ItemDatabase database; public NetworkList Slots; // 무게 정보는 서버에서만 쓰고 나머지는 읽기만 가능 (네트워크 보안) private NetworkVariable _currentWeight = new NetworkVariable(0f, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); public float CurrentWeight => _currentWeight.Value; void Awake() { Slots = new NetworkList(); } public override void OnNetworkSpawn() { if (IsServer) { InitializeInventory(); } // 로컬 플레이어라면 UI 연결 if (IsOwner) { QuickslotUI ui = FindFirstObjectByType(); if (ui != null) ui.BindInventory(this); } } // PlayerInventory.cs 내의 AddItemRpc 예시 [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] public void AddItemRpc(int itemID, int amount) { // 이제 필드 변수 없이 바로 접근 가능! ItemData data = ItemDatabase.Instance.GetItemByID(itemID); if (data == null) return; float addedWeight = data.weight * amount; bool added = false; for (int i = 0; i < Slots.Count; i++) { // 기존에 같은 아이템이 있거나(-1은 빈 슬롯을 의미) 빈 슬롯인 경우 if (Slots[i].ItemID == itemID || Slots[i].ItemID == -1) { Slots[i] = new InventorySlot { ItemID = itemID, Amount = Slots[i].Amount + amount }; added = true; break; } } if (added) { _currentWeight.Value += addedWeight; } } // 슬롯 선택 요청 (최신 RPC 방식 적용) [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] public void ChangeSelectedSlotRpc(int index) { if (index >= 0 && index < slotCount) { Debug.Log($"[PlayerInventory] 슬롯 선택 변경 요청: {index}"); _selectedSlotIndex.Value = index; } } // 현재 선택된 슬롯의 아이템 데이터를 가져오는 편의 기능 public ItemData GetSelectedItemData() { var slot = Slots[SelectedSlotIndex]; if (slot.ItemID == -1) return null; return ItemDatabase.Instance.GetItemByID(slot.ItemID); } private void InitializeInventory() { // 슬롯을 깨끗하게 비우고 시작 (이미 데이터가 있을 경우를 대비) if (Slots.Count > 0) Slots.Clear(); _currentWeight.Value = 0; // 전체 슬롯 개수만큼 빈 슬롯(-1) 먼저 생성 for (int i = 0; i < slotCount; i++) { Slots.Add(new InventorySlot { ItemID = -1, Amount = 0 }); } // 설정된 기본 아이템들을 순서대로 채워 넣음 for (int i = 0; i < startingItems.Count && i < slotCount; i++) { if (startingItems[i].item != null) { ItemData data = startingItems[i].item; int amount = startingItems[i].amount; Slots[i] = new InventorySlot { ItemID = data.itemID, Amount = amount }; // 초기 무게 합산 _currentWeight.Value += data.weight * amount; } } } // PlayerInventory.cs에 추가 public ItemData GetItemDataInSlot(int index) { if (index < 0 || index >= Slots.Count) return null; var slot = Slots[index]; if (slot.ItemID == -1) return null; return ItemDatabase.Instance.GetItemByID(slot.ItemID); } }