private bool BuildTarget(BlockTarget target, ShipyardItem item, IMyCubeBlock tool)
        {
            IMyProjector projector = target.Projector;
            IMySlimBlock block     = target.Block;

            if (projector == null || block == null)
            {
                return(false);
            }

            if (projector.CanBuild(block, false) != BuildCheckResult.OK)
            {
                return(false);
            }

            if (MyAPIGateway.Session.CreativeMode)
            {
                projector.Build(block, 0, tool.EntityId, false);
                return(projector.CanBuild(block, true) != BuildCheckResult.OK);
            }

            //try to remove the first component from inventory
            string name = ((MyCubeBlockDefinition)block.BlockDefinition).Components[0].Definition.Id.SubtypeName;

            if (_tmpInventory.PullAny(item.ConnectedCargo, name, 2))
            {
                _tmpInventory.Clear();
                projector.Build(block, 0, tool.EntityId, false);
                return(projector.CanBuild(block, true) != BuildCheckResult.OK);
            }

            return(false);
        }
示例#2
0
        public static void SendNewYard(ShipyardItem item, ulong steamId = 0)
        {
            Logging.Instance.WriteLine("Sent Yard");
            var newYard = new YardStruct
            {
                GridId   = item.EntityId,
                ToolIds  = item.Tools.Select(x => x.EntityId).ToArray(),
                YardType = item.YardType
            };

            if (item.Menu?.Buttons != null)
            {
                Logging.Instance.WriteLine("Button ID: " + item.Menu.Buttons.EntityId);
                newYard.ButtonId = item.Menu.Buttons.EntityId;
            }

            string message = MyAPIGateway.Utilities.SerializeToXML(newYard);

            byte[] data = Encoding.UTF8.GetBytes(message);

            if (steamId == 0)
            {
                SendMessageToClients(MessageTypeEnum.NewYard, data);
            }
            else
            {
                SendMessageTo(MessageTypeEnum.NewYard, data, steamId);
            }
        }
示例#3
0
        public static void SendYardState(ShipyardItem item)
        {
            var data = new byte[sizeof(long) + 1];

            BitConverter.GetBytes(item.EntityId).CopyTo(data, 0);
            data[sizeof(long)] = (byte)item.YardType;

            SendMessageToClients(MessageTypeEnum.YardState, data);
        }
示例#4
0
        //    OBB corner structure
        //     ZMax    ZMin
        //    0----1  4----5
        //    |    |  |    |
        //    |    |  |    |
        //    3----2  7----6

        /// <summary>
        ///     Makes sure the shipyard has a complete frame made of shipyard conveyor blocks
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private bool IsFrameComplete(ShipyardItem item)
        {
            using (Profiler.Start(FullName, nameof(IsFrameComplete)))
            {
                var corners = new Vector3D[8];
                item.ShipyardBox.GetCorners(corners, 0);

                var gridCorners = new Vector3I[8];
                for (int i = 0; i < 8; i++)
                {
                    gridCorners[i] = ((IMyCubeGrid)item.YardEntity).WorldToGridInteger(corners[i]);
                }

                LinePair[] lines =
                {
                    new LinePair(0, 1),
                    new LinePair(0, 4),
                    new LinePair(1, 2),
                    new LinePair(1, 5),
                    new LinePair(2, 3),
                    new LinePair(2, 6),
                    new LinePair(3, 0),
                    new LinePair(3, 7),
                    new LinePair(4, 5),
                    new LinePair(5, 6),
                    new LinePair(6, 7),
                    new LinePair(7, 4),
                };

                var grid = (IMyCubeGrid)item.YardEntity;
                foreach (LinePair line in lines)
                {
                    var it = new MathUtility.Vector3ILineIterator(gridCorners[line.Start], gridCorners[line.End]);
                    while (it.IsValid())
                    {
                        IMySlimBlock block = grid.GetCubeBlock(it.Current);
                        it.MoveNext();
                        if (block == null)
                        {
                            return(false);
                        }

                        if (!block.BlockDefinition.Id.SubtypeName.Contains("Shipyard"))
                        {
                            return(false);
                        }

                        if (block.BuildPercent() < .8)
                        {
                            return(false);
                        }
                    }
                }

                return(true);
            }
        }
示例#5
0
        private string FormatMainMenu(ShipyardItem item)
        {
            var result = new StringBuilder();

            result.Append("Automated Shipyard Main Menu\r\n\r\n");
            result.Append("Current targets: " + item.ContainsGrids.Count);
            result.Append("\r\n\r\n");

            result.Append(". Exit : Up :. Down :: Select");
            result.Append("\r\n\r\n");

            return(result.ToString());
        }
        //    OBB corner structure
        //     ZMax    ZMin
        //    0----1  4----5
        //    |    |  |    |
        //    |    |  |    |
        //    3----2  7----6
        /// <summary>
        ///     Updates the internal list of lines so we only draw a laser if there is a frame to contain it
        /// </summary>
        /// <param name="item"></param>
        private void UpdateBoxLines(ShipyardItem item)
        {
            var lineBlock = Profiler.Start(FullName, nameof(UpdateBoxLines));
            var corners   = new Vector3D[8];

            item.ShipyardBox.GetCorners(corners, 0);
            var grid = (IMyCubeGrid)item.YardEntity;

            var gridCorners = new Vector3I[8];

            for (int i = 0; i < 8; i++)
            {
                gridCorners[i] = grid.WorldToGridInteger(corners[i]);
            }

            item.BoxLines.Clear();

            //okay, really long unrolled loop coming up, but it's the simplest way to do it
            //zMax face
            if (WalkLine(gridCorners[0], gridCorners[1], grid))
            {
                item.BoxLines.Add(new LineItem(corners[0], corners[1]));
            }
            if (WalkLine(gridCorners[1], gridCorners[2], grid))
            {
                item.BoxLines.Add(new LineItem(corners[1], corners[2]));
            }
            if (WalkLine(gridCorners[2], gridCorners[3], grid))
            {
                item.BoxLines.Add(new LineItem(corners[2], corners[3]));
            }
            if (WalkLine(gridCorners[3], gridCorners[0], grid))
            {
                item.BoxLines.Add(new LineItem(corners[3], corners[0]));
            }
            //zMin face
            if (WalkLine(gridCorners[4], gridCorners[5], grid))
            {
                item.BoxLines.Add(new LineItem(corners[4], corners[5]));
            }
            if (WalkLine(gridCorners[5], gridCorners[6], grid))
            {
                item.BoxLines.Add(new LineItem(corners[5], corners[6]));
            }
            if (WalkLine(gridCorners[6], gridCorners[7], grid))
            {
                item.BoxLines.Add(new LineItem(corners[6], corners[7]));
            }
            if (WalkLine(gridCorners[7], gridCorners[4], grid))
            {
                item.BoxLines.Add(new LineItem(corners[7], corners[4]));
            }
            //connecting lines
            if (WalkLine(gridCorners[0], gridCorners[4], grid))
            {
                item.BoxLines.Add(new LineItem(corners[0], corners[4]));
            }
            if (WalkLine(gridCorners[1], gridCorners[5], grid))
            {
                item.BoxLines.Add(new LineItem(corners[1], corners[5]));
            }
            if (WalkLine(gridCorners[2], gridCorners[6], grid))
            {
                item.BoxLines.Add(new LineItem(corners[2], corners[6]));
            }
            if (WalkLine(gridCorners[3], gridCorners[7], grid))
            {
                item.BoxLines.Add(new LineItem(corners[3], corners[7]));
            }

            lineBlock.End();
        }
