static void DeconstructPart(TextWriter output, IScriptRootData root, IStructure S, DeconstructData deconstructData, IContainer target, VectorInt3 targetPos, string N)
        {
            IDeviceLock locked = null;

            var startTime       = DateTime.Now;
            var maxMilliSeconds = EmpyrionScripting.Configuration.Current.InGameScriptsIntervallMS;

            try
            {
                for (; deconstructData.Y >= deconstructData.MinPos.y; deconstructData.Y--)
                {
                    for (; deconstructData.X <= deconstructData.MaxPos.x; deconstructData.X++)
                    {
                        for (; deconstructData.Z <= deconstructData.MaxPos.z; deconstructData.Z++)
                        {
                            deconstructData.CheckedBlocks++;

                            var block = S.GetBlock(deconstructData.X, 128 + deconstructData.Y, deconstructData.Z);
                            if (block != null)
                            {
                                block.Get(out var blockType, out _, out _, out _);
                                if (blockType > 0 && blockType != PlayerCoreType)
                                {
                                    locked = locked ?? CreateDeviceLock(EmpyrionScripting.ModApi?.Playfield, root.E.S.GetCurrent(), targetPos);
                                    if (!locked.Success)
                                    {
                                        deconstructData.CheckedBlocks--;
                                        output.WriteLine($"Container '{N}' is locked");
                                        return;
                                    }

                                    if (target.AddItems(blockType, 1) > 0)
                                    {
                                        deconstructData.CheckedBlocks--;
                                        output.WriteLine($"Container '{N}' is full");
                                        return;
                                    }
                                    block.Set(0);
                                    deconstructData.RemovedBlocks++;

                                    if (deconstructData.RemovedBlocks > 100 && deconstructData.RemovedBlocks % 100 == 0 && (DateTime.Now - startTime).TotalMilliseconds > maxMilliSeconds)
                                    {
                                        return;
                                    }
                                }
                            }
                        }
                        deconstructData.Z = deconstructData.MinPos.z;
                    }
                    deconstructData.X = deconstructData.MinPos.x;
                }
            }
            finally
            {
                locked?.Dispose();
            }
        }
        static void ProcessBlockPart(TextWriter output, IScriptRootData root, IStructure S, ProcessBlockData processBlockData,
                                     IContainer target, VectorInt3 targetPos, string N, int replaceId, Tuple <int, int>[] list,
                                     Func <IContainer, int, bool> processBlock)
        {
            IDeviceLock locked = null;

            try
            {
                for (; processBlockData.Y >= processBlockData.MinPos.y; processBlockData.Y--)
                {
                    for (; processBlockData.X <= processBlockData.MaxPos.x; processBlockData.X++)
                    {
                        for (; processBlockData.Z <= processBlockData.MaxPos.z; processBlockData.Z++)
                        {
                            processBlockData.CheckedBlocks++;

                            var block = S.GetBlock(processBlockData.X, 128 + processBlockData.Y, processBlockData.Z);
                            if (block != null)
                            {
                                block.Get(out var blockType, out _, out _, out _);

                                if (list != null &&
                                    list.Length > 0 &&
                                    !list.Any(L => L.Item1 <= blockType && L.Item2 >= blockType))
                                {
                                    blockType = 0;
                                }

                                if (blockType > 0 && blockType != PlayerCoreType)
                                {
                                    if (EmpyrionScripting.Configuration.Current?.DeconstructBlockSubstitution != null &&
                                        EmpyrionScripting.Configuration.Current.DeconstructBlockSubstitution.TryGetValue(blockType, out var substituteTo))
                                    {
                                        blockType = substituteTo;
                                    }

                                    if (blockType > 0 && N != null)
                                    {
                                        locked = locked ?? WeakCreateDeviceLock(root, root.GetCurrentPlayfield(), root.E.S.GetCurrent(), targetPos);
                                        if (!locked.Success)
                                        {
                                            processBlockData.CheckedBlocks--;
                                            output.WriteLine($"Container '{N}' is locked");
                                            return;
                                        }

                                        if (processBlock(target, blockType))
                                        {
                                            processBlockData.CheckedBlocks--;
                                            output.WriteLine($"Container '{N}' is full");
                                            return;
                                        }
                                    }

                                    block.Set(replaceId);
                                    processBlockData.RemovedBlocks++;

                                    if (processBlockData.RemovedBlocks > 100 && processBlockData.RemovedBlocks % 100 == 0 && root.TimeLimitReached)
                                    {
                                        return;
                                    }
                                }
                            }
                        }
                        processBlockData.Z = processBlockData.MinPos.z;
                    }
                    processBlockData.X = processBlockData.MinPos.x;
                }
            }
            finally
            {
                locked?.Dispose();
            }
        }