🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 太空工程师编程笔记3 - 物流与生产 ### 物流与生产相关功能 物流与生产是管理基地或者大型飞船的基础,也是官方编程手册中没有说得太清楚的地方。 利用API,其实可以做到这么几件事情: 1、物体的统计调度,及管道联通性检查。 2、控制组装机组装或拆装,将组件添加到队列或从队列中删除。 3、控制精炼厂精炼。 4、控制筛选器的筛选。 #### API 存储接口,各类有存储能力的块都继承了此接口。功能可以看接口,比较明白。 ~~~csharp public interface IMyInventory { // Methods bool CanItemsBeAdded(MyFixedPoint amount, SerializableDefinitionId contentId); bool ContainItems(MyFixedPoint amount, MyObjectBuilder_PhysicalObject ob); IMyInventoryItem FindItem(SerializableDefinitionId contentId); MyFixedPoint GetItemAmount(SerializableDefinitionId contentId, MyItemFlags flags = 0); IMyInventoryItem GetItemByID(uint id); List<IMyInventoryItem> GetItems(); bool IsConnectedTo(IMyInventory dst); bool IsItemAt(int position); bool TransferItemFrom(IMyInventory sourceInventory, int sourceItemIndex, int? targetItemIndex = new int?(), bool? stackIfPossible = new bool?(), MyFixedPoint? amount = new MyFixedPoint?()); bool TransferItemTo(IMyInventory dst, int sourceItemIndex, int? targetItemIndex = new int?(), bool? stackIfPossible = new bool?(), MyFixedPoint? amount = new MyFixedPoint?()); // Properties bool IsFull { get; } Vector3 Size { get; } MyFixedPoint CurrentMass { get; } MyFixedPoint MaxVolume { get; } MyFixedPoint CurrentVolume { get; } IMyInventoryOwner Owner { get; } } ~~~ 存储Item,即每个存储项,比如一坨矿石。 ~~~csharp public interface IMyInventoryItem { // Properties MyFixedPoint Amount { get; set; } float Scale { get; set; } MyObjectBuilder_Base Content { get; set; } uint ItemId { get; set; } } ~~~ 组装机 ~~~csharp public interface IMyAssembler : IMyProductionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Properties [Obsolete("Use the Mode property")] bool DisassembleEnabled { get; } float CurrentProgress { get; } MyAssemblerMode Mode { get; set; } bool CooperativeMode { get; set; } bool Repeating { get; set; } } ~~~ 精炼厂其实没有特殊接口 ~~~csharp public interface IMyRefinery : IMyProductionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity { } ~~~ 组装机和精炼厂共同继承的IMyProductionBlock才是生产队列的关键所在 ~~~csharp public interface IMyProductionBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Methods void AddQueueItem(MyDefinitionId blueprint, decimal amount); void AddQueueItem(MyDefinitionId blueprint, double amount); void AddQueueItem(MyDefinitionId blueprint, MyFixedPoint amount); bool CanUseBlueprint(MyDefinitionId blueprint); void ClearQueue(); void GetQueue(List<MyProductionItem> items); void InsertQueueItem(int idx, MyDefinitionId blueprint, decimal amount); void InsertQueueItem(int idx, MyDefinitionId blueprint, double amount); void InsertQueueItem(int idx, MyDefinitionId blueprint, MyFixedPoint amount); void MoveQueueItemRequest(uint queueItemId, int targetIdx); void RemoveQueueItem(int idx, decimal amount); void RemoveQueueItem(int idx, double amount); void RemoveQueueItem(int idx, MyFixedPoint amount); // Properties IMyInventory InputInventory { get; } IMyInventory OutputInventory { get; } bool IsProducing { get; } bool IsQueueEmpty { get; } uint NextItemId { get; } bool UseConveyorSystem { get; set; } } ~~~ 筛选器 ~~~csharp public interface IMyConveyorSorter : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Methods void AddItem(MyInventoryItemFilter item); void GetFilterList(List<MyInventoryItemFilter> items); bool IsAllowed(MyDefinitionId id); void RemoveItem(MyInventoryItemFilter item); void SetFilter(MyConveyorSorterMode mode, List<MyInventoryItemFilter> items); // Properties bool DrainAll { get; set; } MyConveyorSorterMode Mode { get; } } ~~~ 以及他们用到的MyDefinitionId ~~~csharp public struct MyDefinitionId : IEquatable<MyDefinitionId> { public static readonly DefinitionIdComparerType Comparer; public readonly MyObjectBuilderType TypeId; public readonly MyStringHash SubtypeId; public static MyDefinitionId FromContent(MyObjectBuilder_Base content); public static MyDefinitionId Parse(string id); public static bool TryParse(string id, out MyDefinitionId definitionId); public static bool TryParse(string type, string subtype, out MyDefinitionId definitionId); public string SubtypeName { get; } public MyDefinitionId(MyObjectBuilderType type); public MyDefinitionId(MyObjectBuilderType type, string subtypeName); public MyDefinitionId(MyObjectBuilderType type, MyStringHash subtypeId); public MyDefinitionId(MyRuntimeObjectBuilderId type, MyStringHash subtypeId); public override int GetHashCode(); public long GetHashCodeLong(); public override bool Equals(object obj); public override string ToString(); public bool Equals(MyDefinitionId other); public static bool operator ==(MyDefinitionId l, MyDefinitionId r); public static bool operator !=(MyDefinitionId l, MyDefinitionId r); public static implicit operator MyDefinitionId(SerializableDefinitionId v); public static implicit operator SerializableDefinitionId(MyDefinitionId v); static MyDefinitionId(); // Nested Types public class DefinitionIdComparerType : IEqualityComparer<MyDefinitionId> { // Methods public DefinitionIdComparerType(); public bool Equals(MyDefinitionId x, MyDefinitionId y); public int GetHashCode(MyDefinitionId obj); } } ~~~ ### 编程 #### 物品统计 统计当前网格所有的物品,并输出汇总数量 ~~~csharp Dictionary<string,int> list=new Dictionary<string,int>(); public void Main(string argument, UpdateType updateSource) { //先获取所有块 List<IMyTerminalBlock> blocks=new List<IMyTerminalBlock>(); GridTerminalSystem.GetBlocksOfType<IMyTerminalBlock>(blocks,block=>block.HasInventory); Echo("共有存储个数:"+blocks.Count); //统计物品数量 foreach (IMyTerminalBlock block in blocks) { foreach (IMyInventoryItem item in block.GetInventory().GetItems()) { //Echo(item.Amount.ToString()); //Echo(item.Scale.ToString()); //Echo(item.Content.TypeId.ToString()); //Echo(item.ItemId.ToString()); string itemName=item.Content.TypeId.ToString()+"-"+item.Content.SubtypeId.ToString(); int itemCount=(int)item.Amount; if(list.ContainsKey(itemName)){ list[itemName]+=itemCount; }else{ list.Add(itemName,itemCount); } } } //在终端输出 Echo("共有以下物体:"); foreach (var item in list) { Echo(item.Key+":"+item.Value); } } ~~~ #### 物品归集 将所有可以转移到第一个存储的物体,转移到第一个存储。 这里要注意的是,组装机和精炼厂存储并非通过GetInventory获得,应通过IMyProductionBlock的InputInventory和OutputInventory操作。 ~~~csharp public void Main(string argument, UpdateType updateSource) { //先获取所有块 List<IMyTerminalBlock> blocks=new List<IMyTerminalBlock>(); GridTerminalSystem.GetBlocksOfType<IMyTerminalBlock>(blocks,block=>block.HasInventory); Echo("共有存储个数:"+blocks.Count); if(blocks.Count<1)return; //取第一个 IMyTerminalBlock first=blocks[0]; Echo("第一块是:"+first.CustomName); //进行转运 foreach (IMyTerminalBlock block in blocks) { if(block!=first&&block.GetInventory()!=null) foreach (IMyInventoryItem item in block.GetInventory().GetItems()) { if(block.GetInventory().IsConnectedTo(first.GetInventory())){ Echo("正在从"+block.CustomName+"运输"+item.ToString()); if(block.GetInventory().IsItemAt(0))block.GetInventory().TransferItemTo(first.GetInventory(),0); } } } } ~~~ #### 控制组装机生产队列 打印组装机任务队列,并向任务队列里添加任务。 ~~~csharp public void Main(string argument, UpdateType updateSource) { //先获取一个组装机 List<IMyAssembler> assemblers=new List<IMyAssembler>(); GridTerminalSystem.GetBlocksOfType<IMyAssembler>(assemblers); if(assemblers.Count<1)return; IMyAssembler assembler=assemblers[0]; Echo("目标组装机:"+assembler.CustomName); Echo("工作状态:"+assembler.Mode); Echo("当前任务队列:"); List<MyProductionItem> items=new List<MyProductionItem>(); assembler.GetQueue(items); foreach (var item in items) { Echo(item.BlueprintId+":"+item.Amount); } //设定组装机工作状态,不管其之前如何 assembler.Mode=MyAssemblerMode.Assembly; //assembler.Mode=MyAssemblerMode.Disassembly; //创建一个物品蓝图 MyDefinitionId blueprint=MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/BulletproofGlass"); //确认并添加到组装机队列 if(assembler.CanUseBlueprint(blueprint))assembler.AddQueueItem(blueprint,5.0); } ~~~