示例#7
0
        private static void HandleNewShipyard(byte[] data)
        {
            Logging.Instance.WriteLine("ReceivedYard");
            string message    = Encoding.UTF8.GetString(data);
            var    yardStruct = MyAPIGateway.Utilities.SerializeFromXML <YardStruct>(message);

            //the server has already verified this shipyard. Don't question it, just make the shipyard item
            if (yardStruct.ToolIds.Length != 8)
            {
                return;
            }

            IMyEntity outEntity;

            if (!MyAPIGateway.Entities.TryGetEntityById(yardStruct.GridId, out outEntity))
            {
                return;
            }

            var yardGrid = outEntity as IMyCubeGrid;

            if (yardGrid == null)
            {
                return;
            }

            var points = new List <Vector3D>(8);
            var tools  = new List <IMyCubeBlock>(8);

            foreach (long toolId in yardStruct.ToolIds)
            {
                IMyEntity entity;
                if (!MyAPIGateway.Entities.TryGetEntityById(toolId, out entity))
                {
                    return;
                }

                var block = entity as IMyCubeBlock;
                if (block == null)
                {
                    return;
                }

                tools.Add(block);
                points.Add(block.GetPosition());
            }

            MyOrientedBoundingBoxD yardBox = MathUtility.CreateOrientedBoundingBox(yardGrid, points, 2.5);

            var yardItem = new ShipyardItem(yardBox, tools.ToArray(), yardStruct.YardType, yardGrid);

            if (MyAPIGateway.Entities.TryGetEntityById(yardStruct.ButtonId, out outEntity))
            {
                Logging.Instance.WriteLine("Bind Buttons");
                var buttons = (IMyButtonPanel)outEntity;
                buttons.ButtonPressed += yardItem.HandleButtonPressed;
                var blockDef = (MyButtonPanelDefinition)MyDefinitionManager.Static.GetCubeBlockDefinition(buttons.BlockDefinition);
                for (int i = 1; i <= 4; i++)
                {
                    var c = blockDef.ButtonColors[i % blockDef.ButtonColors.Length];
                    buttons.SetEmissiveParts($"Emissive{i}", new Color(c.X, c.Y, c.Z), c.W);
                }
                buttons.SetCustomButtonName(0, "Exit");
                buttons.SetCustomButtonName(1, "Up");
                buttons.SetCustomButtonName(2, "Down");
                buttons.SetCustomButtonName(3, "Select");
                //buttons.SetEmissiveParts("Emissive1", blockDef.ButtonColors[1 % blockDef.ButtonColors.Length], 1);
                //buttons.SetEmissiveParts("Emissive2", blockDef.ButtonColors[2 % blockDef.ButtonColors.Length], 1);
                //buttons.SetEmissiveParts("Emissive3", blockDef.ButtonColors[3 % blockDef.ButtonColors.Length], 1);
                //buttons.SetEmissiveParts("Emissive4", blockDef.ButtonColors[4 % blockDef.ButtonColors.Length], 1);
            }
            yardItem.Settings = ShipyardSettings.Instance.GetYardSettings(yardItem.EntityId);
            ProcessLocalYards.LocalYards.Add(yardItem);
            var corners = new Vector3D[8];

            yardItem.ShipyardBox.GetCorners(corners, 0);
            //check ShipyardItem.UpdatePowerUse for details on this value
            float maxpower = 5 + (float)Vector3D.DistanceSquared(corners[0], corners[6]) / 8;

            maxpower += 90;

            foreach (IMyCubeBlock tool in yardItem.Tools)
            {
                var corner = ((IMyCollector)tool).GameLogic.GetAs <ShipyardCorner>();
                corner.SetMaxPower(maxpower);
                corner.Shipyard = yardItem;
                //tool.SetEmissiveParts("Emissive1", Color.Yellow, 0f);
            }
            yardItem.Settings = ShipyardSettings.Instance.GetYardSettings(yardItem.EntityId);
            ProcessLocalYards.LocalYards.Add(yardItem);
        }
        private bool StepWeld(ShipyardItem shipyardItem)
        {
            var targetsToRemove = new HashSet <BlockTarget>();
            var targetsToRedraw = new HashSet <BlockTarget>();

            //we need to multiply this by MyShipWelder.WELDER_AMOUNT_PER_SECOND / 2, which also evaluates to 1
            float weldAmount = MyAPIGateway.Session.WelderSpeedMultiplier * shipyardItem.Settings.WeldMultiplier;
            float boneAmount = weldAmount * .1f;

            if (shipyardItem.TargetBlocks.Count == 0)
            {
                var sortBlock = Profiler.Start(FullName, nameof(StepWeld), "Sort Targets");
                shipyardItem.TargetBlocks.Clear();
                shipyardItem.ProxDict.Clear();
                //precalculate all the BlockTarget for our target grids to speed things up
                var gridTargets = new Dictionary <long, List <BlockTarget> >();
                foreach (IMyCubeGrid targetGrid in shipyardItem.YardGrids)
                {
                    if (targetGrid.Closed || targetGrid.MarkedForClose)
                    {
                        continue;
                    }

                    var tmpBlocks = new List <IMySlimBlock>();
                    targetGrid.GetBlocks(tmpBlocks);

                    gridTargets.Add(targetGrid.EntityId, new List <BlockTarget>(tmpBlocks.Count));
                    foreach (IMySlimBlock block in tmpBlocks.ToArray())
                    {
                        if (block == null || (block.CubeGrid.Physics != null && block.IsFullIntegrity && !block.HasDeformation))
                        {
                            continue;
                        }

                        var target = new BlockTarget(block, shipyardItem);

                        shipyardItem.TargetBlocks.Add(target);

                        gridTargets[targetGrid.EntityId].Add(target);
                    }

                    //Shouldn't be needed as this is handled by the projector logic in BlockTarget

                    //var proj = targetGrid.Projector();
                    //if (proj != null && !shipyardItem.YardGrids.Contains(proj.CubeGrid))
                    //{
                    //    proj.CubeGrid.GetBlocks(tmpBlocks);
                    //    gridTargets.Add(proj.CubeGrid.EntityId, new List<BlockTarget>());
                    //    foreach (var block in tmpBlocks.ToArray())
                    //    {
                    //        if (block == null || (targetGrid.Physics != null && block.IsFullIntegrity && !block.HasDeformation))
                    //            continue;

                    //        var pos = block.GetPosition();
                    //        if (!shipyardItem.ShipyardBox.Contains(ref pos))
                    //            continue;

                    //        var target = new BlockTarget(block, shipyardItem);

                    //        shipyardItem.TargetBlocks.Add(target);
                    //        gridTargets[block.CubeGrid.EntityId].Add(target);
                    //    }
                    //}
                }
                int count = 0;
                foreach (KeyValuePair <long, List <BlockTarget> > entry in gridTargets)
                {
                    count += entry.Value.Count;
                }

                foreach (IMyCubeBlock tool in shipyardItem.Tools)
                {
                    shipyardItem.ProxDict.Add(tool.EntityId, new List <BlockTarget>());
                    //first sort grids by distance to tool
                    shipyardItem.YardGrids.Sort((a, b) =>
                                                Vector3D.DistanceSquared(a.Center(), tool.GetPosition()).CompareTo(
                                                    Vector3D.DistanceSquared(b.Center(), tool.GetPosition())));

                    foreach (IMyCubeGrid grid in shipyardItem.YardGrids)
                    {
                        //then sort blocks by distance to grid center
                        List <BlockTarget> list = gridTargets[grid.EntityId];
                        switch (shipyardItem.Settings.BuildPattern)
                        {
                        case BuildPatternEnum.FromProjector:
                            list.Sort((a, b) => a.ProjectorDist.CompareTo(b.ProjectorDist));
                            break;

                        case BuildPatternEnum.FromCenter:
                            list.Sort((a, b) => a.CenterDist.CompareTo(b.CenterDist));
                            break;

                        case BuildPatternEnum.FromCorners:
                            list.Sort((a, b) => a.ToolDist[tool.EntityId].CompareTo(b.ToolDist[tool.EntityId]));
                            break;

                        default:
                            throw new Exception("Invalid BuildPatternEnum");
                        }
                        shipyardItem.ProxDict[tool.EntityId].AddRange(list);
                    }
                }
                sortBlock.End();
            }

            //nothing to do
            if (shipyardItem.TargetBlocks.Count == 0)
            {
                Logging.Instance.WriteDebug("TargetBlocks 0");
                return(false);
            }

            //assign blocks to our welders
            foreach (IMyCubeBlock welder in shipyardItem.Tools)
            {
                for (int i = 0; i < shipyardItem.Settings.BeamCount; i++)
                {
                    if (shipyardItem.BlocksToProcess[welder.EntityId][i] != null)
                    {
                        continue;
                    }

                    var         toRemove   = new List <BlockTarget>();
                    BlockTarget nextTarget = null;

                    foreach (BlockTarget target in shipyardItem.ProxDict[welder.EntityId])
                    {
                        bool found = false;
                        //each block can only have one laser assigned
                        foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess)
                        {
                            if (entry.Value.Contains(target))
                            {
                                found = true;
                                break;
                            }
                        }
                        if (found)
                        {
                            toRemove.Add(target);
                            continue;
                        }

                        if (target.Projector != null)
                        {
                            BuildCheckResult res = target.Projector.CanBuild(target.Block, false);
                            if (res == BuildCheckResult.AlreadyBuilt)
                            {
                                target.UpdateAfterBuild();
                            }
                            else if (res != BuildCheckResult.OK)
                            {
                                continue;
                            }
                            else
                            {
                                bool success = false;
                                Utilities.InvokeBlocking(() => success = BuildTarget(target, shipyardItem, welder));
                                Logging.Instance.WriteDebug(success.ToString());
                                if (!success)
                                {
                                    //toRemove.Add(target);
                                    continue;
                                }
                                target.UpdateAfterBuild();
                            }
                        }
                        if (target.CubeGrid.Physics != null && target.Block.IsFullIntegrity && !target.Block.HasDeformation)
                        {
                            toRemove.Add(target);
                            continue;
                        }
                        nextTarget = target;
                        break;
                    }

                    if (nextTarget != null)
                    {
                        targetsToRedraw.Add(nextTarget);
                        shipyardItem.BlocksToProcess[welder.EntityId][i] = nextTarget;
                    }

                    foreach (BlockTarget removeTarget in toRemove)
                    {
                        shipyardItem.ProxDict[welder.EntityId].Remove(removeTarget);
                        shipyardItem.TargetBlocks.Remove(removeTarget);
                    }
                }
            }

            //update lasers
            foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess)
            {
                for (int i = 0; i < entry.Value.Length; i++)
                {
                    BlockTarget targetBlock = entry.Value[i];

                    if (targetBlock == null || _stalledTargets.Contains(targetBlock))
                    {
                        continue;
                    }

                    if (targetsToRedraw.Contains(targetBlock))
                    {
                        var toolLine = new Communication.ToolLineStruct
                        {
                            ToolId       = entry.Key,
                            GridId       = targetBlock.CubeGrid.EntityId,
                            BlockPos     = targetBlock.GridPosition,
                            PackedColor  = Color.DarkCyan.PackedValue,
                            Pulse        = false,
                            EmitterIndex = (byte)i
                        };

                        Communication.SendLine(toolLine, shipyardItem.ShipyardBox.Center);
                    }
                }
            }

            if (shipyardItem.BlocksToProcess.All(e => e.Value.All(t => t == null)))
            {
                Logging.Instance.WriteDebug("Null thing?");
                return(false);
            }

            shipyardItem.UpdatePowerUse();
            targetsToRedraw.Clear();

            Utilities.InvokeBlocking(() =>
            {
                foreach (IMyCubeBlock welder in shipyardItem.Tools)
                {
                    var tool = (IMyCollector)welder;
                    MyInventory welderInventory = ((MyEntity)tool).GetInventory();
                    int i = 0;
                    foreach (BlockTarget target in shipyardItem.BlocksToProcess[tool.EntityId])
                    {
                        if (target == null)
                        {
                            continue;
                        }

                        if (target.CubeGrid.Physics == null || target.CubeGrid.Closed || target.CubeGrid.MarkedForClose)
                        {
                            targetsToRemove.Add(target);
                            continue;
                        }

                        if (!MyAPIGateway.Session.CreativeMode)
                        {
                            /*
                             * Welding laser "efficiency" is a float between 0-1 where:
                             *   0.0 =>   0% of component stock used for construction (100% loss)
                             *   1.0 => 100% of component stock used for construction (0% loss)
                             *
                             * Efficiency decay/distance formula is the same as above for grinder
                             */
                            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("Welder[{0}]block[{1}] distance=[{2:F2}m] efficiency=[{3:F5}]", tool.DisplayNameText, i, Math.Sqrt(target.ToolDist[tool.EntityId]), efficiency));

                            /*
                             * We have to factor in our efficiency ratio before transferring to the block "construction stockpile",
                             * but that math isn't nearly as easy as it was with the grinder.
                             *
                             * For each missing component type, we know how many items are "missing" from the construction model, M
                             *
                             * The simplest approach would be to pull M items from the conveyor system (if enabled), then move
                             * (M*efficiency) items to the "construction stockpile" and vaporize the other (M*(1-efficiency)) items.
                             * However, this approach would leave the construction stockpile incomplete and require several iterations
                             * before M items have actually been copied.
                             *
                             * A better solution is to pull enough "extra" items from the conveyors that the welder has enough to
                             * move M items to the construction stockpile even after losses due to distance inefficiency
                             *
                             * For example, if the target block is missing M=9 items and we are running at 0.9 (90%) efficiency,
                             * ideally that means we should pull 10 units, vaporize 1, and still have 9 for construction. However,
                             * if the conveyor system was only able to supply us with 2 components, we should not continue to blindly
                             * vaporize 1 unit.
                             *
                             * Instead, we have to consult the post-conveyor-pull welder inventory to determine if it has at least
                             * the required number of components.  If it does, we vaporize M*(1-efficiency).  Otherwise we only
                             * vaporize current_count*(1-efficiency) and transfer the rest to the construction stockpile
                             */
                            var missingComponents = new Dictionary <string, int>();
                            target.Block.GetMissingComponents(missingComponents);

                            var wasteComponents = new Dictionary <string, int>();
                            foreach (KeyValuePair <string, int> entry in missingComponents)
                            {
                                var componentId            = new MyDefinitionId(typeof(MyObjectBuilder_Component), entry.Key);
                                int missing                = entry.Value;
                                MyFixedPoint totalRequired = (MyFixedPoint)(missing / efficiency);

                                MyFixedPoint currentStock = welderInventory.GetItemAmount(componentId);

                                //Logging.Instance.WriteDebug(String.Format("Welder[{0}]block[{1}] Component[{2}] missing[{3:F3}] inefficiency requires[{4:F3}] in_stock[{5:F3}]", tool.DisplayNameText, i, entry.Key, missing, totalRequired, currentStock));
                                if (currentStock < totalRequired && tool.UseConveyorSystem)
                                {
                                    // Welder doesn't have totalRequired, so try to pull the difference from conveyors
                                    welderInventory.PullAny(shipyardItem.ConnectedCargo, entry.Key, (int)Math.Ceiling((double)(totalRequired - currentStock)));
                                    currentStock = welderInventory.GetItemAmount(componentId);
                                    //Logging.Instance.WriteDebug(String.Format("Welder[{0}]block[{1}] Component[{2}] - after conveyor pull - in_stock[{3:F3}]", tool.DisplayNameText, i, entry.Key, currentStock));
                                }

                                // Now compute the number of components to delete
                                // MoveItemsToConstructionPile() below won't move anything if we have less than 1 unit,
                                // so don't bother "losing" anything due to ineffeciency
                                if (currentStock >= 1)
                                {
                                    // The lesser of (missing, currentStock), times (1 minus) our efficiency fraction
                                    MyFixedPoint toDelete = MyFixedPoint.Min(MyFixedPoint.Floor(currentStock), missing) * (MyFixedPoint)(1 - efficiency);
                                    //Logging.Instance.WriteDebug(String.Format("Welder[{0}]block[{1}] Component[{2}] amount lost due to distance [{3:F3}]", tool.DisplayNameText, i, entry.Key, toDelete));
                                    welderInventory.RemoveItemsOfType((int)toDelete, componentId);
                                }
                            }

                            target.Block.MoveItemsToConstructionStockpile(welderInventory);

                            missingComponents.Clear();
                            target.Block.GetMissingComponents(missingComponents);

                            if (missingComponents.Any() && !target.Block.HasDeformation)
                            {
                                if (_stalledTargets.Add(target))
                                {
                                    targetsToRedraw.Add(target);
                                }
                            }
                            else
                            {
                                if (_stalledTargets.Remove(target))
                                {
                                    targetsToRedraw.Add(target);
                                }
                            }

                            target.Block.IncreaseMountLevel(weldAmount, 0, welderInventory, boneAmount, true);
                            if (target.Block.IsFullIntegrity && !target.Block.HasDeformation)
                            {
                                targetsToRemove.Add(target);
                            }
                        }
                        i++;
                    }
                }
            });

            shipyardItem.MissingComponentsDict.Clear();

            foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess)
            {
                for (int i = 0; i < entry.Value.Length; i++)
                {
                    BlockTarget target = entry.Value[i];

                    if (target == null)
                    {
                        continue;
                    }

                    if (targetsToRemove.Contains(target))
                    {
                        Communication.ClearLine(entry.Key, i);
                        _stalledTargets.Remove(target);
                        shipyardItem.TargetBlocks.Remove(target);
                        entry.Value[i] = null;
                        continue;
                    }

                    if (_stalledTargets.Contains(target))
                    {
                        var blockComponents = new Dictionary <string, int>();
                        target.Block.GetMissingComponents(blockComponents);

                        foreach (KeyValuePair <string, int> component in blockComponents)
                        {
                            if (shipyardItem.MissingComponentsDict.ContainsKey(component.Key))
                            {
                                shipyardItem.MissingComponentsDict[component.Key] += component.Value;
                            }
                            else
                            {
                                shipyardItem.MissingComponentsDict.Add(component.Key, component.Value);
                            }
                        }

                        var toolLine = new Communication.ToolLineStruct
                        {
                            ToolId       = entry.Key,
                            GridId       = target.CubeGrid.EntityId,
                            BlockPos     = target.GridPosition,
                            PackedColor  = Color.Purple.PackedValue,
                            Pulse        = true,
                            EmitterIndex = (byte)i
                        };

                        if (targetsToRedraw.Contains(target))
                        {
                            Communication.ClearLine(entry.Key, i);
                            Communication.SendLine(toolLine, shipyardItem.ShipyardBox.Center);
                        }
                        continue;
                    }
                }
            }

            return(true);
        }
        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();
        }
