void Main(int ticks = 0)
        {
            try
            {
                if (ticks == 0)
                {
                    ticks = SessionCore.WorkSkipTicks;
                }
                System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
                if (Tool.IsToolWorking())
                {
                    watch.Start();
                }
                try
                {
                    if (IsWelder && LocalPlayerIsOwner && HUDModule.MessageExpired)
                    {
                        MissingHUD.Hide();
                    }
                    PowerModule.SetPowerUsage();

                    if (Tool.IsToolWorking() && PowerModule.HasEnoughPower)
                    {
                        Work(ticks);
                        BeamCtlModule.DrawBeam();
                    }
                    else if (!PowerModule.HasEnoughPower)
                    {
                        DebugNote.Text = $"{Tool.CustomName}: not enough power";
                    }
                    else
                    {
                        DebugNote.Text = $"{Tool.CustomName}: idle";
                        //UnbuiltBlocks.Clear();
                    }
                    Tool.RefreshCustomInfo();
                    //if (SessionCore.Debug) DebugNote.Text = $"{Tool.CustomName} perf. impact: {(RunTimesAvailable ? Math.Round(AvgRunTime, 5).ToString() : "--")}/{(RunTimesAvailable ? Math.Round(MaxRunTime, 5).ToString() : "--")} ms (avg/max)";
                }
                catch (Exception Scrap)
                {
                    SessionCore.LogError($"{Tool.CustomName}.Main().Work()", Scrap);
                }
                if (Tool.IsToolWorking())
                {
                    watch.Stop();
                    watch.Report(Tool.CustomName, "Main()");
                }
            }
            catch (Exception Scrap)
            {
                SessionCore.LogError($"{Tool.CustomName}.Main()", Scrap);
            }
        }
        public void UpdateInventoryCache()
        {
            if (SessionCore.IsUnloading)
            {
                return;
            }
            lock (InventoryLock)
            {
                InventoriesStatus.Clear();
                OnboardInventoryOwners.Clear();
                if (!HasWatchers)
                {
                    return;
                }
                ShallShowDebug = true;
                System.Diagnostics.Stopwatch Watch = new System.Diagnostics.Stopwatch();
                Watch.Start();
                List <IMyTerminalBlock>       trash  = new List <IMyTerminalBlock>();
                Func <IMyTerminalBlock, bool> Puller = (Block) =>
                {
                    if (IsValidInventory(Block))
                    {
                        OnboardInventoryOwners.Add(Block);
                    }
                    return(false);
                };
                Term.GetBlocksOfType(trash, Puller);

                foreach (var Watcher in Watchers)
                {
                    InventoriesPerWatcher[Watcher] = RefreshAccessibleInventories(Watcher);
                }
                LastUpdate   = DateTime.Now;
                NeedsRefresh = false;

                Watch.Stop();
                Watch.Report(Grid.CustomName, "Grid inventories refresh", UseAsync: true);
            }
        }
        void Weld(ICollection <IMySlimBlock> Blocks, int ticks = 1)
        {
            UnbuiltBlocks.Clear();
            if (Blocks.Count == 0)
            {
                return;
            }
            float SpeedRatio   = (VanillaToolConstants.WelderSpeed / Blocks.Count) * ticks * TermModule.SpeedMultiplier;
            float BoneFixSpeed = VanillaToolConstants.WelderBoneRepairSpeed * ticks;
            Dictionary <IMySlimBlock, int> UniqueBlocks = new Dictionary <IMySlimBlock, int>();

            if (!TermModule.DistanceMode)
            {
                UniqueBlocks = Blocks.CollapseDuplicates();
            }
            else
            {
                IMySlimBlock Block = Blocks.OrderByDescending(x => Vector3D.DistanceSquared(x.GetPosition(), Tool.GetPosition())).ToList().First();
                UniqueBlocks.Add(Block, 1);
                SpeedRatio = VanillaToolConstants.WelderSpeed * ticks * TermModule.SpeedMultiplier;
            }
            HashSet <IMySlimBlock> unbuilt     = new HashSet <IMySlimBlock>();
            List <IMySlimBlock>    CanBuild    = new List <IMySlimBlock>();
            List <IMySlimBlock>    CannotBuild = new List <IMySlimBlock>();

            if (MyAPIGateway.Session.CreativeMode)
            {
                foreach (IMySlimBlock Block in UniqueBlocks.Keys)
                {
                    float blockRatio = SpeedRatio * UniqueBlocks.GetData(Block);
                    Block.MoveItemsToConstructionStockpile(ToolCargo);
                    Block.IncreaseMountLevel(blockRatio, Welder.OwnerId, ToolCargo, BoneFixSpeed, Welder.HelpOthers);
                }
                return;
            }

            foreach (IMySlimBlock Block in UniqueBlocks.Keys)
            {
                if (Block.CanContinueBuild(ToolCargo))
                {
                    CanBuild.Add(Block);
                }
                else
                {
                    CannotBuild.Add(Block);
                }
            }

            SessionCore.DebugWrite(Tool.CustomName, $"Can build {CanBuild.Count} blocks", WriteOnlyIfDebug: true);
            SessionCore.DebugWrite(Tool.CustomName, $"Can't build {CannotBuild.Count} blocks", WriteOnlyIfDebug: true);

            bool Pull = false;

            var Components = Reduce(CannotBuild.ReadMissingComponents());
            Dictionary <string, int> Pulled = new Dictionary <string, int>();

            lock (GridInventoryModule.InventoryLock)
            {
                if (Welder.UseConveyorSystem)
                {
                    GridInventoryModule.PullIn(Welder, Components, "Component");
                }
                Pull = Pulled.Count > 0;
            }
            SessionCore.DebugWrite(Tool.CustomName, $"Pulled {Pulled.Values.Sum()} components", WriteOnlyIfDebug: true);

            System.Diagnostics.Stopwatch WelderWatch = new System.Diagnostics.Stopwatch();
            WelderWatch.Start();
            foreach (IMySlimBlock Block in UniqueBlocks.Keys)
            {
                if (!Pull && !CanBuild.Contains(Block))
                {
                    unbuilt.Add(Block);
                    continue;
                }
                float blockRatio = SpeedRatio * UniqueBlocks.GetData(Block);
                if (!Weld(Block, blockRatio, BoneFixSpeed))
                {
                    unbuilt.Add(Block);
                }
            }
            WelderWatch.Stop();
            WelderWatch.Report(Tool.CustomName, "Welding", UseAsync: true);

            System.Diagnostics.Stopwatch ReadMissingWatch = new System.Diagnostics.Stopwatch();
            ReadMissingWatch.Start();
            if (unbuilt.Count > 0)
            {
                Dictionary <string, int> Missing = new Dictionary <string, int>();
                unbuilt.ReadMissingComponents(Missing);
                Missing = Reduce(Missing);
                if (Missing.Count > 0)
                {
                    UnbuiltBlocks.UnionWith(unbuilt);
                }
            }
            ComplainUnbuilt();
            ReadMissingWatch.Stop();
            ReadMissingWatch.Report(Tool.CustomName, "ReadMissing", true);
            SessionCore.DebugAsync(Tool.CustomName, $"Unbuilt: {unbuilt.Count} blocks", WriteOnlyIfDebug: true);
        }