void StartScriptLoop(ScriptBase script) { if (scriptTask != null && scriptTask.Status == TaskStatus.Running) { logTools.Error("Already has one running Script Task", false); return; } logTools.Info("StartScriptLoop..."); mumuState = MumuState.Create(); script.SetMumuState(mumuState); tokenSource = new CancellationTokenSource(); ct = tokenSource.Token; scriptTask = new Task(() => { viewportRect = mumuState.ViewportRect; viewportCapture = mumuState.DoCapture(viewportRect); logTools.Info($"Script: {script.Name} OnStart"); script.OnStart(viewportCapture, viewportRect); while (true) { if (ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } try { Thread.Sleep(script.Interval); viewportRect = mumuState.ViewportRect; viewportCapture = mumuState.DoCapture(viewportRect); logTools.Info($"Script: {script.Name} Tick"); script.Tick(viewportCapture, viewportRect); } catch (Exception e) { logTools.Error($"Script: {script.Name} Tick ERROR", false); if (!script.CanKeepOnWhenException || logTools.IsSelfOrChildrenBreakException(e)) { throw e; } else { PrintException(e); } } } }, tokenSource.Token); scriptTask.ContinueWith((t) => { if (t.IsFaulted) { PrintException(t.Exception); } else if (t.IsCanceled) { logTools.Error("Script Canceled", false); } ScriptBase.OnScriptEnded(script.Name, !t.IsFaulted && !t.IsCanceled); }); scriptTask.Start(); }