示例#10
0
        public override void UpdateOnceBeforeFrame()
        {
            if (_init)
            {
                return;
            }

            _init  = true;
            _block = Entity as IMyCollector;

            if (_block == null)
            {
                return;
            }

            //create terminal controls
            IMyTerminalControlSeparator sep = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlSeparator, IMyCollector>(string.Empty);

            sep.Visible = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(sep);

            IMyTerminalControlOnOffSwitch guideSwitch = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlOnOffSwitch, IMyCollector>("Shipyard_GuideSwitch");

            guideSwitch.Title   = MyStringId.GetOrCompute("Guide Boxes");
            guideSwitch.Tooltip = MyStringId.GetOrCompute("Toggles the guide boxes drawn around grids in the shipyard.");
            guideSwitch.OnText  = MyStringId.GetOrCompute("On");
            guideSwitch.OffText = MyStringId.GetOrCompute("Off");
            guideSwitch.Visible = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            guideSwitch.Enabled = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner") && GetYard(b) != null;
            guideSwitch.SupportsMultipleBlocks = true;
            guideSwitch.Getter = GetGuideEnabled;
            guideSwitch.Setter = SetGuideEnabled;
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(guideSwitch);
            Controls.Add(guideSwitch);

            var lockSwitch = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlOnOffSwitch, IMyCollector>("Shipyard_LockSwitch");

            lockSwitch.Title   = MyStringId.GetOrCompute("Advanced Locking");
            lockSwitch.Tooltip = MyStringId.GetOrCompute("Toggles locking grids in the shipyard when grinding or welding while moving.");
            lockSwitch.OnText  = MyStringId.GetOrCompute("On");
            lockSwitch.OffText = MyStringId.GetOrCompute("Off");
            lockSwitch.Visible = b => b.BlockDefinition.SubtypeId.Equals("ShipyardCorner_Small");
            lockSwitch.Enabled = b => b.BlockDefinition.SubtypeId.Equals("ShipyardCorner_Small") && GetYard(b) != null;
            lockSwitch.SupportsMultipleBlocks = true;
            lockSwitch.Getter = GetLockEnabled;
            lockSwitch.Setter = SetLockEnabled;
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(lockSwitch);
            Controls.Add(lockSwitch);

            IMyTerminalControlButton grindButton = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlButton, IMyCollector>("Shipyard_GrindButton");
            IMyTerminalControlButton weldButton  = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlButton, IMyCollector>("Shipyard_WeldButton");
            IMyTerminalControlButton stopButton  = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlButton, IMyCollector>("Shipyard_StopButton");

            grindButton.Title   = MyStringId.GetOrCompute("Grind");
            grindButton.Tooltip = MyStringId.GetOrCompute("Begins grinding ships in the yard.");
            grindButton.Enabled = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner") && GetYard(b)?.YardType == ShipyardType.Disabled;
            grindButton.Visible = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            grindButton.SupportsMultipleBlocks = true;
            grindButton.Action = b => Communication.SendYardCommand(b.CubeGrid.EntityId, ShipyardType.Grind);
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(grindButton);
            Controls.Add(grindButton);

            weldButton.Title   = MyStringId.GetOrCompute("Weld");
            weldButton.Tooltip = MyStringId.GetOrCompute("Begins welding ships in the yard.");
            weldButton.Enabled = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner") && GetYard(b)?.YardType == ShipyardType.Disabled;
            weldButton.Visible = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            weldButton.SupportsMultipleBlocks = true;
            weldButton.Action = b => Communication.SendYardCommand(b.CubeGrid.EntityId, ShipyardType.Weld);
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(weldButton);
            Controls.Add(weldButton);

            stopButton.Title   = MyStringId.GetOrCompute("Stop");
            stopButton.Tooltip = MyStringId.GetOrCompute("Stops the shipyard.");
            stopButton.Enabled = b =>
            {
                if (!b.BlockDefinition.SubtypeId.Contains("ShipyardCorner"))
                {
                    return(false);
                }

                ShipyardItem yard = GetYard(b);

                return(yard?.YardType == ShipyardType.Weld || yard?.YardType == ShipyardType.Grind);
            };
            stopButton.Visible = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            stopButton.SupportsMultipleBlocks = true;
            stopButton.Action = b => Communication.SendYardCommand(b.CubeGrid.EntityId, ShipyardType.Disabled);
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(stopButton);
            Controls.Add(stopButton);

            IMyTerminalControlCombobox buildPattern = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlCombobox, IMyCollector>("Shipyard_BuildPattern");

            buildPattern.Title           = MyStringId.GetOrCompute("Build Pattern");
            buildPattern.Tooltip         = MyStringId.GetOrCompute("Pattern used to build projections.");
            buildPattern.ComboBoxContent = FillPatternCombo;
            buildPattern.Visible         = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            buildPattern.Enabled         = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner") && GetYard(b)?.YardType == ShipyardType.Disabled;
            buildPattern.Getter          = GetBuildPattern;
            buildPattern.Setter          = SetBuildPattern;
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(buildPattern);
            Controls.Add(buildPattern);

            IMyTerminalControlSlider beamCountSlider = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlSlider, IMyCollector>("Shipyard_BeamCount");

            beamCountSlider.Title = MyStringId.GetOrCompute("Beam Count");

            beamCountSlider.Tooltip = MyStringId.GetOrCompute("Number of beams this shipyard can use per corner.");
            beamCountSlider.SetLimits(1, 3);
            beamCountSlider.Writer  = (b, result) => result.Append(GetBeamCount(b));
            beamCountSlider.Visible = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            beamCountSlider.Enabled = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner") && GetYard(b) != null;
            beamCountSlider.Getter  = b => GetBeamCount(b);
            beamCountSlider.Setter  = (b, v) =>
            {
                SetBeamCount(b, (int)Math.Round(v, 0, MidpointRounding.ToEven));
                beamCountSlider.UpdateVisual();
            };
            beamCountSlider.SupportsMultipleBlocks = true;
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(beamCountSlider);
            Controls.Add(beamCountSlider);

            IMyTerminalControlSlider grindSpeedSlider = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlSlider, IMyCollector>("Shipyard_GrindSpeed");

            grindSpeedSlider.Title = MyStringId.GetOrCompute("Grind Speed");

            grindSpeedSlider.Tooltip = MyStringId.GetOrCompute("How fast this shipyard grinds grids.");
            grindSpeedSlider.SetLimits(0.01f, 2);
            grindSpeedSlider.Writer  = (b, result) => result.Append(GetGrindSpeed(b));
            grindSpeedSlider.Visible = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            grindSpeedSlider.Enabled = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner") && GetYard(b) != null;
            grindSpeedSlider.Getter  = GetGrindSpeed;
            grindSpeedSlider.Setter  = (b, v) =>
            {
                SetGrindSpeed(b, (float)Math.Round(v, 2, MidpointRounding.ToEven));
                grindSpeedSlider.UpdateVisual();
            };
            grindSpeedSlider.SupportsMultipleBlocks = true;
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(grindSpeedSlider);
            Controls.Add(grindSpeedSlider);

            IMyTerminalControlSlider weldSpeedSlider = MyAPIGateway.TerminalControls.CreateControl <IMyTerminalControlSlider, IMyCollector>("Shipyard_WeldSpeed");

            weldSpeedSlider.Title = MyStringId.GetOrCompute("Weld Speed");

            weldSpeedSlider.Tooltip = MyStringId.GetOrCompute("How fast this shipyard welds grids.");
            weldSpeedSlider.SetLimits(0.01f, 2);
            weldSpeedSlider.Writer  = (b, result) => result.Append(GetWeldSpeed(b));
            weldSpeedSlider.Visible = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            weldSpeedSlider.Enabled = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner") && GetYard(b) != null;
            weldSpeedSlider.Getter  = GetWeldSpeed;
            weldSpeedSlider.Setter  = (b, v) =>
            {
                SetWeldSpeed(b, (float)Math.Round(v, 2, MidpointRounding.ToEven));
                weldSpeedSlider.UpdateVisual();
            };
            weldSpeedSlider.SupportsMultipleBlocks = true;
            MyAPIGateway.TerminalControls.AddControl <IMyCollector>(weldSpeedSlider);
            Controls.Add(weldSpeedSlider);

            IMyTerminalAction grindAction = MyAPIGateway.TerminalControls.CreateAction <IMyCollector>("Shipyard_GrindAction");

            grindAction.Enabled = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            grindAction.Name    = new StringBuilder("Grind");
            grindAction.Icon    = @"Textures\GUI\Icons\Actions\Start.dds";
            grindAction.Action  = b => Communication.SendYardCommand(b.CubeGrid.EntityId, ShipyardType.Grind);
            MyAPIGateway.TerminalControls.AddAction <IMyCollector>(grindAction);

            IMyTerminalAction weldAction = MyAPIGateway.TerminalControls.CreateAction <IMyCollector>("Shipyard_WeldAction");

            weldAction.Enabled = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            weldAction.Name    = new StringBuilder("Weld");
            weldAction.Icon    = @"Textures\GUI\Icons\Actions\Start.dds";
            weldAction.Action  = b => Communication.SendYardCommand(b.CubeGrid.EntityId, ShipyardType.Weld);
            MyAPIGateway.TerminalControls.AddAction <IMyCollector>(weldAction);

            IMyTerminalAction stopAction = MyAPIGateway.TerminalControls.CreateAction <IMyCollector>("Shipyard_StopAction");

            stopAction.Enabled = b => b.BlockDefinition.SubtypeId.Contains("ShipyardCorner");
            stopAction.Name    = new StringBuilder("Stop");
            stopAction.Icon    = @"Textures\GUI\Icons\Actions\Reset.dds";
            stopAction.Action  = b => Communication.SendYardCommand(b.CubeGrid.EntityId, ShipyardType.Disabled);
            MyAPIGateway.TerminalControls.AddAction <IMyCollector>(stopAction);
        }
