public bool ExecNext()
        {
            var             found = false;
            IScriptRootData data  = null;

            lock (ExecQueue) found = ExecQueue.TryDequeue(out data);
            if (!found)
            {
                return(false);
            }

            if (!ThreadPool.QueueUserWorkItem(ExecScript, data))
            {
                Log($"EmpyrionScripting Mod: ExecNext NorThreadPoolFree {data.ScriptId}", LogLevel.Debug);
                return(false);
            }
            return(true);
        }
        public void Add(IScriptRootData data)
        {
            if (ScriptNeedsMainThread.TryGetValue(data.ScriptId, out var needMainThread))
            {
                data.ScriptNeedsMainThread = needMainThread;
            }
            else
            {
                ScriptNeedsMainThread.TryAdd(data.ScriptId, false);
            }

            if (WaitForExec.TryAdd(data.ScriptId, data))
            {
                ExecQueue.Enqueue(data.ScriptId);
            }
            else
            {
                WaitForExec.AddOrUpdate(data.ScriptId, data, (scriptId, oldData) => data);
            }
        }
        public void ExecNext(int maxCount, int scriptsSyncExecution, ref int syncExecCount, Stopwatch scriptLoopTimeLimiter)
        {
            if (BackgroundWorkerToDo.Count > maxCount / 2)
            {
                return;
            }

            var scriptLoopTimeLimiterStopwatch = scriptLoopTimeLimiter;
            var timeLimitBackgroundReached     = new Func <bool>(() => scriptLoopTimeLimiterStopwatch.ElapsedMilliseconds > EmpyrionScripting.Configuration.Current.ScriptLoopBackgroundTimeLimiterMS);

            TimeLimitSyncReached = new Func <bool>(() => scriptLoopTimeLimiterStopwatch.ElapsedMilliseconds > EmpyrionScripting.Configuration.Current.ScriptLoopSyncTimeLimiterMS);

            Log($"ExecNext: {WaitForExec.Count} -> {ExecQueue.Count}", LogLevel.Debug);

            for (int i = maxCount - 1; i >= 0; i--)
            {
                if (ExecQueue.TryDequeue(out var scriptId) && WaitForExec.TryGetValue(scriptId, out var data))
                {
                    if (data.ScriptNeedsMainThread)
                    {
                        Interlocked.Increment(ref syncExecCount);

                        if (syncExecCount > scriptsSyncExecution)
                        {
                            ExecQueue.Enqueue(scriptId);
                        }
                        else
                        {
                            ((ScriptRootData)data).ScriptLoopTimeLimitReached = TimeLimitSyncReached;
                            ExecNext(data);
                        }
                    }
                    else
                    {
                        ((ScriptRootData)data).ScriptLoopTimeLimitReached = timeLimitBackgroundReached;
                        ExecNext(data);
                    }
                }