370 lines
10 KiB
C#
370 lines
10 KiB
C#
using Godot;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
|
||
public partial class InventoryManager : Node
|
||
{
|
||
// 库存数据结构
|
||
public class InventoryItem
|
||
{
|
||
public string ItemId { get; set; }
|
||
public int Quantity { get; set; }
|
||
|
||
public InventoryItem(string itemId, int quantity = 0)
|
||
{
|
||
ItemId = itemId;
|
||
Quantity = quantity;
|
||
}
|
||
}
|
||
|
||
// 单例实例
|
||
private static InventoryManager instance;
|
||
public static InventoryManager Instance
|
||
{
|
||
get
|
||
{
|
||
return instance;
|
||
}
|
||
}
|
||
|
||
// 库存数据字典 - 物品ID -> 库存项
|
||
private Dictionary<string, InventoryItem> inventory = new Dictionary<string, InventoryItem>();
|
||
|
||
// 线程锁
|
||
private readonly object inventoryLock = new object();
|
||
|
||
// 事件委托
|
||
public delegate void InventoryChangedEventHandler(string itemId, int oldQuantity, int newQuantity);
|
||
public event InventoryChangedEventHandler InventoryChanged;
|
||
|
||
public override void _Ready()
|
||
{
|
||
GD.Print("InventoryManager _Ready 开始");
|
||
|
||
// 确保单例
|
||
if (instance == null)
|
||
{
|
||
instance = this;
|
||
InitializeInventory();
|
||
}
|
||
else
|
||
{
|
||
GD.PrintErr("InventoryManager 实例已存在!");
|
||
QueueFree();
|
||
}
|
||
}
|
||
|
||
// 初始化库存
|
||
private void InitializeInventory()
|
||
{
|
||
GD.Print("初始化库存系统");
|
||
|
||
lock (inventoryLock)
|
||
{
|
||
// 为所有已知物品创建库存条目(初始数量为0)
|
||
if (GameData.Instance != null)
|
||
{
|
||
var allItems = GameData.Instance.GetAllItems();
|
||
foreach (var item in allItems)
|
||
{
|
||
inventory[item.Key] = new InventoryItem(item.Key, 0);
|
||
}
|
||
GD.Print($"初始化了 {inventory.Count} 个物品的库存条目");
|
||
}
|
||
else
|
||
{
|
||
GD.PrintErr("GameData.Instance 为 null,无法初始化库存");
|
||
}
|
||
}
|
||
|
||
// 添加一些测试数据
|
||
AddTestData();
|
||
}
|
||
|
||
// 添加测试数据
|
||
private void AddTestData()
|
||
{
|
||
GD.Print("添加测试库存数据");
|
||
AddItem("iron_ore", 100);
|
||
AddItem("copper_ore", 50);
|
||
AddItem("coal_ore", 75);
|
||
AddItem("water", 200);
|
||
AddItem("iron_ingot", 25);
|
||
AddItem("copper_ingot", 15);
|
||
AddItem("magnet", 8); // 添加磁铁,用于合成磁线圈
|
||
AddItem("gear", 6); // 添加齿轮,用于合成钻机
|
||
}
|
||
|
||
// 添加物品到库存
|
||
public bool AddItem(string itemId, int quantity)
|
||
{
|
||
if (quantity <= 0) return false;
|
||
|
||
lock (inventoryLock)
|
||
{
|
||
int oldQuantity = GetItemQuantityUnsafe(itemId);
|
||
|
||
if (!inventory.ContainsKey(itemId))
|
||
{
|
||
inventory[itemId] = new InventoryItem(itemId, quantity);
|
||
}
|
||
else
|
||
{
|
||
inventory[itemId].Quantity += quantity;
|
||
}
|
||
|
||
int newQuantity = inventory[itemId].Quantity;
|
||
GD.Print($"添加物品: {itemId} +{quantity} (总量: {newQuantity})");
|
||
|
||
// 在锁外触发事件
|
||
CallDeferred(nameof(TriggerInventoryChanged), itemId, oldQuantity, newQuantity);
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 从库存中移除物品
|
||
public bool RemoveItem(string itemId, int quantity)
|
||
{
|
||
if (quantity <= 0) return false;
|
||
|
||
lock (inventoryLock)
|
||
{
|
||
if (!inventory.ContainsKey(itemId)) return false;
|
||
|
||
int oldQuantity = inventory[itemId].Quantity;
|
||
if (oldQuantity < quantity) return false; // 库存不足
|
||
|
||
inventory[itemId].Quantity -= quantity;
|
||
|
||
int newQuantity = inventory[itemId].Quantity;
|
||
GD.Print($"移除物品: {itemId} -{quantity} (剩余: {newQuantity})");
|
||
|
||
// 在锁外触发事件
|
||
CallDeferred(nameof(TriggerInventoryChanged), itemId, oldQuantity, newQuantity);
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 设置物品数量
|
||
public void SetItemQuantity(string itemId, int quantity)
|
||
{
|
||
lock (inventoryLock)
|
||
{
|
||
int oldQuantity = GetItemQuantityUnsafe(itemId);
|
||
|
||
if (!inventory.ContainsKey(itemId))
|
||
{
|
||
inventory[itemId] = new InventoryItem(itemId, quantity);
|
||
}
|
||
else
|
||
{
|
||
inventory[itemId].Quantity = quantity;
|
||
}
|
||
|
||
GD.Print($"设置物品数量: {itemId} = {quantity}");
|
||
|
||
// 在锁外触发事件
|
||
CallDeferred(nameof(TriggerInventoryChanged), itemId, oldQuantity, quantity);
|
||
}
|
||
}
|
||
|
||
// 获取物品数量(线程安全)
|
||
public int GetItemQuantity(string itemId)
|
||
{
|
||
lock (inventoryLock)
|
||
{
|
||
return GetItemQuantityUnsafe(itemId);
|
||
}
|
||
}
|
||
|
||
// 获取物品数量(非线程安全,内部使用)
|
||
private int GetItemQuantityUnsafe(string itemId)
|
||
{
|
||
if (inventory.ContainsKey(itemId))
|
||
{
|
||
return inventory[itemId].Quantity;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
// 检查是否有足够的物品
|
||
public bool HasEnoughItems(string itemId, int requiredQuantity)
|
||
{
|
||
return GetItemQuantity(itemId) >= requiredQuantity;
|
||
}
|
||
|
||
// 检查是否有足够的材料(用于配方检查)
|
||
public bool HasEnoughMaterials(Dictionary<string, int> recipe)
|
||
{
|
||
if (recipe == null) return true;
|
||
|
||
lock (inventoryLock)
|
||
{
|
||
foreach (var requirement in recipe)
|
||
{
|
||
if (GetItemQuantityUnsafe(requirement.Key) < requirement.Value)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 消耗材料(用于生产)
|
||
public bool ConsumeMaterials(Dictionary<string, int> recipe)
|
||
{
|
||
if (recipe == null) return true;
|
||
|
||
lock (inventoryLock)
|
||
{
|
||
// 先检查是否有足够材料
|
||
foreach (var requirement in recipe)
|
||
{
|
||
if (GetItemQuantityUnsafe(requirement.Key) < requirement.Value)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 消耗材料
|
||
foreach (var requirement in recipe)
|
||
{
|
||
int oldQuantity = GetItemQuantityUnsafe(requirement.Key);
|
||
inventory[requirement.Key].Quantity -= requirement.Value;
|
||
int newQuantity = inventory[requirement.Key].Quantity;
|
||
|
||
// 在锁外触发事件
|
||
CallDeferred(nameof(TriggerInventoryChanged), requirement.Key, oldQuantity, newQuantity);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 获取所有库存物品
|
||
public Dictionary<string, InventoryItem> GetAllInventory()
|
||
{
|
||
lock (inventoryLock)
|
||
{
|
||
var result = new Dictionary<string, InventoryItem>();
|
||
foreach (var item in inventory)
|
||
{
|
||
result[item.Key] = new InventoryItem(item.Value.ItemId, item.Value.Quantity);
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
|
||
// 获取有库存的物品(数量>0)
|
||
public Dictionary<string, InventoryItem> GetAvailableItems()
|
||
{
|
||
lock (inventoryLock)
|
||
{
|
||
var result = new Dictionary<string, InventoryItem>();
|
||
foreach (var item in inventory)
|
||
{
|
||
if (item.Value.Quantity > 0)
|
||
{
|
||
result[item.Key] = new InventoryItem(item.Value.ItemId, item.Value.Quantity);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
|
||
// 获取指定分类的库存物品
|
||
public Dictionary<string, InventoryItem> GetInventoryByCategory(GameData.ItemCategory category)
|
||
{
|
||
lock (inventoryLock)
|
||
{
|
||
var result = new Dictionary<string, InventoryItem>();
|
||
|
||
foreach (var item in inventory)
|
||
{
|
||
var itemData = GameData.Instance?.GetItem(item.Key);
|
||
if (itemData != null && itemData.Category == category)
|
||
{
|
||
result[item.Key] = new InventoryItem(item.Value.ItemId, item.Value.Quantity);
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
}
|
||
|
||
// 清空库存
|
||
public void ClearInventory()
|
||
{
|
||
Dictionary<string, int> oldQuantities;
|
||
|
||
lock (inventoryLock)
|
||
{
|
||
oldQuantities = new Dictionary<string, int>();
|
||
|
||
foreach (var item in inventory)
|
||
{
|
||
oldQuantities[item.Key] = item.Value.Quantity;
|
||
item.Value.Quantity = 0;
|
||
}
|
||
|
||
GD.Print("清空所有库存");
|
||
}
|
||
|
||
// 在锁外触发事件
|
||
foreach (var item in oldQuantities)
|
||
{
|
||
if (item.Value > 0)
|
||
{
|
||
CallDeferred(nameof(TriggerInventoryChanged), item.Key, item.Value, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获取库存总数量
|
||
public int GetTotalItemCount()
|
||
{
|
||
lock (inventoryLock)
|
||
{
|
||
return inventory.Values.Sum(item => item.Quantity);
|
||
}
|
||
}
|
||
|
||
// 调试:打印所有库存
|
||
public void PrintInventory()
|
||
{
|
||
lock (inventoryLock)
|
||
{
|
||
GD.Print("=== 当前库存 ===");
|
||
foreach (var item in inventory)
|
||
{
|
||
if (item.Value.Quantity > 0)
|
||
{
|
||
var itemData = GameData.Instance?.GetItem(item.Key);
|
||
string itemName = itemData?.Name ?? item.Key;
|
||
GD.Print($"{itemName}: {item.Value.Quantity}");
|
||
}
|
||
}
|
||
GD.Print("===============");
|
||
}
|
||
}
|
||
|
||
// 触发库存变化事件(在主线程中调用)
|
||
private void TriggerInventoryChanged(string itemId, int oldQuantity, int newQuantity)
|
||
{
|
||
InventoryChanged?.Invoke(itemId, oldQuantity, newQuantity);
|
||
}
|
||
|
||
// 清理单例
|
||
public override void _ExitTree()
|
||
{
|
||
if (instance == this)
|
||
{
|
||
instance = null;
|
||
}
|
||
}
|
||
} |