/// <summary> /// If there are enough resources, return TimeSpan(0) /// Otherwise calculate how long it will take to get enough resources and transit res from /// main village, if we have that enabled. Return the one that takes less time. /// DateTime for usage in nextExecution time /// </summary> /// <param name="acc">Account</param> /// <param name="vill">(target) Village</param> /// <param name="requiredRes">Resources required</param> /// <param name="task">Bot task that doesn't have enough resources</param> /// <param name="buildingTask">Potential building task</param> /// <returns>When next village update should occur</returns> private static DateTime?NewUnfinishedTask(Account acc, Village vill, Resources requiredRes, BotTask task, BuildingTask buildingTask = null) { var stillNeededRes = SubtractResources(requiredRes.ToArray(), vill.Res.Stored.Resources.ToArray(), true); // Whether we have enough resources. This should already be checked before calling this method! if (IsZeroResources(stillNeededRes)) { ResSpendingHelper.AddUnfinishedTask(vill, task, requiredRes); return(DateTime.Now); } acc.Wb.Log($"Not enough resources for the task {task.GetName()}! Needed {requiredRes}. Bot will try finish the task later"); if (IsStorageTooLow(acc, vill, requiredRes)) { acc.Wb.Log($"Storage is too low."); ResSpendingHelper.AddUnfinishedTask(vill, task, requiredRes); return(null); } // Try to use hero resources first if (vill.Settings.UseHeroRes && acc.AccInfo.ServerVersion == ServerVersionEnum.T4_5) // Only T4.5 has resources in hero inv { var heroRes = HeroHelper.GetHeroResources(acc); // If we have some hero resources, we should use those first if (!IsZeroResources(heroRes)) { var heroEquipTask = UseHeroResources(acc, vill, ref stillNeededRes, heroRes, buildingTask); // If we have enough hero res for our task, execute the task // right after hero equip finishes if (IsZeroResources(SubtractResources(stillNeededRes, heroRes, true))) { heroEquipTask.NextTask = task; return(null); } } } ResSpendingHelper.AddUnfinishedTask(vill, task, requiredRes); // When will we have enough resources from production DateTime enoughRes = TimeHelper.EnoughResToUpgrade(vill, stillNeededRes); var mainVill = AccountHelper.GetMainVillage(acc); if (mainVill == vill) { return(enoughRes); } DateTime resTransit = MarketHelper.TransitResourcesFromMain(acc, vill); if (resTransit < enoughRes) { enoughRes = resTransit; } if (enoughRes < DateTime.Now) { return(DateTime.Now); } return(enoughRes); }
/// <summary> /// Called PageLoaded (after navigating to a specific url) or from /// Task timer, if there is no url/bot is already on the url /// </summary> /// <param name="acc">Account</param> /// <param name="task">Task to be executed</param> /// <returns></returns> public static async Task Execute(Account acc, BotTask task) { // Before every execution, wait a random delay if (acc.AccInfo.ServerVersion == Classificator.ServerVersionEnum.T4_5) { await Task.Delay(AccountHelper.Delay()); } if (acc.Wb?.CurrentUrl == null && task.GetType() != typeof(CheckProxy)) { await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/dorf1.php"); } if (task.Vill == null) { task.Vill = acc.Villages.FirstOrDefault(x => x.Active); } try { acc.Wb.Log($"Executing task {task.GetName()}" + (task.Vill == null ? "" : $" in village {task.Vill.Name}")); switch (await task.Execute(acc)) { case TaskRes.Retry: task.RetryCounter++; if (task.NextExecute == null) { task.NextExecute = DateTime.Now.AddMinutes(3); } break; default: task.RetryCounter = 0; if (task.NextTask != null) { task.NextTask.ExecuteAt = DateTime.MinValue.AddHours(5); task.NextTask.Stage = TaskStage.Start; TaskExecutor.AddTask(acc, task.NextTask); task.NextTask = null; } break; } } catch (Exception e) { if (acc.Wb != null) { acc.Wb.Log($"Error executing task {task.GetName()}! Vill {task.Vill?.Name}", e); } task.RetryCounter++; if (task.NextExecute == null) { task.NextExecute = DateTime.Now.AddMinutes(3); } } //We want to re-execute the same task later if (task.NextExecute != null && task.RetryCounter < 3) { task.ExecuteAt = task.NextExecute ?? default; task.NextExecute = null; ReorderTaskList(acc); task.Stage = TaskStage.Start; return; } // Remove the task from the task list acc.Tasks.Remove(task); }
/// <summary> /// Called PageLoaded (after navigating to a specific url) or from /// Task timer, if there is no url/bot is already on the url /// </summary> /// <param name="acc">Account</param> /// <param name="task">Task to be executed</param> /// <returns></returns> public static async Task Execute(Account acc, BotTask task) { // Before every execution, wait a random delay await Task.Delay(AccountHelper.Delay()); if (task.Vill == null) { task.Vill = acc.Villages.FirstOrDefault(x => x.Active); } acc.Logger.Information($"Executing task {task.GetName()}" + (task.Vill == null ? "" : $" in village {task.Vill.Name}")); try { switch (await task.Execute(acc)) { case TaskRes.Retry: task.RetryCounter++; if (task.NextExecute == null) { task.NextExecute = DateTime.Now.AddMinutes(3); } break; default: task.RetryCounter = 0; if (task.NextTask != null) { task.NextTask.ExecuteAt = DateTime.MinValue.AddHours(5); task.NextTask.Stage = TaskStage.Start; acc.Tasks.Add(task.NextTask); task.NextTask = null; } break; } } catch (WebDriverException e) when(e.Message.Contains("chrome not reachable") || e.Message.Contains("no such window:")) { acc.Logger.Warning($"Chrome has problem while executing task {task.GetName()}! Vill {task.Vill?.Name}. Try reopen Chrome"); acc.Tasks.Add(new ReopenDriver() { ExecuteAt = DateTime.MinValue, Priority = TaskPriority.High, ReopenAt = DateTime.MinValue }); //try exccute task after we reopen chrome 1 mintues if (task.NextExecute == null) { task.NextExecute = DateTime.MinValue.AddMinutes(1); // make sure current task is excuted after reopen driver } } catch (Exception e) { acc.Logger.Error(e, $"Error executing task {task.GetName()}! Vill {task.Vill?.Name}"); task.RetryCounter++; if (task.NextExecute == null) { task.NextExecute = DateTime.Now.AddMinutes(3); } } //We want to re-execute the same task later if (task.NextExecute != null && task.RetryCounter < 3) { task.ExecuteAt = task.NextExecute ?? default; task.NextExecute = null; acc.Tasks.ReOrder(); task.Stage = TaskStage.Start; acc.Logger.Warning($"Task {task.GetName()}" + (task.Vill == null ? "" : $" in village {task.Vill.Name} will be re-executed at {task.ExecuteAt}")); return; } // Remove the task from the task list acc.Tasks.Remove(task); if (task.RetryCounter >= 3) { acc.Logger.Warning($"Task {task.GetName()}" + (task.Vill == null ? "" : $" in village {task.Vill.Name} is already re-executed 3 times. Ignore it")); } else { acc.Logger.Information($"Task {task.GetName()}" + (task.Vill == null ? "" : $" in village {task.Vill.Name} is done.")); } }