示例#11
0
        private string FormatWeldStats(ShipyardItem item)
        {
            if (!_stats.ContainsKey(item))
            {
                _stats.Add(item, new StatInfo());
            }

            StatInfo stats = _stats[item];

            if (stats.StartTime == 0)
            {
                stats.StartTime = MyAPIGateway.Session.ElapsedPlayTime.TotalMilliseconds;
                //calculating stats can take tens or hundreds of ms, so drop it in a thread and check back when the scan animation is finished.
                MyAPIGateway.Parallel.StartBackground(() =>
                {
                    try
                    {
                        var statBlock         = Profiler.Start(FullName, nameof(FormatWeldStats));
                        stats.TotalComponents = new Dictionary <string, int>();
                        var blockList         = new List <IMySlimBlock>();
                        var processGrids      = new HashSet <IMyCubeGrid>();
                        processGrids.UnionWith(item.YardGrids);
                        processGrids.UnionWith(item.ContainsGrids);

                        var projections = new HashSet <IMyCubeGrid>();

                        foreach (IMyCubeGrid grid in processGrids)
                        {
                            if (grid.MarkedForClose || grid.Closed)
                            {
                                continue;
                            }

                            grid.GetBlocks(blockList);

                            foreach (IMySlimBlock block in blockList)
                            {
                                var projector = block?.FatBlock as IMyProjector;
                                if (projector == null)
                                {
                                    continue;
                                }
                                if (projector.IsProjecting && projector.ProjectedGrid != null)
                                {
                                    projections.Add(projector.ProjectedGrid);
                                }
                            }

                            blockList.Clear();
                        }

                        processGrids.UnionWith(projections);

                        foreach (IMyCubeGrid grid in processGrids)
                        {
                            if (grid.MarkedForClose || grid.Closed)
                            {
                                continue;
                            }

                            grid.GetBlocks(blockList);
                            stats.BlockCount += blockList.Count;

                            var missingComponents = new Dictionary <string, int>();
                            foreach (IMySlimBlock block in blockList)
                            {
                                //var blockDef = (MyObjectBuilder_CubeBlockDefinition)block.BlockDefinition.GetObjectBuilder();
                                //grindTime += Math.Max(blockDef.BuildTimeSeconds / ShipyardSettings.Instance.GrindMultiplier, 0.5f);

                                var blockDef = (MyCubeBlockDefinition)block.BlockDefinition;
                                //IntegrityPointsPerSec = MaxIntegrity / BuildTimeSeconds
                                //this is much, much faster than pulling the objectbuilder and getting the data from there.
                                if (grid.Physics != null)
                                {
                                    stats.GrindTime += Math.Max((1 - block.BuildPercent()) * (blockDef.MaxIntegrity / blockDef.IntegrityPointsPerSec) / MyAPIGateway.Session.WelderSpeedMultiplier / item.Settings.WeldMultiplier, 0.5f);
                                }
                                else
                                {
                                    stats.GrindTime += Math.Max(blockDef.MaxIntegrity / blockDef.IntegrityPointsPerSec / MyAPIGateway.Session.WelderSpeedMultiplier / item.Settings.WeldMultiplier, 0.5f);
                                }

                                block.GetMissingComponents(missingComponents);

                                if (grid.Physics != null)
                                {
                                    foreach (KeyValuePair <string, int> missing in missingComponents)
                                    {
                                        if (!stats.TotalComponents.ContainsKey(missing.Key))
                                        {
                                            stats.TotalComponents.Add(missing.Key, missing.Value);
                                        }
                                        else
                                        {
                                            stats.TotalComponents[missing.Key] += missing.Value;
                                        }
                                    }
                                }
                                else
                                {
                                    //projections will always consume the fully component count
                                    foreach (MyCubeBlockDefinition.Component component in blockDef.Components)
                                    {
                                        if (stats.TotalComponents.ContainsKey(component.Definition.Id.SubtypeName))
                                        {
                                            stats.TotalComponents[component.Definition.Id.SubtypeName] += component.Count;
                                        }
                                        else
                                        {
                                            stats.TotalComponents.Add(component.Definition.Id.SubtypeName, component.Count);
                                        }
                                    }
                                }
                                missingComponents.Clear();
                            }

                            blockList.Clear();
                        }

                        var result = new StringBuilder();
                        result.Append("Scan Results:\r\n\r\n");
                        result.Append("Targets: " + item.YardGrids.Count);
                        result.Append("\r\n");
                        result.Append("Block Count: " + stats.BlockCount);
                        result.Append("\r\n");
                        float grindTime = stats.GrindTime / (item.Settings.BeamCount * 8);
                        if (grindTime >= 7200)
                        {
                            result.Append("Estimated Construct Time: " + (grindTime / 3600).ToString("0.00") + " hours");
                        }
                        else if (grindTime >= 120)
                        {
                            result.Append("Estimated Construct Time: " + (grindTime / 60).ToString("0.00") + " min");
                        }
                        else
                        {
                            result.Append("Estimated Construct Time: " + grindTime.ToString("0.00") + "s");
                        }
                        result.Append("\r\n");
                        if (stats.TotalComponents.Any())
                        {
                            result.Append("Estimated Components Used:\r\n\r\n");
                            double multiplier = Math.Max(item.ShipyardBox.HalfExtent.LengthSquared() / 200000, 1);
                            foreach (KeyValuePair <string, int> component in stats.TotalComponents)
                            {
                                if (component.Value != 0)
                                {
                                    result.Append($"{component.Key}: {component.Value / multiplier}\r\n");
                                }
                            }
                        }

                        stats.Output = result.ToString();
                        statBlock.End();
                    }
                    catch (Exception ex)
                    {
                        Logging.Instance.WriteLine(ex.ToString());
                    }
                });
            }

            if (!string.IsNullOrEmpty(stats.Output) && MyAPIGateway.Session.ElapsedPlayTime.TotalMilliseconds - stats.StartTime > 6000)
            {
                return(stats.Output);
            }
            return("SCANNING...");
        }
