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;
        }
Пример #2
0
 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;
     }
 }
Пример #3
0
        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();
        }