Init
This commit is contained in:
143
scripts/data/CraftingRecipeManager.cs
Normal file
143
scripts/data/CraftingRecipeManager.cs
Normal file
@ -0,0 +1,143 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
|
||||
public partial class CraftingRecipeManager : Node
|
||||
{
|
||||
public static CraftingRecipeManager Instance { get; private set; }
|
||||
|
||||
public class Ingredient
|
||||
{
|
||||
public string ItemId { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
}
|
||||
|
||||
public class CraftingRecipe
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string OutputItem { get; set; }
|
||||
public int OutputQuantity { get; set; }
|
||||
public string CraftingMethod { get; set; }
|
||||
public float CraftingTime { get; set; }
|
||||
public List<Ingredient> Ingredients { get; set; } = new List<Ingredient>();
|
||||
}
|
||||
|
||||
public class CraftingRecipeData
|
||||
{
|
||||
public List<CraftingRecipe> Recipes { get; set; } = new List<CraftingRecipe>();
|
||||
}
|
||||
|
||||
private CraftingRecipeData recipeData;
|
||||
private Dictionary<string, CraftingRecipe> recipeMap = new Dictionary<string, CraftingRecipe>();
|
||||
private Dictionary<string, List<CraftingRecipe>> outputItemMap = new Dictionary<string, List<CraftingRecipe>>();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
LoadCraftingRecipes();
|
||||
}
|
||||
else
|
||||
{
|
||||
QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCraftingRecipes()
|
||||
{
|
||||
string configPath = "res://data/config/crafting_recipes.json";
|
||||
|
||||
if (!FileAccess.FileExists(configPath))
|
||||
{
|
||||
GD.PrintErr($"合成配方配置文件不存在: {configPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
using var file = FileAccess.Open(configPath, FileAccess.ModeFlags.Read);
|
||||
if (file == null)
|
||||
{
|
||||
GD.PrintErr($"无法打开合成配方配置文件: {configPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
string jsonContent = file.GetAsText();
|
||||
|
||||
try
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
recipeData = JsonSerializer.Deserialize<CraftingRecipeData>(jsonContent, options);
|
||||
|
||||
if (recipeData?.Recipes != null)
|
||||
{
|
||||
// 构建配方映射
|
||||
foreach (var recipe in recipeData.Recipes)
|
||||
{
|
||||
recipeMap[recipe.Id] = recipe;
|
||||
|
||||
// 按输出物品分组
|
||||
if (!outputItemMap.ContainsKey(recipe.OutputItem))
|
||||
{
|
||||
outputItemMap[recipe.OutputItem] = new List<CraftingRecipe>();
|
||||
}
|
||||
outputItemMap[recipe.OutputItem].Add(recipe);
|
||||
|
||||
GD.Print($"加载合成配方: {recipe.Id} - {recipe.OutputItem} ({recipe.CraftingMethod})");
|
||||
}
|
||||
|
||||
GD.Print($"成功加载 {recipeData.Recipes.Count} 个合成配方");
|
||||
}
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
GD.PrintErr($"解析合成配方配置文件失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public List<CraftingRecipe> GetAllRecipes()
|
||||
{
|
||||
return recipeData?.Recipes ?? new List<CraftingRecipe>();
|
||||
}
|
||||
|
||||
public CraftingRecipe GetRecipe(string recipeId)
|
||||
{
|
||||
return recipeMap.GetValueOrDefault(recipeId);
|
||||
}
|
||||
|
||||
public List<CraftingRecipe> GetRecipesForItem(string itemId)
|
||||
{
|
||||
return outputItemMap.GetValueOrDefault(itemId) ?? new List<CraftingRecipe>();
|
||||
}
|
||||
|
||||
public bool CanCraft(string recipeId)
|
||||
{
|
||||
var recipe = GetRecipe(recipeId);
|
||||
if (recipe == null || InventoryManager.Instance == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有足够的材料
|
||||
foreach (var ingredient in recipe.Ingredients)
|
||||
{
|
||||
if (InventoryManager.Instance.GetItemQuantity(ingredient.ItemId) < ingredient.Quantity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
197
scripts/data/GameData.cs
Normal file
197
scripts/data/GameData.cs
Normal file
@ -0,0 +1,197 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public partial class GameData : Node
|
||||
{
|
||||
// 物品分类枚举
|
||||
public enum ItemCategory
|
||||
{
|
||||
RawMaterial, // 原材料
|
||||
ProcessedMaterial, // 冶炼成品
|
||||
Building, // 建筑
|
||||
Component, // 组件
|
||||
Product // 产品
|
||||
}
|
||||
|
||||
// 物品数据结构
|
||||
public class ItemData
|
||||
{
|
||||
public string Id { get; set; } // 物品ID
|
||||
public string Name { get; set; } // 物品名称
|
||||
public ItemCategory Category { get; set; } // 物品分类
|
||||
public string Description { get; set; } // 物品描述
|
||||
public Dictionary<string, int> Recipe { get; set; } // 合成配方
|
||||
public float CraftTime { get; set; } // 合成时间
|
||||
public float PowerConsumption { get; set; } // 耗电量
|
||||
public string IconPath { get; set; } // 图标路径
|
||||
}
|
||||
|
||||
// 单例实例
|
||||
private static GameData instance;
|
||||
public static GameData Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
// 物品数据字典
|
||||
private Dictionary<string, ItemData> items = new Dictionary<string, ItemData>();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
instance = this; // 设置单例实例
|
||||
LoadItemsFromCSV();
|
||||
}
|
||||
|
||||
// 从CSV文件加载物品数据
|
||||
private void LoadItemsFromCSV()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 读取CSV文件
|
||||
string csvPath = "res://data/config/items.csv";
|
||||
if (!Godot.FileAccess.FileExists(csvPath))
|
||||
{
|
||||
GD.PrintErr("物品数据文件不存在: " + csvPath);
|
||||
return;
|
||||
}
|
||||
|
||||
var file = Godot.FileAccess.Open(csvPath, Godot.FileAccess.ModeFlags.Read);
|
||||
if (file == null)
|
||||
{
|
||||
GD.PrintErr("无法打开物品数据文件: " + csvPath);
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取标题行
|
||||
string header = file.GetLine();
|
||||
string[] headers = header.Split(',');
|
||||
|
||||
// 读取数据行
|
||||
while (!file.EofReached())
|
||||
{
|
||||
string line = file.GetLine();
|
||||
if (string.IsNullOrEmpty(line)) continue;
|
||||
|
||||
string[] values = line.Split(',');
|
||||
if (values.Length != headers.Length) continue;
|
||||
|
||||
// 创建物品数据
|
||||
var item = new ItemData
|
||||
{
|
||||
Id = values[0],
|
||||
Name = values[1],
|
||||
Category = (ItemCategory)Enum.Parse(typeof(ItemCategory), values[2]),
|
||||
Description = values[3],
|
||||
Recipe = ParseRecipe(values[4]),
|
||||
CraftTime = float.Parse(values[5]),
|
||||
PowerConsumption = float.Parse(values[6]),
|
||||
IconPath = values[7]
|
||||
};
|
||||
|
||||
AddItem(item);
|
||||
}
|
||||
|
||||
file.Close();
|
||||
GD.Print("成功加载物品数据");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GD.PrintErr("加载物品数据时出错: " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// 解析配方字符串
|
||||
private Dictionary<string, int> ParseRecipe(string recipeStr)
|
||||
{
|
||||
if (string.IsNullOrEmpty(recipeStr) || recipeStr == "null")
|
||||
return null;
|
||||
|
||||
var recipe = new Dictionary<string, int>();
|
||||
string[] pairs = recipeStr.Split(';');
|
||||
|
||||
foreach (string pair in pairs)
|
||||
{
|
||||
string[] parts = pair.Split(':');
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
string itemId = parts[0];
|
||||
int amount = int.Parse(parts[1]);
|
||||
recipe[itemId] = amount;
|
||||
}
|
||||
}
|
||||
|
||||
return recipe;
|
||||
}
|
||||
|
||||
// 添加物品
|
||||
private void AddItem(ItemData item)
|
||||
{
|
||||
items[item.Id] = item;
|
||||
}
|
||||
|
||||
// 获取物品数据
|
||||
public ItemData GetItem(string id)
|
||||
{
|
||||
if (items.ContainsKey(id))
|
||||
{
|
||||
return items[id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取所有物品
|
||||
public Dictionary<string, ItemData> GetAllItems()
|
||||
{
|
||||
return items;
|
||||
}
|
||||
|
||||
// 获取指定分类的所有物品
|
||||
public Dictionary<string, ItemData> GetItemsByCategory(ItemCategory category)
|
||||
{
|
||||
var result = new Dictionary<string, ItemData>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Value.Category == category)
|
||||
{
|
||||
result[item.Key] = item.Value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 检查是否有足够的材料进行合成
|
||||
public bool HasEnoughMaterials(string itemId, Dictionary<string, int> inventory)
|
||||
{
|
||||
var item = GetItem(itemId);
|
||||
if (item == null || item.Recipe == null) return false;
|
||||
|
||||
foreach (var requirement in item.Recipe)
|
||||
{
|
||||
if (!inventory.ContainsKey(requirement.Key) ||
|
||||
inventory[requirement.Key] < requirement.Value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 计算合成所需时间
|
||||
public float GetCraftTime(string itemId)
|
||||
{
|
||||
var item = GetItem(itemId);
|
||||
return item?.CraftTime ?? 0f;
|
||||
}
|
||||
|
||||
// 计算合成所需电力
|
||||
public float GetPowerConsumption(string itemId)
|
||||
{
|
||||
var item = GetItem(itemId);
|
||||
return item?.PowerConsumption ?? 0f;
|
||||
}
|
||||
}
|
||||
169
scripts/data/ResourceCategoryManager.cs
Normal file
169
scripts/data/ResourceCategoryManager.cs
Normal file
@ -0,0 +1,169 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
|
||||
public partial class ResourceCategoryManager : Node
|
||||
{
|
||||
// 资源分类数据结构
|
||||
public class ResourceCategory
|
||||
{
|
||||
public string CategoryName { get; set; }
|
||||
public List<string> ItemIds { get; set; }
|
||||
}
|
||||
|
||||
// 单例实例
|
||||
private static ResourceCategoryManager instance;
|
||||
public static ResourceCategoryManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
// 资源分类列表
|
||||
private List<ResourceCategory> categories = new List<ResourceCategory>();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
GD.Print("ResourceCategoryManager _Ready 开始");
|
||||
instance = this; // 设置单例实例
|
||||
LoadResourceCategories();
|
||||
}
|
||||
|
||||
// 从JSON文件加载资源分类配置
|
||||
private void LoadResourceCategories()
|
||||
{
|
||||
try
|
||||
{
|
||||
string jsonPath = "res://data/config/resource_categories.json";
|
||||
GD.Print($"尝试加载配置文件: {jsonPath}");
|
||||
|
||||
if (!Godot.FileAccess.FileExists(jsonPath))
|
||||
{
|
||||
GD.PrintErr("资源分类配置文件不存在: " + jsonPath);
|
||||
return;
|
||||
}
|
||||
|
||||
var file = Godot.FileAccess.Open(jsonPath, Godot.FileAccess.ModeFlags.Read);
|
||||
if (file == null)
|
||||
{
|
||||
GD.PrintErr("无法打开资源分类配置文件: " + jsonPath);
|
||||
return;
|
||||
}
|
||||
|
||||
string jsonContent = file.GetAsText();
|
||||
file.Close();
|
||||
|
||||
// GD.Print($"JSON文件内容长度: {jsonContent.Length}");
|
||||
// GD.Print($"JSON文件内容: {jsonContent}");
|
||||
|
||||
// 解析JSON
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
categories = JsonSerializer.Deserialize<List<ResourceCategory>>(jsonContent, options);
|
||||
|
||||
if (categories == null)
|
||||
{
|
||||
GD.PrintErr("JSON反序列化结果为null");
|
||||
categories = new List<ResourceCategory>();
|
||||
return;
|
||||
}
|
||||
|
||||
GD.Print($"成功加载资源分类配置,共 {categories.Count} 个分类");
|
||||
|
||||
// 打印每个分类的详细信息
|
||||
foreach (var category in categories)
|
||||
{
|
||||
GD.Print($"分类: {category.CategoryName}, 物品数量: {category.ItemIds?.Count ?? 0}");
|
||||
if (category.ItemIds != null)
|
||||
{
|
||||
foreach (var itemId in category.ItemIds)
|
||||
{
|
||||
GD.Print($" - {itemId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GD.PrintErr("加载资源分类配置时出错: " + e.Message);
|
||||
GD.PrintErr("堆栈跟踪: " + e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有分类
|
||||
public List<ResourceCategory> GetAllCategories()
|
||||
{
|
||||
GD.Print($"GetAllCategories 被调用,返回 {categories.Count} 个分类");
|
||||
return categories;
|
||||
}
|
||||
|
||||
// 根据分类名称获取分类
|
||||
public ResourceCategory GetCategoryByName(string categoryName)
|
||||
{
|
||||
return categories.Find(c => c.CategoryName == categoryName);
|
||||
}
|
||||
|
||||
// 根据物品ID获取所属分类
|
||||
public ResourceCategory GetCategoryByItemId(string itemId)
|
||||
{
|
||||
return categories.Find(c => c.ItemIds.Contains(itemId));
|
||||
}
|
||||
|
||||
// 获取指定分类的所有物品数据
|
||||
public Dictionary<string, GameData.ItemData> GetItemsByCategory(string categoryName)
|
||||
{
|
||||
GD.Print($"GetItemsByCategory 被调用,分类名称: {categoryName}");
|
||||
|
||||
var category = GetCategoryByName(categoryName);
|
||||
if (category == null)
|
||||
{
|
||||
GD.PrintErr($"未找到分类: {categoryName}");
|
||||
return new Dictionary<string, GameData.ItemData>();
|
||||
}
|
||||
|
||||
GD.Print($"找到分类 {categoryName},包含 {category.ItemIds?.Count ?? 0} 个物品ID");
|
||||
|
||||
// 检查GameData.Instance
|
||||
if (GameData.Instance == null)
|
||||
{
|
||||
GD.PrintErr("GameData.Instance 为 null!");
|
||||
return new Dictionary<string, GameData.ItemData>();
|
||||
}
|
||||
|
||||
var result = new Dictionary<string, GameData.ItemData>();
|
||||
foreach (string itemId in category.ItemIds)
|
||||
{
|
||||
// GD.Print($"尝试获取物品: {itemId}");
|
||||
var item = GameData.Instance.GetItem(itemId);
|
||||
if (item != null)
|
||||
{
|
||||
GD.Print($"成功获取物品: {itemId} - {item.Name}");
|
||||
result[itemId] = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.PrintErr($"未找到物品: {itemId}");
|
||||
}
|
||||
}
|
||||
|
||||
GD.Print($"GetItemsByCategory 返回 {result.Count} 个物品");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取分类名称列表
|
||||
public List<string> GetCategoryNames()
|
||||
{
|
||||
var names = new List<string>();
|
||||
foreach (var category in categories)
|
||||
{
|
||||
names.Add(category.CategoryName);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user