示例#12
0
        public string FormatStatus(ShipyardItem item)
        {
            bool welding = false;
            var  result  = new StringBuilder();

            result.Append("Shipyard Status:\r\n");
            switch (item.YardType)
            {
            case ShipyardType.Disabled:
                result.Append("IDLE");
                break;

            case ShipyardType.Grind:
                result.Append("GRINDING");
                break;

            case ShipyardType.Weld:
                result.Append("WELDING");
                welding = true;
                break;

            default:
                result.Append("ERROR");
                return(result.ToString());
            }

            result.Append("\r\n\r\n");

            if (welding && item.MissingComponentsDict.Count > 0)
            {
                result.Append("Missing Components:\r\n");
                foreach (KeyValuePair <string, int> component in item.MissingComponentsDict)
                {
                    result.Append($"{component.Key}: {component.Value}\r\n");
                }
                result.Append("\r\n");
            }

            float time = 0f;

            if (item.YardType == ShipyardType.Grind)
            {
                foreach (BlockTarget target in item.TargetBlocks)
                {
                    if (target.Projector != null)
                    {
                        continue;
                    }
                    time += target.Block.Integrity / ((MyCubeBlockDefinition)target.Block.BlockDefinition).IntegrityPointsPerSec;
                }
                time /= item.Settings.GrindMultiplier;
                time  = time / (item.Settings.BeamCount * 8);
            }
            else //welding
            {
                foreach (BlockTarget target in item.TargetBlocks)
                {
                    if (target.Projector != null)
                    {
                        time += target.BuildTime;
                    }
                    else
                    {
                        time += (target.Block.MaxIntegrity - target.Block.Integrity) / ((MyCubeBlockDefinition)target.Block.BlockDefinition).IntegrityPointsPerSec;
                    }
                }
                time /= item.Settings.WeldMultiplier;
                time  = time / (item.Settings.BeamCount * 8);
            }

            int active = item.BlocksToProcess.Sum(entry => entry.Value.Count(target => target != null));

            result.Append("Targets: " + item.YardGrids.Count);
            result.Append("\r\n");
            result.Append($"Active beams: {active}/{item.Settings.BeamCount * 8}");
            result.Append("\r\n");
            result.Append("Blocks remaining: " + item.TargetBlocks.Count);
            result.Append("\r\n");
            result.Append("Estimated time remaining: " + TimeSpan.FromSeconds((int)time).ToString("g"));
            result.Append("\r\n\r\n");
            return(result.ToString());
        }
