protected override void AddProducedItemToInventory(MyBlueprintDefinitionBase definition, MyFixedPoint amountMult) { System.Diagnostics.Debug.Assert(Sync.IsServer, "This method should be called only on server!"); if (!Sync.IsServer) { return; } MyInventory interactingInventory = null; MyInventory innerInventory = (Entity as MyEntity).GetInventory(); bool resultAdded = false; if (m_lastEntityInteraction != null) { interactingInventory = (m_lastEntityInteraction as MyEntity).GetInventory(); if (interactingInventory != null) { foreach (var prodItem in definition.Results) { var amountToAdd = prodItem.Amount * amountMult; var inventoryItem = CreateInventoryItem(prodItem.Id, amountToAdd); resultAdded = interactingInventory.Add(inventoryItem, inventoryItem.Amount); if (!resultAdded) { resultAdded = innerInventory.Add(inventoryItem, inventoryItem.Amount); } System.Diagnostics.Debug.Assert(resultAdded, "Result of adding is false!"); } } } else { if (innerInventory == null) { System.Diagnostics.Debug.Fail("Inventory was not found on the entity!"); return; } foreach (var prodItem in definition.Results) { var amountToAdd = prodItem.Amount * amountMult; var inventoryItem = CreateInventoryItem(prodItem.Id, amountToAdd); resultAdded = innerInventory.Add(inventoryItem, inventoryItem.Amount); System.Diagnostics.Debug.Assert(resultAdded, "Result of adding is false!"); } } m_lastEntityInteraction = null; }
protected override void AddProducedItemToInventory(MyBlueprintDefinitionBase definition, MyFixedPoint amountMult) { if (Sync.IsServer) { MyInventory inventory = null; MyInventory inventory2 = (base.Entity as MyEntity).GetInventory(0); if (this.m_lastEntityInteraction == null) { if (inventory2 == null) { return; } foreach (MyBlueprintDefinitionBase.Item item3 in definition.Results) { MyFixedPoint amount = item3.Amount * amountMult; IMyInventoryItem item = base.CreateInventoryItem(item3.Id, amount); inventory2.Add(item, item.Amount); } } else { inventory = (this.m_lastEntityInteraction as MyEntity).GetInventory(0); if (inventory != null) { foreach (MyBlueprintDefinitionBase.Item item in definition.Results) { MyFixedPoint amount = item.Amount * amountMult; IMyInventoryItem item2 = base.CreateInventoryItem(item.Id, amount); if (!inventory.Add(item2, item2.Amount)) { inventory2.Add(item2, item2.Amount); } } } } this.m_lastEntityInteraction = null; } }
public static bool PullAny(this MyInventory inventory, HashSet <IMyTerminalBlock> sourceInventories, Dictionary <string, int> toPull) { bool result = false; foreach (KeyValuePair <string, int> entry in toPull) { int remainingAmount = entry.Value; //Logging.Instance.WriteDebug(entry.Key + entry.Value); foreach (IMyTerminalBlock block in sourceInventories) { if (block == null || block.Closed) { continue; } MyInventory sourceInventory; //get the output inventory for production blocks if (((MyEntity)block).InventoryCount > 1) { sourceInventory = ((MyEntity)block).GetInventory(1); } else { sourceInventory = ((MyEntity)block).GetInventory(); } List <MyPhysicalInventoryItem> sourceItems = sourceInventory.GetItems(); if (sourceItems.Count == 0) { continue; } var toMove = new List <KeyValuePair <MyPhysicalInventoryItem, int> >(); foreach (MyPhysicalInventoryItem item in sourceItems) { if (item.Content.SubtypeName == entry.Key) { if (item.Amount <= 0) //KEEEN { continue; } if (item.Amount >= remainingAmount) { toMove.Add(new KeyValuePair <MyPhysicalInventoryItem, int>(item, remainingAmount)); remainingAmount = 0; result = true; } else { remainingAmount -= (int)item.Amount; toMove.Add(new KeyValuePair <MyPhysicalInventoryItem, int>(item, (int)item.Amount)); result = true; } } } foreach (KeyValuePair <MyPhysicalInventoryItem, int> itemEntry in toMove) { if (inventory.ComputeAmountThatFits(itemEntry.Key.Content.GetId()) < itemEntry.Value) { return(false); } sourceInventory.Remove(itemEntry.Key, itemEntry.Value); inventory.Add(itemEntry.Key, itemEntry.Value); } if (remainingAmount == 0) { break; } } } return(result); }
public static void TryMoveToFreeCargo(MyCubeBlock source, List <IMyInventory> connectedInventory, bool ignoreOtherFactories = false) { try { List <IMyInventory> removalList = new List <IMyInventory>(); MyInventory sourceInventory = source.GetInventory(); foreach (IMyInventory inv in connectedInventory.OrderByDescending(x => (float)x.MaxVolume - (float)x.CurrentVolume)) { MyInventory targetInventory = inv as MyInventory; IMyInventory outinv = null; if (!IsValidInventoryConnection(sourceInventory, targetInventory, out outinv)) { removalList.Add(inv); continue; } if ((IMyEntity)(targetInventory.Owner) is IMyProductionBlock) { continue; // Dont push to assembler inventories } List <VRage.Game.Entity.MyPhysicalInventoryItem> items = sourceInventory.GetItems(); for (int i = 0; i < items.Count; i++) { IMyInventoryItem subItem = items[i] as IMyInventoryItem; if (subItem == null) { continue; } MyAPIGateway.Utilities.InvokeOnGameThread(() => { try { if (subItem == null || targetInventory == null || sourceInventory == null) { return; } MyFixedPoint amountFits = targetInventory.ComputeAmountThatFits(new MyDefinitionId(subItem.Content.TypeId, subItem.Content.SubtypeId)); amountFits = (amountFits > subItem.Amount) ? subItem.Amount : amountFits; if (amountFits > (MyFixedPoint)0f && sourceInventory.Remove(subItem, amountFits)) { targetInventory.Add(subItem, amountFits); } } catch (Exception e) { Logging.Instance.WriteLine($"NaniteConstructionSystem.Extensions.GridHelper.TryMoveToFreeCargo:\n{e.ToString()}"); } }); } } foreach (IMyInventory inv in removalList) { MyAPIGateway.Utilities.InvokeOnGameThread(() => { connectedInventory.Remove(inv); }); } } catch (InvalidOperationException ex) { Logging.Instance.WriteLine("NaniteConstructionSystem.Extensions.GridHelper.TryMoveToFreeCargo: A list was modified. Aborting.", 1); } catch (Exception ex) when(ex.ToString().Contains("IndexOutOfRangeException")) //because Keen thinks we shouldn't have access to this exception ... { Logging.Instance.WriteLine("NaniteConstructionSystem.Extensions.GridHelper.TryMoveToFreeCargo: A list was modified. Aborting.", 1); } }
private void StepGrind(ShipyardItem shipyardItem) { var targetsToRedraw = new HashSet <BlockTarget>(); //we need to multiply this by MyShipGrinderConstants.GRINDER_AMOUNT_PER_SECOND / 2... which evaluates to 1 float grindAmount = MyAPIGateway.Session.GrinderSpeedMultiplier * shipyardItem.Settings.GrindMultiplier; if (shipyardItem.TargetBlocks.Count == 0) { var targetblock = Profiler.Start(FullName, nameof(StepGrind), "Populate target blocks"); var blocks = new List <IMySlimBlock>(); Logging.Instance.WriteLine(shipyardItem.YardGrids.Count.ToString()); foreach (IMyCubeGrid yardGrid in shipyardItem.YardGrids.Where(g => g.Physics != null)) //don't process projections { var tmpBlocks = new List <IMySlimBlock>(); yardGrid.GetBlocks(tmpBlocks); blocks.AddRange(tmpBlocks); } foreach (IMySlimBlock tmpBlock in blocks) { shipyardItem.TargetBlocks.Add(new BlockTarget(tmpBlock, shipyardItem)); } targetblock.End(); } List <BlockTarget> allBlocks = shipyardItem.TargetBlocks.ToList(); if (allBlocks.Count == 0) { return; } if (!shipyardItem.ProxDict.Any()) { //sort blocks by distance to each tool foreach (IMyCubeBlock tool in shipyardItem.Tools) { var targetSortBlock = Profiler.Start(FullName, nameof(StepGrind), "Sort Targets"); List <BlockTarget> sortTargets = allBlocks.ToList(); sortTargets.Sort((a, b) => a.ToolDist[tool.EntityId].CompareTo(b.ToolDist[tool.EntityId])); shipyardItem.ProxDict[tool.EntityId] = sortTargets; targetSortBlock.End(); } } var targetFindBlock = Profiler.Start(FullName, nameof(StepGrind), "Find Targets"); foreach (IMyCubeBlock tool in shipyardItem.Tools) { if (tool.Closed || tool.MarkedForClose) { //this is bad shipyardItem.Disable(); return; } BlockTarget[] blockArray = shipyardItem.BlocksToProcess[tool.EntityId]; //find the next target for each grinder, if it needs one for (int i = 0; i < shipyardItem.Settings.BeamCount; i++) { var toRemove = new HashSet <BlockTarget>(); if (blockArray[i] != null) { continue; } BlockTarget nextTarget = null; for (int b = 0; b < shipyardItem.ProxDict[tool.EntityId].Count; b++) { nextTarget = shipyardItem.ProxDict[tool.EntityId][b]; if (nextTarget.CubeGrid.Closed || nextTarget.CubeGrid.MarkedForClose) { continue; } //one grinder per block, please bool found = false; foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess) { foreach (BlockTarget target in entry.Value) { if (target == null) { continue; } if (target == nextTarget) { found = true; break; } } } if (found) { toRemove.Add(nextTarget); continue; } targetsToRedraw.Add(nextTarget); break; } foreach (BlockTarget removeTarget in toRemove) { shipyardItem.ProxDict[tool.EntityId].Remove(removeTarget); shipyardItem.TargetBlocks.Remove(removeTarget); } //we found a block to pair with our grinder, add it to the dictionary and carry on with destruction if (nextTarget != null) { shipyardItem.BlocksToProcess[tool.EntityId][i] = nextTarget; } } } targetFindBlock.End(); shipyardItem.UpdatePowerUse(); var grindActionBlock = Profiler.Start(FullName, nameof(StepGrind), "Grind action"); var removeTargets = new List <BlockTarget>(); //do the grinding Utilities.InvokeBlocking(() => { foreach (IMyCubeBlock tool in shipyardItem.Tools) { for (int b = 0; b < shipyardItem.BlocksToProcess[tool.EntityId].Length; b++) { BlockTarget target = shipyardItem.BlocksToProcess[tool.EntityId][b]; if (target == null) { continue; } if (target.CubeGrid.Closed || target.CubeGrid.MarkedForClose) { Logging.Instance.WriteDebug("Error in grind action: Target closed"); removeTargets.Add(target); return; } if (targetsToRedraw.Contains(target)) { var toolLine = new Communication.ToolLineStruct { ToolId = tool.EntityId, GridId = target.CubeGrid.EntityId, BlockPos = target.GridPosition, PackedColor = Color.OrangeRed.PackedValue, Pulse = false, EmitterIndex = (byte)b }; Communication.SendLine(toolLine, shipyardItem.ShipyardBox.Center); } /* * Grinding laser "efficiency" is a float between 0-1 where: * 0.0 => 0% of components recovered * 1.0 => 100% of components recovered * * Efficiency decays exponentially as distance to the target (length of the "laser") increases * 0m => 1.0000 * 10m => 0.9995 * 25m => 0.9969 * 50m => 0.9875 * 100m => 0.9500 * 150m => 0.8875 * 250m => 0.6875 * 400m => 0.2000 * inf => 0.1000 * We impose a minimum efficiency of 0.1 (10%), which happens at distances > ~450m */ double efficiency = 1 - (target.ToolDist[tool.EntityId] / 200000); if (!shipyardItem.StaticYard) { efficiency /= 2; } if (efficiency < 0.1) { efficiency = 0.1; } //Logging.Instance.WriteDebug(String.Format("Grinder[{0}]block[{1}] distance=[{2:F2}m] efficiency=[{3:F5}]", tool.DisplayNameText, b, Math.Sqrt(target.ToolDist[tool.EntityId]), efficiency)); if (!shipyardItem.YardGrids.Contains(target.CubeGrid)) { //we missed this grid or its split at some point, so add it to the list and register the split event shipyardItem.YardGrids.Add(target.CubeGrid); ((MyCubeGrid)target.CubeGrid).OnGridSplit += shipyardItem.OnGridSplit; } MyInventory grinderInventory = ((MyEntity)tool).GetInventory(); if (!target.Block.IsFullyDismounted) { var decreaseBlock = Profiler.Start(FullName, nameof(StepGrind), "DecreaseMountLevel"); target.Block.DecreaseMountLevel(grindAmount, grinderInventory); decreaseBlock.End(); var inventoryBlock = Profiler.Start(FullName, nameof(StepGrind), "Grind Inventory"); // First move everything into _tmpInventory target.Block.MoveItemsFromConstructionStockpile(_tmpInventory); // Then move items into grinder inventory, factoring in our efficiency ratio foreach (MyPhysicalInventoryItem item in _tmpInventory.GetItems()) { //Logging.Instance.WriteDebug(String.Format("Grinder[{0}]block[{1}] Item[{2}] grind_amt[{3:F2}] collect_amt[{4:F2}]", tool.DisplayNameText, b, item.Content.SubtypeName, item.Amount, (double)item.Amount*efficiency)); grinderInventory.Add(item, (int)Math.Round((double)item.Amount * efficiency)); } // Then clear out everything left in _tmpInventory _tmpInventory.Clear(); inventoryBlock.End(); } // This isn't an <else> clause because target.Block may have become FullyDismounted above, // in which case we need to run both code blocks if (target.Block.IsFullyDismounted) { var dismountBlock = Profiler.Start(FullName, nameof(StepGrind), "FullyDismounted"); var tmpItemList = new List <MyPhysicalInventoryItem>(); var blockEntity = target.Block.FatBlock as MyEntity; if (blockEntity != null && blockEntity.HasInventory) { var dismountInventory = Profiler.Start(FullName, nameof(StepGrind), "DismountInventory"); for (int i = 0; i < blockEntity.InventoryCount; ++i) { MyInventory blockInventory = blockEntity.GetInventory(i); if (blockInventory == null) { continue; } if (blockInventory.Empty()) { continue; } tmpItemList.Clear(); tmpItemList.AddRange(blockInventory.GetItems()); foreach (MyPhysicalInventoryItem item in tmpItemList) { //Logging.Instance.WriteDebug(String.Format("Grinder[{0}]block[{1}] Item[{2}] inventory[{3:F2}] collected[{4:F2}]", tool.DisplayNameText, b, item.Content.SubtypeName, item.Amount, (double)item.Amount * efficiency)); blockInventory.Remove(item, item.Amount); grinderInventory.Add(item, (int)Math.Round((double)item.Amount * efficiency)); } } dismountInventory.End(); } target.Block.SpawnConstructionStockpile(); target.CubeGrid.RazeBlock(target.GridPosition); removeTargets.Add(target); shipyardItem.TargetBlocks.Remove(target); dismountBlock.End(); } } } }); foreach (KeyValuePair <long, List <BlockTarget> > entry in shipyardItem.ProxDict) { foreach (BlockTarget removeBlock in removeTargets) { entry.Value.Remove(removeBlock); } } foreach (BlockTarget removeBlock in removeTargets) { shipyardItem.TargetBlocks.Remove(removeBlock); } //shipyardItem.ActiveTargets = 0; //clear lines for any destroyed blocks and update our target count foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess) { for (int i = 0; i < entry.Value.Length; i++) { BlockTarget removeBlock = entry.Value[i]; if (removeTargets.Contains(removeBlock)) { Communication.ClearLine(entry.Key, i); entry.Value[i] = null; } //if (!removeTargets.Contains(removeBlock) && removeBlock != null) //{ // shipyardItem.ActiveTargets++; //} } } grindActionBlock.End(); }