using System; using System.Collections.Generic; using Cielonos.MainGame.Characters.Inventory; using Cielonos.MainGame.Characters.Inventory.Collections; using UnityEngine; using Object = UnityEngine.Object; namespace Cielonos.MainGame.Characters { public partial class PlayerInventorySubcontroller { public partial class BackpackSubmodule : SubmoduleBase { public List mainWeapons = new List(); public List supportEquipments = new List(); public List passiveEquipments = new List(); public List consumables = new List(); /// /// Resources 路径中道具类型对应的子文件夹名。 /// 约定路径格式:Resources/Items/{子文件夹}/{类名}.prefab /// private static readonly Dictionary ItemTypeToSubfolder = new() { { typeof(MainWeaponBase), "MainWeapon" }, { typeof(SupportEquipmentBase), "SupportEquipment" }, { typeof(PassiveEquipmentBase), "PassiveEquipment" }, { typeof(ConsumableBase), "Consumable" }, }; public BackpackSubmodule(PlayerInventorySubcontroller owner) : base(owner) { } } // ================================================================ // 获取道具(已有实例) // ================================================================ public partial class BackpackSubmodule { /// /// 通过 Resources 加载 Prefab,实例化到对应的 Container 下,然后加入背包。 /// 若为消耗品且背包中已存在同类型实例,则直接堆叠,不再重复生成。 /// /// 道具的具体类型(必须继承 ItemBase)。 /// 消耗品的初始 / 追加堆叠数量,非消耗品忽略此参数。 /// 背包中该道具的实例引用;加载失败时返回 null。 public T ObtainItem(int amount = 1) where T : ItemBase { // 消耗品:如果背包中已有同类型实例,直接堆叠 if (typeof(ConsumableBase).IsAssignableFrom(typeof(T))) { ConsumableBase existing = consumables.Find(c => c is T); if (existing != null) { existing.Add(amount); return existing as T; } } // 确定 Resources 子路径 string subfolder = ResolveSubfolder(typeof(T)); if (subfolder == null) { Debug.LogError($"[Backpack] 无法确定 {typeof(T).Name} 的 Resources 子文件夹。"); return null; } string resourcePath = $"Items/{subfolder}/{typeof(T).Name}"; GameObject prefab = Resources.Load(resourcePath); if (prefab == null) { Debug.LogError($"[Backpack] 未找到 Prefab:Resources/{resourcePath}"); return null; } // 实例化到对应的 Container 下 Transform container = GetContainerForType(typeof(T)); GameObject instance = Object.Instantiate(prefab, container); instance.name = typeof(T).Name; T item = instance.GetComponent(); if (item == null) { Debug.LogError($"[Backpack] Prefab '{resourcePath}' 上未找到组件 {typeof(T).Name}。"); Object.Destroy(instance); return null; } ObtainItem(item, amount); return item; } /// /// 将已有的道具实例加入背包。 /// 对于消耗品,amount 指定堆叠数量;-1 表示使用道具自身的 stackAmount。 /// public void ObtainItem(ItemBase item, int amount = -1) { item.Initialize(); if (item is MainWeaponBase mainWeapon) { ObtainMainWeapon(mainWeapon); } else if (item is SupportEquipmentBase supportEquipment) { ObtainSupportEquipment(supportEquipment); } else if (item is PassiveEquipmentBase passiveEquipment) { ObtainPassiveEquipment(passiveEquipment); } else if (item is ConsumableBase consumable) { ObtainConsumable(consumable, amount); } item.OnObtained(); } /// /// 通过预制体引用获取道具:实例化到对应 Container 下并加入背包。 /// 消耗品会自动堆叠。用于 MechanicalTable、LogisticsCenter 等持有直接预制体引用的场景。 /// /// 道具预制体(必须包含 ItemBase 组件)。 /// 消耗品的堆叠数量,非消耗品忽略。 /// 背包中该道具的实例引用;失败时返回 null。 public ItemBase ObtainItem(GameObject prefab, int amount = 1) { ItemBase prefabItem = prefab.GetComponent(); if (prefabItem == null) { Debug.LogError($"[Backpack] Prefab '{prefab.name}' 上未找到 ItemBase 组件。"); return null; } // 消耗品:如果背包中已有同类型实例,直接堆叠 if (prefabItem is ConsumableBase) { ConsumableBase existing = consumables.Find(c => c.GetType() == prefabItem.GetType()); if (existing != null) { existing.Add(amount); return existing; } } Transform container = GetContainerForType(prefabItem.GetType()); GameObject instance = Object.Instantiate(prefab, container); instance.name = prefabItem.GetType().Name; ItemBase item = instance.GetComponent(); if (item == null) { Debug.LogError($"[Backpack] 实例化后的 '{prefab.name}' 上未找到 ItemBase 组件。"); Object.Destroy(instance); return null; } ObtainItem(item, amount); return item; } public void DiscardItem(ItemBase item, int amount = -1) { if (item is MainWeaponBase mainWeapon) { DiscardMainWeapon(mainWeapon); } else if (item is SupportEquipmentBase supportEquipment) { DiscardSupportEquipment(supportEquipment); } else if (item is PassiveEquipmentBase passiveEquipment) { DiscardPassiveEquipment(passiveEquipment); } else if (item is ConsumableBase consumable) { DiscardConsumable(consumable, amount); } item.OnDiscarded(); } } // ================================================================ // 内部实现:获取 / 丢弃各类型道具 // ================================================================ public partial class BackpackSubmodule { private void ObtainMainWeapon(MainWeaponBase item) { if (!mainWeapons.Contains(item)) { mainWeapons.Add(item); } } private void DiscardMainWeapon(MainWeaponBase item) { if (mainWeapons.Contains(item)) { mainWeapons.Remove(item); } } private void ObtainSupportEquipment(SupportEquipmentBase item) { if (!supportEquipments.Contains(item)) { supportEquipments.Add(item); } } private void DiscardSupportEquipment(SupportEquipmentBase item) { if (supportEquipments.Contains(item)) { supportEquipments.Remove(item); } } private void ObtainPassiveEquipment(PassiveEquipmentBase item) { if (!passiveEquipments.Contains(item)) { passiveEquipments.Add(item); } } private void DiscardPassiveEquipment(PassiveEquipmentBase item) { if (passiveEquipments.Contains(item)) { passiveEquipments.Remove(item); } } private void ObtainConsumable(ConsumableBase item, int amount = -1) { ConsumableBase existingItem = consumables.Find(c => c.GetType() == item.GetType()); if (existingItem != null) { // 背包中已有同类型消耗品,堆叠 int stack = amount == -1 ? item.stackAmount : amount; existingItem.Add(stack); } else { // 首次获得,加入列表并设置初始堆叠 consumables.Add(item); if (amount >= 0) { item.stackAmount = amount; } } } private void DiscardConsumable(ConsumableBase item, int amount = -1) { if (consumables.Contains(item)) { ConsumableBase existingItem = consumables.Find(consumable => consumable.GetType() == item.GetType()); existingItem.stackAmount -= amount == -1 ? item.stackAmount : amount; // 如果amount为-1则丢弃全部 if (existingItem.stackAmount <= 0) { consumables.Remove(existingItem); } } } } // ================================================================ // 内部实现:Resources 路径 / Container 解析 // ================================================================ public partial class BackpackSubmodule { /// /// 根据道具具体类型查找其基类对应的 Resources 子文件夹名。 /// private static string ResolveSubfolder(Type itemType) { foreach (var kvp in ItemTypeToSubfolder) { if (kvp.Key.IsAssignableFrom(itemType)) return kvp.Value; } return null; } /// /// 根据道具类型返回对应的父级 Container Transform。 /// private Transform GetContainerForType(Type itemType) { if (typeof(MainWeaponBase).IsAssignableFrom(itemType)) return owner.mainWeaponContainer; if (typeof(SupportEquipmentBase).IsAssignableFrom(itemType)) return owner.supportEquipmentContainer; if (typeof(PassiveEquipmentBase).IsAssignableFrom(itemType)) return owner.passiveEquipmentContainer; if (typeof(ConsumableBase).IsAssignableFrom(itemType)) return owner.consumableContainer; return owner.player.transform; } } } }