示例#13
0
        public override void Handle()
        {
            var tmpEntities = new HashSet <IMyEntity>();

            MyAPIGateway.Entities.GetEntities(tmpEntities);
            if (tmpEntities.Count == 0)
            {
                Logging.Instance.WriteLine("Failed to get list of entities in ShipyardDetection.");
                return;
            }

            //copy the list of entities because concurrency
            IMyEntity[] entities = tmpEntities.ToArray();

            //run through our current list of shipyards and make sure they're still valid
            var itemsToRemove   = new HashSet <ShipyardItem>();
            var firstCheckBlock = Profiler.Start(FullName, nameof(Handle), "First Check");

            foreach (ShipyardItem item in ShipyardsList)
            {
                if (!AreToolsConnected(item.Tools))
                {
                    Logging.Instance.WriteLine("remove item tools " + item.Tools.Length);
                    item.Disable();
                    itemsToRemove.Add(item);
                    foreach (var tool in item.Tools)
                    {
                        Communication.SendCustomInfo(tool.EntityId, "Invalid Shipyard: All tools must be on the same conveyor network!");
                    }
                    continue;
                }

                if (item.Tools.Any(x => x.Closed || x.MarkedForClose))
                {
                    Logging.Instance.WriteLine("remove item closed tools " + item.Tools.Length);
                    item.Disable();
                    itemsToRemove.Add(item);
                    continue;
                }

                if (!entities.Contains(item.YardEntity) || item.YardEntity.Closed || item.YardEntity.MarkedForClose)
                {
                    Logging.Instance.WriteLine("remove item entity");
                    item.Disable();
                    itemsToRemove.Add(item);
                    continue;
                }

                using (Profiler.Start(FullName, nameof(Handle), "Physics Check"))
                {
                    if (item.YardEntity.Physics == null ||
                        item.StaticYard && (!item.YardEntity.Physics.IsStatic || !((IMyCubeGrid)item.YardEntity).IsInVoxels()))
                    {
                        Logging.Instance.WriteLine("remove item physics");
                        itemsToRemove.Add(item);
                        item.Disable();
                        foreach (var tool in item.Tools)
                        {
                            Communication.SendCustomInfo(tool.EntityId, "Invalid Shipyard: Shipyard must be anchored to voxels!");
                        }
                        continue;
                    }
                }

                if (item.Tools.Any(t => ((IMyTerminalBlock)t).CustomInfo.Contains("Invalid Shipyard")))
                {
                    foreach (var tool in item.Tools)
                    {
                        Communication.SendCustomInfo(tool.EntityId, string.Empty);
                    }
                }
            }
            firstCheckBlock.End();

            foreach (ShipyardItem item in itemsToRemove)
            {
                item.YardType = ShipyardType.Invalid;
                Communication.SendYardState(item);
                ShipyardsList.Remove(item);
            }

            foreach (IMyEntity entity in entities)
            {
                _corners.Clear();
                var grid = entity as IMyCubeGrid;

                if (grid?.Physics == null || grid.Closed || grid.MarkedForClose)
                {
                    continue;
                }

                if (ShipyardsList.Any(x => x.EntityId == entity.EntityId))
                {
                    continue;
                }

                var gridBlocks = new List <IMySlimBlock>();
                grid.GetBlocks(gridBlocks);

                foreach (IMySlimBlock slimBlock in gridBlocks.ToArray())
                {
                    var collector = slimBlock.FatBlock as IMyCollector;
                    if (collector == null)
                    {
                        continue;
                    }

                    if (collector.BlockDefinition.SubtypeId.StartsWith("ShipyardCorner"))
                    {
                        _corners.Add(slimBlock.FatBlock);
                    }
                }

                if (_corners.Count != 8)
                {
                    foreach (var tool in _corners)
                    {
                        Communication.SendCustomInfo(tool.EntityId, $"Invalid Shipyard: Must be 8 corner blocks, there are {_corners.Count} on this grid!");
                    }
                    continue;
                }

                if (_corners.Any(c => c.BlockDefinition.SubtypeId != _corners[0].BlockDefinition.SubtypeId))
                {
                    foreach (var tool in _corners)
                    {
                        Communication.SendCustomInfo(tool.EntityId, $"Invalid Shipyard: All 8 corner blocks must be the same type!");
                    }
                    continue;
                }

                using (Profiler.Start(FullName, nameof(Handle), "Static Check"))
                {
                    if (_corners[0].BlockDefinition.SubtypeId == "ShipyardCorner_Large" && !ShipyardCore.Debug)
                    {
                        if (!grid.IsStatic || !grid.IsInVoxels())
                        {
                            Logging.Instance.WriteDebug($"Yard {grid.EntityId} failed: Static check");
                            foreach (var tool in _corners)
                            {
                                Communication.SendCustomInfo(tool.EntityId, "Invalid Shipyard: Shipyard must be anchored to voxels!");
                            }
                            continue;
                        }
                    }
                }

                if (!IsYardValid(entity, _corners))
                {
                    continue;
                }

                //add an offset of 2.5m because the corner points are at the center of a 3^3 block, and the yard will be 2.5m short in all dimensions
                MyOrientedBoundingBoxD testBox = MathUtility.CreateOrientedBoundingBox((IMyCubeGrid)entity, _corners.Select(x => x.GetPosition()).ToList(), 2.5);

                Logging.Instance.WriteLine("Found yard");
                var item = new ShipyardItem(
                    testBox,
                    _corners.ToArray(),
                    ShipyardType.Disabled,
                    entity);
                item.Settings = ShipyardSettings.Instance.GetYardSettings(item.EntityId);
                foreach (IMyCubeBlock tool in _corners)
                {
                    item.BlocksToProcess.Add(tool.EntityId, new BlockTarget[3]);
                }

                ShipyardsList.Add(item);
                Communication.SendNewYard(item);
                foreach (var tool in item.Tools)
                {
                    Communication.SendCustomInfo(tool.EntityId, "");
                }
            }

            Communication.SendYardCount();
        }