添加基础的生产线内容-不少bug
This commit is contained in:
@ -43,6 +43,51 @@ public partial class GameScene : Control
|
||||
{
|
||||
GD.Print("GameScene _Ready 开始");
|
||||
|
||||
// 先初始化管理器系统,确保在UI创建之前完成
|
||||
InitializeManagers();
|
||||
|
||||
// 等待一帧确保管理器完全初始化
|
||||
CallDeferred(nameof(InitializeUI));
|
||||
}
|
||||
|
||||
private void InitializeManagers()
|
||||
{
|
||||
// 创建ProductionLineManager
|
||||
var productionLineManager = new ProductionLineManager();
|
||||
productionLineManager.Name = "ProductionLineManager";
|
||||
AddChild(productionLineManager);
|
||||
|
||||
// 创建ProductionProcessor
|
||||
var productionProcessor = new ProductionProcessor();
|
||||
productionProcessor.Name = "ProductionProcessor";
|
||||
AddChild(productionProcessor);
|
||||
|
||||
GD.Print("自动产线管理器初始化完成");
|
||||
}
|
||||
|
||||
private void InitializeUI()
|
||||
{
|
||||
GD.Print("开始初始化UI");
|
||||
|
||||
// 测试ProductionLineManager是否正常
|
||||
var productionLineManager = ProductionLineManager.Instance;
|
||||
if (productionLineManager != null)
|
||||
{
|
||||
var allLines = productionLineManager.GetAllProductionLines();
|
||||
GD.Print($"ProductionLineManager已初始化,共有 {allLines.Count} 个生产线");
|
||||
|
||||
var categories = productionLineManager.GetAllCategories();
|
||||
GD.Print($"生产线分类数: {categories.Count}");
|
||||
foreach (var category in categories)
|
||||
{
|
||||
GD.Print($"- 分类: {category}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.PrintErr("ProductionLineManager 仍然为null!");
|
||||
}
|
||||
|
||||
// 获取UI引用
|
||||
powerGenerationLabel = GetNode<Label>("HSplitContainer/LeftPanel/VBoxContainer/PowerInfo/MarginContainer/VBoxContainer/PowerRow1/PowerGeneration");
|
||||
powerConsumptionLabel = GetNode<Label>("HSplitContainer/LeftPanel/VBoxContainer/PowerInfo/MarginContainer/VBoxContainer/PowerRow1/PowerConsumption");
|
||||
@ -131,6 +176,246 @@ public partial class GameScene : Control
|
||||
GD.Print("按下C键,尝试开始铁块合成");
|
||||
}
|
||||
}
|
||||
|
||||
// 按P键测试自动产线
|
||||
if (keyEvent.Keycode == Key.P)
|
||||
{
|
||||
TestProductionLine();
|
||||
}
|
||||
|
||||
// 按L键列出所有产线
|
||||
if (keyEvent.Keycode == Key.L)
|
||||
{
|
||||
ListAllProductionLines();
|
||||
}
|
||||
|
||||
// 按B键测试生产线UI
|
||||
if (keyEvent.Keycode == Key.B)
|
||||
{
|
||||
TestProductionLineUI();
|
||||
}
|
||||
|
||||
// 按R键刷新标签页
|
||||
if (keyEvent.Keycode == Key.R)
|
||||
{
|
||||
RefreshProductionLineTabs();
|
||||
}
|
||||
|
||||
// 按I键查看库存状态
|
||||
if (keyEvent.Keycode == Key.I)
|
||||
{
|
||||
ShowInventoryStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TestProductionLine()
|
||||
{
|
||||
var productionLineManager = ProductionLineManager.Instance;
|
||||
if (productionLineManager == null)
|
||||
{
|
||||
GD.PrintErr("ProductionLineManager not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// 给库存添加一些建筑和材料用于测试
|
||||
var inventoryManager = InventoryManager.Instance;
|
||||
if (inventoryManager != null)
|
||||
{
|
||||
inventoryManager.AddItem("mining_drill", 2); // 添加2个钻机
|
||||
inventoryManager.AddItem("furnace", 1); // 添加1个熔炉
|
||||
inventoryManager.AddItem("iron_ore", 10); // 添加10个铁矿用于冶炼测试
|
||||
GD.Print("已添加测试物品到库存");
|
||||
}
|
||||
|
||||
// 测试添加铁矿采集产线
|
||||
productionLineManager.AddBuilding("iron_ore_extraction", 1);
|
||||
|
||||
// 测试添加自动冶炼产线
|
||||
productionLineManager.AddBuilding("iron_smelting_auto", 1);
|
||||
|
||||
GD.Print("已启动测试产线");
|
||||
}
|
||||
|
||||
private void ListAllProductionLines()
|
||||
{
|
||||
var productionLineManager = ProductionLineManager.Instance;
|
||||
if (productionLineManager == null)
|
||||
{
|
||||
GD.PrintErr("ProductionLineManager not found");
|
||||
return;
|
||||
}
|
||||
|
||||
var allLines = productionLineManager.GetAllProductionLines();
|
||||
GD.Print($"总共有 {allLines.Count} 个产线:");
|
||||
|
||||
foreach (var line in allLines)
|
||||
{
|
||||
string requirements = "";
|
||||
if (line.BuildingRequirements != null && line.BuildingRequirements.Count > 0)
|
||||
{
|
||||
var req = line.BuildingRequirements[0];
|
||||
var item = GameData.Instance?.GetItem(req.ItemId);
|
||||
requirements = $"需要: {req.Quantity}x{item?.Name ?? req.ItemId}";
|
||||
if (line.BuildingRequirements.Count > 1)
|
||||
{
|
||||
requirements += "...";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
requirements = "无需求";
|
||||
}
|
||||
|
||||
GD.Print($"- {line.Name} ({line.Category}): {line.ProductionTime}s, {line.PowerConsumption}W, {requirements}");
|
||||
}
|
||||
|
||||
var activeLines = productionLineManager.GetAllActiveProductionLines();
|
||||
GD.Print($"活跃产线: {activeLines.Count} 个");
|
||||
|
||||
foreach (var kvp in activeLines)
|
||||
{
|
||||
var activeLine = kvp.Value;
|
||||
if (activeLine.IsActive)
|
||||
{
|
||||
var line = productionLineManager.GetProductionLine(activeLine.ProductionLineId);
|
||||
GD.Print($" 活跃: {line?.Name} - {activeLine.BuildingCount} 个建筑, {activeLine.ProductionRate:F2}/s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TestProductionLineUI()
|
||||
{
|
||||
// 给库存添加一些建筑用于测试
|
||||
var inventoryManager = InventoryManager.Instance;
|
||||
if (inventoryManager != null)
|
||||
{
|
||||
// 建筑设施
|
||||
inventoryManager.AddItem("mining_drill", 10); // 添加10个钻机
|
||||
inventoryManager.AddItem("furnace", 8); // 添加8个熔炉
|
||||
inventoryManager.AddItem("smelter", 5); // 添加5个冶炼厂
|
||||
inventoryManager.AddItem("miner", 6); // 添加6个采矿机
|
||||
inventoryManager.AddItem("assembler", 3); // 添加3个组装机
|
||||
inventoryManager.AddItem("chemical_plant", 2); // 添加2个化工厂
|
||||
|
||||
// 原材料
|
||||
inventoryManager.AddItem("iron_ore", 50); // 添加50个铁矿
|
||||
inventoryManager.AddItem("copper_ore", 40); // 添加40个铜矿
|
||||
inventoryManager.AddItem("coal_ore", 60); // 添加60个煤矿(修正ID)
|
||||
inventoryManager.AddItem("stone_ore", 80); // 添加80个石矿(修正ID)
|
||||
inventoryManager.AddItem("water", 100); // 添加100个水
|
||||
inventoryManager.AddItem("crude_oil", 30); // 添加30个原油
|
||||
|
||||
// 加工材料
|
||||
inventoryManager.AddItem("iron_ingot", 25); // 添加25个铁块
|
||||
inventoryManager.AddItem("copper_ingot", 20); // 添加20个铜块
|
||||
|
||||
GD.Print("已添加测试建筑设施和材料到库存:");
|
||||
GD.Print("建筑设施: 钻机x10, 熔炉x8, 冶炼厂x5, 采矿机x6, 组装机x3, 化工厂x2");
|
||||
GD.Print("原材料: 铁矿x50, 铜矿x40, 煤矿x60, 石矿x80, 水x100, 原油x30");
|
||||
GD.Print("加工材料: 铁块x25, 铜块x20");
|
||||
GD.Print("现在可以在生产线和合成标签中测试各种功能了!");
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshProductionLineTabs()
|
||||
{
|
||||
GD.Print("刷新生产线标签页");
|
||||
|
||||
if (categoryTabs != null)
|
||||
{
|
||||
var dynamicTabManager = categoryTabs as DynamicTabManager;
|
||||
if (dynamicTabManager != null)
|
||||
{
|
||||
dynamicTabManager.RefreshTabs();
|
||||
GD.Print("已刷新标签页");
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.PrintErr("categoryTabs 不是 DynamicTabManager 类型");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.PrintErr("categoryTabs 为null");
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowInventoryStatus()
|
||||
{
|
||||
GD.Print("=== 当前库存状态 ===");
|
||||
|
||||
var inventoryManager = InventoryManager.Instance;
|
||||
if (inventoryManager == null)
|
||||
{
|
||||
GD.PrintErr("InventoryManager 实例为null");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有物品类别并显示库存
|
||||
var gameData = GameData.Instance;
|
||||
if (gameData == null)
|
||||
{
|
||||
GD.PrintErr("GameData 实例为null");
|
||||
return;
|
||||
}
|
||||
|
||||
var allItems = gameData.GetAllItems();
|
||||
bool hasItems = false;
|
||||
|
||||
GD.Print("建筑设施:");
|
||||
foreach (var kvp in allItems)
|
||||
{
|
||||
var itemId = kvp.Key;
|
||||
var itemData = kvp.Value;
|
||||
if (itemData.Category == GameData.ItemCategory.Building || itemData.Category == GameData.ItemCategory.ProductionDevice)
|
||||
{
|
||||
int quantity = inventoryManager.GetItemQuantity(itemId);
|
||||
if (quantity > 0)
|
||||
{
|
||||
GD.Print($" {itemData.Name}: {quantity} 个");
|
||||
hasItems = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GD.Print("原材料:");
|
||||
foreach (var kvp in allItems)
|
||||
{
|
||||
var itemId = kvp.Key;
|
||||
var itemData = kvp.Value;
|
||||
if (itemData.Category == GameData.ItemCategory.RawMaterial)
|
||||
{
|
||||
int quantity = inventoryManager.GetItemQuantity(itemId);
|
||||
if (quantity > 0)
|
||||
{
|
||||
GD.Print($" {itemData.Name}: {quantity} 个");
|
||||
hasItems = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GD.Print("加工材料:");
|
||||
foreach (var kvp in allItems)
|
||||
{
|
||||
var itemId = kvp.Key;
|
||||
var itemData = kvp.Value;
|
||||
if (itemData.Category == GameData.ItemCategory.ProcessedMaterial)
|
||||
{
|
||||
int quantity = inventoryManager.GetItemQuantity(itemId);
|
||||
if (quantity > 0)
|
||||
{
|
||||
GD.Print($" {itemData.Name}: {quantity} 个");
|
||||
hasItems = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasItems)
|
||||
{
|
||||
GD.Print("库存为空,按B键添加测试物品");
|
||||
}
|
||||
|
||||
GD.Print("=================");
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,7 @@ public partial class GameData : Node
|
||||
RawMaterial, // 原材料
|
||||
ProcessedMaterial, // 冶炼成品
|
||||
Building, // 建筑
|
||||
ProductionDevice, // 生产设备
|
||||
Component, // 组件
|
||||
Product // 产品
|
||||
}
|
||||
|
||||
267
scripts/production/ProductionLineManager.cs
Normal file
267
scripts/production/ProductionLineManager.cs
Normal file
@ -0,0 +1,267 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
|
||||
public partial class ProductionLineManager : Node
|
||||
{
|
||||
public static ProductionLineManager Instance { get; private set; }
|
||||
|
||||
public class ProductionRecipeItem
|
||||
{
|
||||
public string ItemId { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
}
|
||||
|
||||
public class ProductionRecipe
|
||||
{
|
||||
public List<ProductionRecipeItem> Inputs { get; set; } = new List<ProductionRecipeItem>();
|
||||
public List<ProductionRecipeItem> Outputs { get; set; } = new List<ProductionRecipeItem>();
|
||||
}
|
||||
|
||||
public class ProductionLine
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Category { get; set; }
|
||||
public string Description { get; set; }
|
||||
public float ProductionTime { get; set; }
|
||||
public int PowerConsumption { get; set; }
|
||||
public List<ProductionRecipeItem> BuildingRequirements { get; set; } = new List<ProductionRecipeItem>();
|
||||
public ProductionRecipe Recipe { get; set; } = new ProductionRecipe();
|
||||
}
|
||||
|
||||
public class ProductionLineData
|
||||
{
|
||||
public List<ProductionLine> ProductionLines { get; set; } = new List<ProductionLine>();
|
||||
}
|
||||
|
||||
// 活跃的产线实例
|
||||
public class ActiveProductionLine
|
||||
{
|
||||
public string ProductionLineId { get; set; }
|
||||
public int BuildingCount { get; set; } = 0; // 建筑数量
|
||||
public float RemainingTime { get; set; } = 0; // 当前循环剩余时间
|
||||
public bool IsActive { get; set; } = false; // 是否激活
|
||||
public float ProductionRate { get; set; } = 0; // 每秒产出率
|
||||
public int TotalPowerConsumption { get; set; } = 0; // 总功耗
|
||||
}
|
||||
|
||||
private ProductionLineData productionLineData;
|
||||
private Dictionary<string, ProductionLine> productionLineMap = new Dictionary<string, ProductionLine>();
|
||||
private Dictionary<string, List<ProductionLine>> categoryMap = new Dictionary<string, List<ProductionLine>>();
|
||||
private Dictionary<string, ActiveProductionLine> activeProductionLines = new Dictionary<string, ActiveProductionLine>();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
LoadProductionLines();
|
||||
}
|
||||
else
|
||||
{
|
||||
QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadProductionLines()
|
||||
{
|
||||
string configPath = "res://data/config/production_lines.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
|
||||
};
|
||||
|
||||
productionLineData = JsonSerializer.Deserialize<ProductionLineData>(jsonContent, options);
|
||||
|
||||
if (productionLineData?.ProductionLines != null)
|
||||
{
|
||||
// 构建产线映射
|
||||
foreach (var line in productionLineData.ProductionLines)
|
||||
{
|
||||
productionLineMap[line.Id] = line;
|
||||
|
||||
// 按分类分组
|
||||
if (!categoryMap.ContainsKey(line.Category))
|
||||
{
|
||||
categoryMap[line.Category] = new List<ProductionLine>();
|
||||
}
|
||||
categoryMap[line.Category].Add(line);
|
||||
|
||||
GD.Print($"加载自动产线: {line.Id} - {line.Name} ({line.Category})");
|
||||
}
|
||||
|
||||
GD.Print($"成功加载 {productionLineData.ProductionLines.Count} 个自动产线");
|
||||
}
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
GD.PrintErr($"解析自动产线配置文件失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public List<ProductionLine> GetAllProductionLines()
|
||||
{
|
||||
return productionLineData?.ProductionLines ?? new List<ProductionLine>();
|
||||
}
|
||||
|
||||
public ProductionLine GetProductionLine(string lineId)
|
||||
{
|
||||
return productionLineMap.GetValueOrDefault(lineId);
|
||||
}
|
||||
|
||||
public List<ProductionLine> GetProductionLinesByCategory(string category)
|
||||
{
|
||||
return categoryMap.GetValueOrDefault(category) ?? new List<ProductionLine>();
|
||||
}
|
||||
|
||||
public List<string> GetAllCategories()
|
||||
{
|
||||
return new List<string>(categoryMap.Keys);
|
||||
}
|
||||
|
||||
// 建筑管理
|
||||
public void AddBuilding(string productionLineId, int count = 1)
|
||||
{
|
||||
var productionLine = GetProductionLine(productionLineId);
|
||||
if (productionLine == null)
|
||||
{
|
||||
GD.PrintErr($"找不到产线: {productionLineId}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查建筑需求
|
||||
if (productionLine.BuildingRequirements == null || productionLine.BuildingRequirements.Count == 0)
|
||||
{
|
||||
GD.PrintErr($"产线 {productionLine.Name} 没有定义建筑需求");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否有足够的建筑材料
|
||||
var inventoryManager = InventoryManager.Instance;
|
||||
if (inventoryManager == null)
|
||||
{
|
||||
GD.PrintErr("InventoryManager实例为null");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证所有建筑需求
|
||||
foreach (var requirement in productionLine.BuildingRequirements)
|
||||
{
|
||||
int available = inventoryManager.GetItemQuantity(requirement.ItemId);
|
||||
int needed = requirement.Quantity * count;
|
||||
|
||||
if (available < needed)
|
||||
{
|
||||
var itemData = GameData.Instance?.GetItem(requirement.ItemId);
|
||||
string itemName = itemData?.Name ?? requirement.ItemId;
|
||||
GD.Print($"建筑材料不足,需要 {needed} 个 {itemName},当前只有 {available} 个");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 扣除建筑材料
|
||||
foreach (var requirement in productionLine.BuildingRequirements)
|
||||
{
|
||||
int consumeAmount = requirement.Quantity * count;
|
||||
inventoryManager.RemoveItem(requirement.ItemId, consumeAmount);
|
||||
}
|
||||
|
||||
// 添加到活跃产线
|
||||
if (!activeProductionLines.ContainsKey(productionLineId))
|
||||
{
|
||||
activeProductionLines[productionLineId] = new ActiveProductionLine
|
||||
{
|
||||
ProductionLineId = productionLineId
|
||||
};
|
||||
}
|
||||
|
||||
var activeLine = activeProductionLines[productionLineId];
|
||||
activeLine.BuildingCount += count;
|
||||
activeLine.IsActive = true;
|
||||
activeLine.ProductionRate = activeLine.BuildingCount / productionLine.ProductionTime; // 每秒产出率
|
||||
activeLine.TotalPowerConsumption = activeLine.BuildingCount * productionLine.PowerConsumption;
|
||||
|
||||
GD.Print($"成功添加 {count} 个设备到产线 {productionLine.Name}");
|
||||
GD.Print($"当前产线状态: {activeLine.BuildingCount} 个建筑, 产出率: {activeLine.ProductionRate:F2}/s, 功耗: {activeLine.TotalPowerConsumption}W");
|
||||
}
|
||||
|
||||
public void RemoveBuilding(string productionLineId, int count = 1)
|
||||
{
|
||||
if (!activeProductionLines.ContainsKey(productionLineId))
|
||||
{
|
||||
GD.Print($"产线 {productionLineId} 没有建筑可移除");
|
||||
return;
|
||||
}
|
||||
|
||||
var activeLine = activeProductionLines[productionLineId];
|
||||
var productionLine = GetProductionLine(productionLineId);
|
||||
|
||||
count = Mathf.Min(count, activeLine.BuildingCount);
|
||||
if (count <= 0) return;
|
||||
|
||||
activeLine.BuildingCount -= count;
|
||||
|
||||
if (activeLine.BuildingCount <= 0)
|
||||
{
|
||||
activeLine.IsActive = false;
|
||||
activeLine.ProductionRate = 0;
|
||||
activeLine.TotalPowerConsumption = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
activeLine.ProductionRate = activeLine.BuildingCount / productionLine.ProductionTime;
|
||||
activeLine.TotalPowerConsumption = activeLine.BuildingCount * productionLine.PowerConsumption;
|
||||
}
|
||||
|
||||
// 归还建筑材料到库存
|
||||
var inventoryManager = InventoryManager.Instance;
|
||||
if (inventoryManager != null && productionLine.BuildingRequirements != null)
|
||||
{
|
||||
foreach (var requirement in productionLine.BuildingRequirements)
|
||||
{
|
||||
int returnAmount = requirement.Quantity * count;
|
||||
inventoryManager.AddItem(requirement.ItemId, returnAmount);
|
||||
}
|
||||
}
|
||||
|
||||
GD.Print($"移除 {count} 个设备从产线 {productionLine.Name}");
|
||||
GD.Print($"当前产线状态: {activeLine.BuildingCount} 个建筑, 产出率: {activeLine.ProductionRate:F2}/s, 功耗: {activeLine.TotalPowerConsumption}W");
|
||||
}
|
||||
|
||||
public ActiveProductionLine GetActiveProductionLine(string productionLineId)
|
||||
{
|
||||
return activeProductionLines.GetValueOrDefault(productionLineId);
|
||||
}
|
||||
|
||||
public Dictionary<string, ActiveProductionLine> GetAllActiveProductionLines()
|
||||
{
|
||||
return activeProductionLines;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
177
scripts/production/ProductionProcessor.cs
Normal file
177
scripts/production/ProductionProcessor.cs
Normal file
@ -0,0 +1,177 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public partial class ProductionProcessor : Node
|
||||
{
|
||||
public static ProductionProcessor Instance { get; private set; }
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
GD.Print("ProductionProcessor 初始化完成");
|
||||
}
|
||||
else
|
||||
{
|
||||
QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
ProcessAllProductionLines((float)delta);
|
||||
}
|
||||
|
||||
private void ProcessAllProductionLines(float deltaTime)
|
||||
{
|
||||
var productionLineManager = ProductionLineManager.Instance;
|
||||
if (productionLineManager == null) return;
|
||||
|
||||
var activeLines = productionLineManager.GetAllActiveProductionLines();
|
||||
|
||||
foreach (var kvp in activeLines)
|
||||
{
|
||||
var activeLine = kvp.Value;
|
||||
if (!activeLine.IsActive || activeLine.BuildingCount <= 0) continue;
|
||||
|
||||
ProcessProductionLine(activeLine, deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessProductionLine(ProductionLineManager.ActiveProductionLine activeLine, float deltaTime)
|
||||
{
|
||||
var productionLine = ProductionLineManager.Instance?.GetProductionLine(activeLine.ProductionLineId);
|
||||
if (productionLine == null) return;
|
||||
|
||||
// 更新生产时间
|
||||
activeLine.RemainingTime -= deltaTime;
|
||||
|
||||
if (activeLine.RemainingTime <= 0)
|
||||
{
|
||||
// 检查是否有足够的原料
|
||||
if (CheckInputMaterials(productionLine, activeLine.BuildingCount))
|
||||
{
|
||||
// 消耗原料
|
||||
ConsumeInputMaterials(productionLine, activeLine.BuildingCount);
|
||||
|
||||
// 生产产品
|
||||
ProduceOutputItems(productionLine, activeLine.BuildingCount);
|
||||
|
||||
// 重置生产时间
|
||||
activeLine.RemainingTime = productionLine.ProductionTime;
|
||||
|
||||
GD.Print($"产线 {productionLine.Name} 完成一轮生产,{activeLine.BuildingCount} 个建筑同时运行");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 原料不足,暂停生产
|
||||
activeLine.RemainingTime = 0.1f; // 短暂等待后再检查
|
||||
GD.Print($"产线 {productionLine.Name} 原料不足,暂停生产");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckInputMaterials(ProductionLineManager.ProductionLine productionLine, int buildingCount)
|
||||
{
|
||||
var inventoryManager = InventoryManager.Instance;
|
||||
if (inventoryManager == null) return false;
|
||||
|
||||
// 检查所有输入材料
|
||||
foreach (var input in productionLine.Recipe.Inputs)
|
||||
{
|
||||
int requiredQuantity = input.Quantity * buildingCount;
|
||||
int availableQuantity = inventoryManager.GetItemQuantity(input.ItemId);
|
||||
|
||||
if (availableQuantity < requiredQuantity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ConsumeInputMaterials(ProductionLineManager.ProductionLine productionLine, int buildingCount)
|
||||
{
|
||||
var inventoryManager = InventoryManager.Instance;
|
||||
if (inventoryManager == null) return;
|
||||
|
||||
foreach (var input in productionLine.Recipe.Inputs)
|
||||
{
|
||||
int consumeQuantity = input.Quantity * buildingCount;
|
||||
inventoryManager.RemoveItem(input.ItemId, consumeQuantity);
|
||||
|
||||
var itemData = GameData.Instance?.GetItem(input.ItemId);
|
||||
string itemName = itemData?.Name ?? input.ItemId;
|
||||
GD.Print($"消耗材料: {itemName} x{consumeQuantity}");
|
||||
}
|
||||
}
|
||||
|
||||
private void ProduceOutputItems(ProductionLineManager.ProductionLine productionLine, int buildingCount)
|
||||
{
|
||||
var inventoryManager = InventoryManager.Instance;
|
||||
if (inventoryManager == null) return;
|
||||
|
||||
foreach (var output in productionLine.Recipe.Outputs)
|
||||
{
|
||||
int produceQuantity = output.Quantity * buildingCount;
|
||||
inventoryManager.AddItem(output.ItemId, produceQuantity);
|
||||
|
||||
var itemData = GameData.Instance?.GetItem(output.ItemId);
|
||||
string itemName = itemData?.Name ?? output.ItemId;
|
||||
GD.Print($"生产物品: {itemName} x{produceQuantity}");
|
||||
}
|
||||
}
|
||||
|
||||
// 公共方法:获取产线当前状态信息
|
||||
public ProductionLineStatus GetProductionLineStatus(string productionLineId)
|
||||
{
|
||||
var activeLine = ProductionLineManager.Instance?.GetActiveProductionLine(productionLineId);
|
||||
var productionLine = ProductionLineManager.Instance?.GetProductionLine(productionLineId);
|
||||
|
||||
if (activeLine == null || productionLine == null)
|
||||
{
|
||||
return new ProductionLineStatus
|
||||
{
|
||||
IsActive = false,
|
||||
Progress = 0,
|
||||
ProductionRate = 0,
|
||||
PowerConsumption = 0,
|
||||
BuildingCount = 0
|
||||
};
|
||||
}
|
||||
|
||||
float progress = 0;
|
||||
if (activeLine.IsActive && productionLine.ProductionTime > 0)
|
||||
{
|
||||
progress = 1.0f - (activeLine.RemainingTime / productionLine.ProductionTime);
|
||||
}
|
||||
|
||||
return new ProductionLineStatus
|
||||
{
|
||||
IsActive = activeLine.IsActive,
|
||||
Progress = Mathf.Clamp(progress, 0.0f, 1.0f),
|
||||
ProductionRate = activeLine.ProductionRate,
|
||||
PowerConsumption = activeLine.TotalPowerConsumption,
|
||||
BuildingCount = activeLine.BuildingCount
|
||||
};
|
||||
}
|
||||
|
||||
public class ProductionLineStatus
|
||||
{
|
||||
public bool IsActive { get; set; }
|
||||
public float Progress { get; set; } // 0-1的进度
|
||||
public float ProductionRate { get; set; } // 每秒产出率
|
||||
public int PowerConsumption { get; set; } // 功耗
|
||||
public int BuildingCount { get; set; } // 建筑数量
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ public partial class DynamicTabManager : TabContainer
|
||||
{
|
||||
private PackedScene itemPanelScene;
|
||||
private PackedScene craftingItemScene;
|
||||
private PackedScene productionLineItemScene;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
@ -29,7 +30,22 @@ public partial class DynamicTabManager : TabContainer
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载ProductionLineItem场景(用于生产线)
|
||||
productionLineItemScene = GD.Load<PackedScene>("res://scenes/ProductionLineItem.tscn");
|
||||
if (productionLineItemScene == null)
|
||||
{
|
||||
GD.PrintErr("无法加载ProductionLineItem场景");
|
||||
return;
|
||||
}
|
||||
|
||||
GD.Print("开始初始化标签页");
|
||||
// 延迟初始化以确保所有管理器都已初始化
|
||||
CallDeferred(nameof(InitializeTabs));
|
||||
}
|
||||
|
||||
public void RefreshTabs()
|
||||
{
|
||||
GD.Print("刷新标签页");
|
||||
InitializeTabs();
|
||||
}
|
||||
|
||||
@ -113,29 +129,146 @@ public partial class DynamicTabManager : TabContainer
|
||||
vboxContainer.SizeFlagsVertical = Control.SizeFlags.ExpandFill;
|
||||
scrollContainer.AddChild(vboxContainer);
|
||||
|
||||
// 获取所有分类
|
||||
var categoryManager = ResourceCategoryManager.Instance;
|
||||
if (categoryManager == null)
|
||||
// 获取生产线管理器
|
||||
var productionLineManager = ProductionLineManager.Instance;
|
||||
if (productionLineManager == null)
|
||||
{
|
||||
GD.PrintErr("ResourceCategoryManager 实例为null");
|
||||
GD.PrintErr("ProductionLineManager 实例为null,创建空的生产线标签");
|
||||
|
||||
// 创建一个提示标签
|
||||
var noDataLabel = new Label();
|
||||
noDataLabel.Text = "生产线管理器未初始化";
|
||||
noDataLabel.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
noDataLabel.VerticalAlignment = VerticalAlignment.Center;
|
||||
vboxContainer.AddChild(noDataLabel);
|
||||
|
||||
// 添加到TabContainer
|
||||
AddChild(scrollContainer);
|
||||
SetTabTitle(GetTabCount() - 1, "生产线");
|
||||
return;
|
||||
}
|
||||
|
||||
var allCategories = categoryManager.GetAllCategories();
|
||||
// 获取所有生产线分类
|
||||
var categories = productionLineManager.GetAllCategories();
|
||||
GD.Print($"获取到 {categories.Count} 个生产线分类");
|
||||
|
||||
// 为生产线相关的分类创建块
|
||||
foreach (var category in allCategories)
|
||||
if (categories.Count == 0)
|
||||
{
|
||||
// 生产线标签包含:生产设备
|
||||
if (category.CategoryName == "生产设备")
|
||||
GD.Print("没有找到生产线分类,创建提示标签");
|
||||
|
||||
// 创建一个提示标签
|
||||
var noDataLabel = new Label();
|
||||
noDataLabel.Text = "暂无生产线配置";
|
||||
noDataLabel.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
noDataLabel.VerticalAlignment = VerticalAlignment.Center;
|
||||
vboxContainer.AddChild(noDataLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 为每个分类创建块
|
||||
foreach (var category in categories)
|
||||
{
|
||||
CreateCategoryBlock(vboxContainer, category, "生产线");
|
||||
GD.Print($"处理生产线分类: {category}");
|
||||
CreateProductionCategoryBlock(vboxContainer, category);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到TabContainer
|
||||
AddChild(scrollContainer);
|
||||
SetTabTitle(GetTabCount() - 1, "生产线");
|
||||
|
||||
GD.Print("生产线标签创建完成");
|
||||
}
|
||||
|
||||
private void CreateProductionCategoryBlock(VBoxContainer parentContainer, string category)
|
||||
{
|
||||
GD.Print($"创建生产线分类块: {category}");
|
||||
|
||||
// 创建分类块的容器
|
||||
var categoryContainer = new VBoxContainer();
|
||||
categoryContainer.Name = $"{category}Block";
|
||||
|
||||
// 添加间距
|
||||
var topSpacer = new Control();
|
||||
topSpacer.CustomMinimumSize = new Vector2(0, 10);
|
||||
categoryContainer.AddChild(topSpacer);
|
||||
|
||||
// 创建标题行(分类名称 + 横线)
|
||||
var titleContainer = new HBoxContainer();
|
||||
|
||||
// 分类名称标签
|
||||
var titleLabel = new Label();
|
||||
titleLabel.Text = category;
|
||||
titleLabel.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
titleContainer.AddChild(titleLabel);
|
||||
|
||||
// 添加小间距
|
||||
var labelSpacer = new Control();
|
||||
labelSpacer.CustomMinimumSize = new Vector2(10, 0);
|
||||
titleContainer.AddChild(labelSpacer);
|
||||
|
||||
// HSeparator 横线分隔符
|
||||
var separator = new HSeparator();
|
||||
separator.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
|
||||
separator.SizeFlagsVertical = Control.SizeFlags.ShrinkCenter;
|
||||
titleContainer.AddChild(separator);
|
||||
|
||||
categoryContainer.AddChild(titleContainer);
|
||||
|
||||
// 添加小间距
|
||||
var spacer = new Control();
|
||||
spacer.CustomMinimumSize = new Vector2(0, 5);
|
||||
categoryContainer.AddChild(spacer);
|
||||
|
||||
// 创建生产线网格 - 使用VBoxContainer实现垂直堆叠
|
||||
var productionContainer = new VBoxContainer();
|
||||
productionContainer.Name = $"{category}ProductionLines";
|
||||
productionContainer.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
|
||||
productionContainer.AddThemeConstantOverride("separation", 8); // 垂直间距
|
||||
|
||||
// 添加该分类的所有生产线
|
||||
AddProductionLinesToContainer(productionContainer, category);
|
||||
|
||||
categoryContainer.AddChild(productionContainer);
|
||||
|
||||
// 添加到父容器
|
||||
parentContainer.AddChild(categoryContainer);
|
||||
}
|
||||
|
||||
private void AddProductionLinesToContainer(VBoxContainer container, string category)
|
||||
{
|
||||
GD.Print($"为分类 '{category}' 添加生产线");
|
||||
|
||||
var productionLineManager = ProductionLineManager.Instance;
|
||||
if (productionLineManager == null)
|
||||
{
|
||||
GD.PrintErr("ProductionLineManager 实例为null");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取该分类的所有生产线
|
||||
var productionLines = productionLineManager.GetProductionLinesByCategory(category);
|
||||
|
||||
GD.Print($"获取到 {productionLines.Count} 条生产线");
|
||||
|
||||
foreach (var productionLine in productionLines)
|
||||
{
|
||||
// 创建ProductionLineItem实例
|
||||
var productionLineItem = productionLineItemScene.Instantiate<ProductionLineItem>();
|
||||
if (productionLineItem == null)
|
||||
{
|
||||
GD.PrintErr($"无法创建ProductionLineItem实例: {productionLine.Name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 设置生产线数据
|
||||
productionLineItem.SetupProductionLine(productionLine);
|
||||
|
||||
// 添加到容器
|
||||
container.AddChild(productionLineItem);
|
||||
|
||||
GD.Print($"成功添加生产线: {productionLine.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateCategoryBlock(VBoxContainer parentContainer, ResourceCategoryManager.ResourceCategory category, string tabType)
|
||||
|
||||
250
scripts/ui/ProductionLineItem.cs
Normal file
250
scripts/ui/ProductionLineItem.cs
Normal file
@ -0,0 +1,250 @@
|
||||
using Godot;
|
||||
|
||||
public partial class ProductionLineItem : Panel
|
||||
{
|
||||
private Label nameLabel;
|
||||
private Label productionLabel;
|
||||
private Label timeLabel;
|
||||
private Label powerLabel;
|
||||
private Label buildingLabel;
|
||||
private Label deviceLabel;
|
||||
private Button addButton;
|
||||
private Button removeButton;
|
||||
private ColorRect progressFill;
|
||||
private TextureRect iconTexture;
|
||||
|
||||
private ProductionLineManager.ProductionLine productionLine;
|
||||
private string productionLineId;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
// 获取UI组件引用
|
||||
nameLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/TopInfoRow/NameLabel");
|
||||
productionLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/TopInfoRow/ProductionLabel");
|
||||
timeLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/InfoRow/TimeLabel");
|
||||
powerLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/InfoRow/PowerLabel");
|
||||
buildingLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/InfoRow/BuildingLabel");
|
||||
deviceLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/RightContainer/BuildingCountRow/DeviceLabel");
|
||||
addButton = GetNode<Button>("MarginContainer/VBoxContainer/TopRow/RightContainer/ButtonsRow/AddButton");
|
||||
removeButton = GetNode<Button>("MarginContainer/VBoxContainer/TopRow/RightContainer/ButtonsRow/RemoveButton");
|
||||
progressFill = GetNode<ColorRect>("MarginContainer/VBoxContainer/ProgressContainer/ProgressFill");
|
||||
iconTexture = GetNode<TextureRect>("MarginContainer/VBoxContainer/TopRow/IconTexture");
|
||||
|
||||
// 连接按钮信号
|
||||
addButton.Pressed += OnAddButtonPressed;
|
||||
removeButton.Pressed += OnRemoveButtonPressed;
|
||||
|
||||
// 如果生产线数据已经设置,现在应用它
|
||||
if (productionLine != null)
|
||||
{
|
||||
ApplyProductionLineData();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetupProductionLine(ProductionLineManager.ProductionLine line)
|
||||
{
|
||||
productionLine = line;
|
||||
productionLineId = line.Id;
|
||||
|
||||
// 如果UI组件还没有初始化,延迟设置
|
||||
if (nameLabel == null)
|
||||
{
|
||||
GD.Print("UI组件还未初始化,延迟设置生产线数据");
|
||||
CallDeferred(nameof(ApplyProductionLineData));
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyProductionLineData();
|
||||
}
|
||||
|
||||
private void ApplyProductionLineData()
|
||||
{
|
||||
if (productionLine == null)
|
||||
{
|
||||
GD.PrintErr("productionLine为null,无法应用数据");
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保UI组件已初始化
|
||||
if (nameLabel == null)
|
||||
{
|
||||
GD.PrintErr("nameLabel仍然为null,UI初始化可能失败");
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置基本信息
|
||||
nameLabel.Text = productionLine.Name;
|
||||
timeLabel.Text = $"{productionLine.ProductionTime:F1}s";
|
||||
powerLabel.Text = $"{productionLine.PowerConsumption}W";
|
||||
|
||||
// 设置建筑需求信息
|
||||
if (productionLine.BuildingRequirements != null && productionLine.BuildingRequirements.Count > 0)
|
||||
{
|
||||
var firstRequirement = productionLine.BuildingRequirements[0];
|
||||
var buildingItem = GameData.Instance?.GetItem(firstRequirement.ItemId);
|
||||
string buildingName = buildingItem?.Name ?? firstRequirement.ItemId;
|
||||
|
||||
if (productionLine.BuildingRequirements.Count == 1)
|
||||
{
|
||||
buildingLabel.Text = $"需要: {firstRequirement.Quantity}x{buildingName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
buildingLabel.Text = $"需要: {firstRequirement.Quantity}x{buildingName}...";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buildingLabel.Text = "无建筑需求";
|
||||
}
|
||||
|
||||
// 尝试加载图标
|
||||
LoadProductionLineIcon();
|
||||
|
||||
// 初始更新显示
|
||||
UpdateDisplay();
|
||||
|
||||
GD.Print($"成功设置生产线数据: {productionLine.Name}");
|
||||
}
|
||||
|
||||
private void LoadProductionLineIcon()
|
||||
{
|
||||
if (productionLine == null) return;
|
||||
|
||||
// 尝试加载产线专用图标,如果没有则使用建筑图标
|
||||
string iconPath = $"res://assets/textures/production_lines/{productionLineId}.png";
|
||||
|
||||
if (!ResourceLoader.Exists(iconPath))
|
||||
{
|
||||
// 回退到建筑图标(使用第一个建筑需求的图标)
|
||||
if (productionLine.BuildingRequirements != null && productionLine.BuildingRequirements.Count > 0)
|
||||
{
|
||||
var firstRequirement = productionLine.BuildingRequirements[0];
|
||||
var buildingItem = GameData.Instance?.GetItem(firstRequirement.ItemId);
|
||||
if (buildingItem != null && !string.IsNullOrEmpty(buildingItem.IconPath))
|
||||
{
|
||||
iconPath = buildingItem.IconPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ResourceLoader.Exists(iconPath))
|
||||
{
|
||||
var texture = GD.Load<Texture2D>(iconPath);
|
||||
if (texture != null)
|
||||
{
|
||||
iconTexture.Texture = texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
// 只有当UI组件准备好且有生产线数据时才更新显示
|
||||
if (productionLine != null && nameLabel != null)
|
||||
{
|
||||
UpdateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDisplay()
|
||||
{
|
||||
if (productionLine == null) return;
|
||||
|
||||
// 确保UI组件已初始化
|
||||
if (deviceLabel == null || productionLabel == null || progressFill == null)
|
||||
{
|
||||
return; // UI组件还没准备好,跳过更新
|
||||
}
|
||||
|
||||
var activeLine = ProductionLineManager.Instance?.GetActiveProductionLine(productionLineId);
|
||||
var status = ProductionProcessor.Instance?.GetProductionLineStatus(productionLineId);
|
||||
|
||||
if (activeLine != null && status != null)
|
||||
{
|
||||
// 更新设备数量
|
||||
deviceLabel.Text = $"设备: {activeLine.BuildingCount}";
|
||||
|
||||
// 更新产出率
|
||||
if (activeLine.IsActive && activeLine.ProductionRate > 0)
|
||||
{
|
||||
productionLabel.Text = $"{activeLine.ProductionRate:F1}/s";
|
||||
}
|
||||
else
|
||||
{
|
||||
productionLabel.Text = "0/s";
|
||||
}
|
||||
|
||||
// 更新进度条
|
||||
progressFill.AnchorRight = status.Progress;
|
||||
|
||||
// 更新按钮状态
|
||||
UpdateButtonStates();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有激活的产线
|
||||
deviceLabel.Text = "设备: 0";
|
||||
productionLabel.Text = "0/s";
|
||||
progressFill.AnchorRight = 0;
|
||||
UpdateButtonStates();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateButtonStates()
|
||||
{
|
||||
if (productionLine == null) return;
|
||||
|
||||
// 确保按钮组件已初始化
|
||||
if (addButton == null || removeButton == null)
|
||||
{
|
||||
return; // 按钮还没准备好,跳过更新
|
||||
}
|
||||
|
||||
// 检查是否有足够的建筑材料来添加设备
|
||||
bool canAdd = CanAddBuilding();
|
||||
addButton.Disabled = !canAdd;
|
||||
|
||||
// 检查是否有设备可以移除
|
||||
var activeLine = ProductionLineManager.Instance?.GetActiveProductionLine(productionLineId);
|
||||
removeButton.Disabled = activeLine == null || activeLine.BuildingCount <= 0;
|
||||
}
|
||||
|
||||
private bool CanAddBuilding()
|
||||
{
|
||||
if (productionLine?.BuildingRequirements == null) return true;
|
||||
|
||||
var inventoryManager = InventoryManager.Instance;
|
||||
if (inventoryManager == null) return false;
|
||||
|
||||
// 检查是否有足够的建筑材料
|
||||
foreach (var requirement in productionLine.BuildingRequirements)
|
||||
{
|
||||
int available = inventoryManager.GetItemQuantity(requirement.ItemId);
|
||||
if (available < requirement.Quantity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnAddButtonPressed()
|
||||
{
|
||||
if (productionLine == null) return;
|
||||
|
||||
// 直接尝试添加建筑到产线(材料检查和扣除在ProductionLineManager中处理)
|
||||
ProductionLineManager.Instance?.AddBuilding(productionLineId, 1);
|
||||
}
|
||||
|
||||
private void OnRemoveButtonPressed()
|
||||
{
|
||||
if (productionLine == null) return;
|
||||
|
||||
// 从产线移除建筑(建筑会自动返回库存)
|
||||
ProductionLineManager.Instance?.RemoveBuilding(productionLineId, 1);
|
||||
|
||||
GD.Print($"移除了 {productionLine.Name} 产线的一个设备");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user