diff --git a/MainCore/AppDbContext.cs b/MainCore/AppDbContext.cs index ffcc4e041..606792fe6 100644 --- a/MainCore/AppDbContext.cs +++ b/MainCore/AppDbContext.cs @@ -234,6 +234,7 @@ public void AddAccount(int accountId) WorkTimeMax = 380, SleepTimeMin = 480, SleepTimeMax = 600, + IsSleepBetweenProxyChanging = false, IsClosedIfNoTask = false, IsDontLoadImage = false, IsMinimized = false, @@ -338,6 +339,7 @@ public void UpdateDatabase() IsDontLoadImage = false, IsMinimized = false, IsAutoAdventure = false, + IsSleepBetweenProxyChanging = false, FarmIntervalMax = 610, FarmIntervalMin = 590, }); @@ -512,6 +514,7 @@ public void AddVersionInfo() KeyValuePair.Create(2022102716038,"IgnoreRomanAdvantage"), KeyValuePair.Create(202212152155,"NPCWarehouse"), KeyValuePair.Create(202212301138,"FarmSettings"), + KeyValuePair.Create(202302101011,"SleepWhenChangingProxy"), }; foreach (var migration in migrations) { diff --git a/MainCore/Errors/Skip.cs b/MainCore/Errors/Skip.cs index 9e8ed42b2..e56a17e32 100644 --- a/MainCore/Errors/Skip.cs +++ b/MainCore/Errors/Skip.cs @@ -4,5 +4,8 @@ namespace MainCore.Errors { public class Skip : Error { + public Skip(string message) : base(message) + { + } } } \ No newline at end of file diff --git a/MainCore/Helper/Implementations/UpgradeBuildingHelper.cs b/MainCore/Helper/Implementations/UpgradeBuildingHelper.cs index c2fbcd060..eec739d2d 100644 --- a/MainCore/Helper/Implementations/UpgradeBuildingHelper.cs +++ b/MainCore/Helper/Implementations/UpgradeBuildingHelper.cs @@ -43,52 +43,64 @@ public Result NextBuildingTask(int accountId, int villageId) var tasks = _planManager.GetList(villageId); if (tasks.Count == 0) { - return Result.Fail("Queue is empty."); + return Result.Fail(new Skip("Queue is empty.")); } + using var context = _contextFactory.CreateDbContext(); - var currentList = context.VillagesCurrentlyBuildings.Where(x => x.VillageId == villageId).ToList(); - var totalBuild = currentList.Count(x => x.Level != -1); + var currentList = context.VillagesCurrentlyBuildings.Where(x => x.VillageId == villageId && x.Level != -1).ToList(); + var totalBuild = currentList.Count; + + if (totalBuild == 0) return GetFirstTask(villageId); + + var accountInfo = context.AccountsInfo.Find(accountId); + var tribe = accountInfo.Tribe; + var hasPlusAccount = accountInfo.HasPlusAccount; + var setting = context.VillagesSettings.Find(villageId); + + var romanAdvantage = tribe == TribeEnums.Romans && !setting.IsIgnoreRomanAdvantage; - if (totalBuild > 0) + var maxBuild = 1; + if (hasPlusAccount) maxBuild++; + if (romanAdvantage) maxBuild++; + if (totalBuild == maxBuild) + { + return Result.Fail(new Skip("Amount of currently building is equal with maximum building can build in same time")); + } + if (romanAdvantage && totalBuild == 2 && currentList.Count(x => x.Id < 19) == 2) { - var accountInfo = context.AccountsInfo.Find(accountId); - var tribe = accountInfo.Tribe; - var hasPlusAccount = accountInfo.HasPlusAccount; - var setting = context.VillagesSettings.Find(villageId); + if (GetFirstBuildingTask(villageId) is null) return Result.Fail(new Skip("Amount of currently building is equal with maximum building can build in same time (there is only resource field in queue)")); + } - var maxBuild = 1; - if (hasPlusAccount) maxBuild++; - if (tribe == TribeEnums.Romans && !setting.IsIgnoreRomanAdvantage) maxBuild++; - if (totalBuild == maxBuild) - { - return Result.Fail("Amount of currently building is equal with maximum building can build in same time"); - } + // roman will have another method to select task + if (!romanAdvantage) return GetFirstTask(villageId); - if (tribe == TribeEnums.Romans && !setting.IsIgnoreRomanAdvantage && maxBuild - totalBuild == 1) - { - var numRes = currentList.Count(x => x.Type.IsResourceField()); - var numInfra = totalBuild - numRes; + // there is atleast 2 slot free + // roman can build both building or resource field + if (maxBuild - totalBuild >= 2) return GetFirstTask(villageId); - if (numRes > numInfra) - { - var freeCrop = context.VillagesResources.Find(villageId).FreeCrop; - if (freeCrop <= 5) - { - return Result.Fail("Cannot build because of lack of freecrop ( < 6 )"); - } - return GetFirstInfrastructureTask(villageId); - } - else if (numInfra > numRes) - { - // no need check free crop, there is magic make sure this always choose crop - // jk, because of how we check free crop later, first res task is always crop - return GetFirstResTask(villageId); - } - // if same means 1 R and 1 I already, 1 ANY will be choose below + var numRes = currentList.Count(x => x.Type.IsResourceField()); + var numBuilding = totalBuild - numRes; + + if (numRes > numBuilding) + { + var freeCrop = context.VillagesResources.Find(villageId).FreeCrop; + if (freeCrop < 6) + { + return Result.Fail(new Skip("Cannot build because of lack of freecrop ( < 6 )")); } + return GetFirstBuildingTask(villageId); + } + else if (numBuilding > numRes) + { + // no need check free crop, there is magic make sure this always choose crop + // jk, because of how we check free crop later, first res task is always crop + return GetFirstResTask(villageId); + } + // if same means 1 R and 1 I already, 1 ANY will be choose below + else + { + return GetFirstTask(villageId); } - - return GetFirstTask(villageId); } public PlanTask ExtractResField(int villageId, PlanTask buildingTask) @@ -136,17 +148,17 @@ public PlanTask ExtractResField(int villageId, PlanTask buildingTask) public void RemoveFinishedCB(int villageId) { using var context = _contextFactory.CreateDbContext(); - var tasksDone = context.VillagesCurrentlyBuildings.Where(x => x.VillageId == villageId).Where(x => x.CompleteTime <= DateTime.Now); + var tasksDone = context.VillagesCurrentlyBuildings.Where(x => x.VillageId == villageId && x.CompleteTime <= DateTime.Now); if (!tasksDone.Any()) return; foreach (var taskDone in tasksDone) { var building = context.VillagesBuildings.Find(villageId, taskDone.Location); - if (building == null) + if (building is null) { - building = context.VillagesBuildings.Where(x => x.VillageId == villageId).FirstOrDefault(x => x.Type == taskDone.Type); - if (building == null) continue; + building = context.VillagesBuildings.FirstOrDefault(x => x.VillageId == villageId && x.Type == taskDone.Type); + if (building is null) continue; } if (building.Level < taskDone.Level) building.Level = taskDone.Level; @@ -165,7 +177,7 @@ private PlanTask GetFirstResTask(int villageId) return task; } - private PlanTask GetFirstInfrastructureTask(int villageId) + private PlanTask GetFirstBuildingTask(int villageId) { var tasks = _planManager.GetList(villageId); var infrastructureTasks = tasks.Where(x => x.Type == PlanTypeEnums.General && !x.Building.IsResourceField()); @@ -192,7 +204,7 @@ private bool IsInfrastructureTaskVaild(int villageId, PlanTask planTask) var buildings = context.VillagesBuildings.Where(x => x.VillageId == villageId).ToList(); foreach (var prerequisiteBuilding in prerequisiteBuildings) { - var building = buildings.FirstOrDefault(x => x.Type == prerequisiteBuilding.Building); + var building = buildings.OrderByDescending(x => x.Level).FirstOrDefault(x => x.Type == prerequisiteBuilding.Building); if (building is null) return false; if (building.Level < prerequisiteBuilding.Level) return false; } diff --git a/MainCore/Migrations/202302101011_SleepWhenChangingProxy.cs b/MainCore/Migrations/202302101011_SleepWhenChangingProxy.cs new file mode 100644 index 000000000..3d6976be2 --- /dev/null +++ b/MainCore/Migrations/202302101011_SleepWhenChangingProxy.cs @@ -0,0 +1,19 @@ +using FluentMigrator; + +namespace MainCore.Migrations +{ + [Migration(202302101011)] + public class SleepWhenChangingProxy : Migration + { + public override void Down() + { + Execute.Sql("ALTER TABLE 'AccountsSettings' DROP COLUMN 'IsSleepBetweenProxyChanging';"); + } + + public override void Up() + { + Alter.Table("AccountsSettings") + .AddColumn("IsSleepBetweenProxyChanging").AsBoolean().WithDefaultValue(false); + } + } +} \ No newline at end of file diff --git a/MainCore/Models/Database/AccountSetting.cs b/MainCore/Models/Database/AccountSetting.cs index 54ff15c86..bbbd0b2a9 100644 --- a/MainCore/Models/Database/AccountSetting.cs +++ b/MainCore/Models/Database/AccountSetting.cs @@ -1,6 +1,4 @@ -using System.Text.Json.Serialization; - -namespace MainCore.Models.Database +namespace MainCore.Models.Database { public class AccountSetting { @@ -13,17 +11,12 @@ public class AccountSetting public int WorkTimeMax { get; set; } public int SleepTimeMin { get; set; } public int SleepTimeMax { get; set; } + public bool IsSleepBetweenProxyChanging { get; set; } public bool IsDontLoadImage { get; set; } public bool IsMinimized { get; set; } public bool IsClosedIfNoTask { get; set; } public bool IsAutoAdventure { get; set; } - - // these below will be on farming tab instead of settings tab - - [JsonIgnore] public int FarmIntervalMin { get; set; } - - [JsonIgnore] public int FarmIntervalMax { get; set; } } } \ No newline at end of file diff --git a/MainCore/Services/Implementations/ChromeBrowser.cs b/MainCore/Services/Implementations/ChromeBrowser.cs index c219d987f..295f04d84 100644 --- a/MainCore/Services/Implementations/ChromeBrowser.cs +++ b/MainCore/Services/Implementations/ChromeBrowser.cs @@ -19,8 +19,13 @@ public sealed class ChromeBrowser : IChromeBrowser private readonly string[] _extensionsPath; private readonly HtmlDocument _htmlDoc = new(); - public ChromeBrowser(string[] extensionsPath) + private readonly string _pathUserData; + + public ChromeBrowser(string[] extensionsPath, string server, string username) { + _pathUserData = Path.Combine(AppContext.BaseDirectory, "Data", "Cache", server.Replace("https://", "").Replace(".", "_"), username); + Directory.CreateDirectory(_pathUserData); + _extensionsPath = extensionsPath; _chromeService = ChromeDriverService.CreateDefaultService(); @@ -58,9 +63,7 @@ public void Setup(Access access, AccountSetting setting) options.AddArgument("--mute-audio"); if (setting.IsDontLoadImage) options.AddArguments("--blink-settings=imagesEnabled=false"); //--disable-images - var path = Path.Combine(AppContext.BaseDirectory, "Data", "Cache", access.ProxyHost ?? "default"); - Directory.CreateDirectory(path); - options.AddArguments($"user-data-dir={path}"); + options.AddArguments($"user-data-dir={_pathUserData}"); _driver = new ChromeDriver(_chromeService, options); if (setting.IsMinimized) _driver.Manage().Window.Minimize(); diff --git a/MainCore/Services/Implementations/ChromeManager.cs b/MainCore/Services/Implementations/ChromeManager.cs index c82776f7a..16ddc775f 100644 --- a/MainCore/Services/Implementations/ChromeManager.cs +++ b/MainCore/Services/Implementations/ChromeManager.cs @@ -1,8 +1,10 @@ using MainCore.Services.Interface; +using Microsoft.EntityFrameworkCore; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; namespace MainCore.Services.Implementations @@ -11,13 +13,22 @@ public sealed class ChromeManager : IChromeManager { private readonly ConcurrentDictionary _dictionary = new(); private string[] _extensionsPath; + private readonly IDbContextFactory _contextFactory; + + public ChromeManager(IDbContextFactory contextFactory) + { + _contextFactory = contextFactory; + } public IChromeBrowser Get(int id) { var result = _dictionary.TryGetValue(id, out ChromeBrowser browser); if (result) return browser; - browser = new ChromeBrowser(_extensionsPath); + using var context = _contextFactory.CreateDbContext(); + var account = context.Accounts.FirstOrDefault(x => x.Id == id); + + browser = new ChromeBrowser(_extensionsPath, account.Server, account.Username); _dictionary.TryAdd(id, browser); return browser; } diff --git a/MainCore/Services/Implementations/PlanManager.cs b/MainCore/Services/Implementations/PlanManager.cs index bdfc919f2..f6296ab4d 100644 --- a/MainCore/Services/Implementations/PlanManager.cs +++ b/MainCore/Services/Implementations/PlanManager.cs @@ -1,5 +1,4 @@ -using MainCore.Helper; -using MainCore.Models.Runtime; +using MainCore.Models.Runtime; using MainCore.Services.Interface; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; @@ -15,108 +14,106 @@ public PlanManager(IDbContextFactory contextFactory) _contextFactory = contextFactory; } - public void Add(int villageId, PlanTask task) + private PlanTask FixTask(int villageId, PlanTask task) { - Check(villageId); - lock (_objLocks[villageId]) + if (task.Type != Enums.PlanTypeEnums.General) return task; + + using var context = _contextFactory.CreateDbContext(); + // check wall + if (task.Building.IsWall()) { - if (task.Type == Enums.PlanTypeEnums.General) + var village = context.Villages.Find(villageId); + var tribe = context.AccountsInfo.Find(village.AccountId).Tribe; + var wall = tribe.GetWall(); + if (task.Building != wall) task.Building = wall; + return task; + } + + // check building can build muiltiple times (warehouse, ganary, ...) + if (task.Building.IsMultipleAllow()) + { + var villageBuildings = context.VillagesBuildings.Where(x => x.VillageId == villageId).ToList(); + var building = villageBuildings.Where(x => x.Type == task.Building).OrderByDescending(x => x.Level).FirstOrDefault(); + if (building is not null) + { + if (task.Location != building.Id && building.Level != building.Type.GetMaxLevel()) + { + task.Location = building.Id; + } + return task; + } + + var currentBuildings = context.VillagesCurrentlyBuildings.Where(x => x.VillageId == villageId).ToList(); + var currentBuilding = currentBuildings.Where(x => x.Type == task.Building).OrderByDescending(x => x.Level).FirstOrDefault(); + if (currentBuilding is not null) { - using var context = _contextFactory.CreateDbContext(); - // check wall - if (task.Building.IsWall()) + if (task.Location != currentBuilding.Location && currentBuilding.Level != currentBuilding.Type.GetMaxLevel()) { - var village = context.Villages.Find(villageId); - var tribe = context.AccountsInfo.Find(village.AccountId).Tribe; - var wall = tribe.GetWall(); - if (task.Building != wall) task.Building = wall; + task.Location = currentBuilding.Location; } + return task; + } + + var planTasks = GetList(villageId); + var planTask = planTasks.Where(x => x.Building == task.Building).OrderByDescending(x => x.Level).FirstOrDefault(); + if (planTask is null) return task; + + if (task.Location != planTask.Location && planTask.Level != planTask.Building.GetMaxLevel()) + { + task.Location = planTask.Location; + } + return task; + } - // check building can build muiltiple times (warehouse, ganary, ...) - if (task.Building.IsMultipleAllow()) + if (task.Building.IsResourceField()) + { + var villageBuilding = context.VillagesBuildings.FirstOrDefault(x => x.VillageId == villageId && x.Id == task.Location); + // different type village ( 4446 import to 3337 for example ) + // now i just ignore the different resource field + if (villageBuilding is null || villageBuilding.Type != task.Building) return null; + return task; + } + { + var villageBuildings = context.VillagesBuildings.Where(x => x.VillageId == villageId).ToList(); + var building = villageBuildings.FirstOrDefault(x => x.Type == task.Building); + if (building is not null) + { + if (task.Location != building.Id) { - var villageBuildings = context.VillagesBuildings.Where(x => x.VillageId == villageId).ToList(); - var building = villageBuildings.Where(x => x.Type == task.Building).OrderByDescending(x => x.Level).FirstOrDefault(); - if (building is null) - { - var currentBuildings = context.VillagesCurrentlyBuildings.Where(x => x.VillageId == villageId).ToList(); - var currentBuilding = currentBuildings.Where(x => x.Type == task.Building).OrderByDescending(x => x.Level).FirstOrDefault(); - if (currentBuilding is null) - { - var planTasks = GetList(villageId); - var planTask = planTasks.Where(x => x.Building == task.Building).OrderByDescending(x => x.Level).FirstOrDefault(); - if (planTask is not null) - { - if (task.Location != planTask.Location && planTask.Level != planTask.Building.GetMaxLevel()) - { - task.Location = planTask.Location; - } - } - } - else - { - if (task.Location != currentBuilding.Location && currentBuilding.Level != currentBuilding.Type.GetMaxLevel()) - { - task.Location = currentBuilding.Location; - } - } - } - else - { - if (task.Location != building.Id && building.Level != building.Type.GetMaxLevel()) - { - task.Location = building.Id; - } - } + task.Location = building.Id; } - else + return task; + } + + var currentBuildings = context.VillagesCurrentlyBuildings.Where(x => x.VillageId == villageId).ToList(); + var currentBuilding = currentBuildings.FirstOrDefault(x => x.Type == task.Building); + if (currentBuilding is not null) + { + if (task.Location != currentBuilding.Location) { - if (task.Building.IsResourceField()) - { - var villageBuilding = context.VillagesBuildings.Where(x => x.VillageId == villageId).FirstOrDefault(x => x.Id == task.Location); - // different type village ( 4446 import to 3337 for example ) - // now i just ignore the different resource field - if (villageBuilding is null || villageBuilding.Type != task.Building) return; - } - else - { - var villageBuildings = context.VillagesBuildings.Where(x => x.VillageId == villageId).ToList(); - var building = villageBuildings.FirstOrDefault(x => x.Type == task.Building); - if (building is null) - { - var currentBuildings = context.VillagesCurrentlyBuildings.Where(x => x.VillageId == villageId).ToList(); - var currentBuilding = currentBuildings.FirstOrDefault(x => x.Type == task.Building); - if (currentBuilding is null) - { - var planTasks = GetList(villageId); - var planTask = planTasks.FirstOrDefault(x => x.Building == task.Building); - if (planTask is not null) - { - if (task.Location != planTask.Location) - { - task.Location = planTask.Location; - } - } - } - else - { - if (task.Location != currentBuilding.Location) - { - task.Location = currentBuilding.Location; - } - } - } - else - { - if (task.Location != building.Id) - { - task.Location = building.Id; - } - } - } + task.Location = currentBuilding.Location; } + return task; + } + + var planTasks = GetList(villageId); + var planTask = planTasks.FirstOrDefault(x => x.Building == task.Building); + if (planTask is null) return task; + if (task.Location != planTask.Location) + { + task.Location = planTask.Location; } + } + return task; + } + public void Add(int villageId, PlanTask task) + { + Check(villageId); + task = FixTask(villageId, task); + if (task is null) return; + lock (_objLocks[villageId]) + { _tasksDict[villageId].Add(task); } } diff --git a/MainCore/Tasks/Misc/NPCTask.cs b/MainCore/Tasks/Misc/NPCTask.cs index 604067706..f8e2a1914 100644 --- a/MainCore/Tasks/Misc/NPCTask.cs +++ b/MainCore/Tasks/Misc/NPCTask.cs @@ -95,7 +95,7 @@ private Result ToMarketPlace() setting.IsAutoNPC = false; context.Update(setting); context.SaveChanges(); - return Result.Fail(new Skip()); + return Result.Fail(new Skip("Marketplace is missing")); } { diff --git a/MainCore/Tasks/Misc/SleepTask.cs b/MainCore/Tasks/Misc/SleepTask.cs index d7694f896..75736202e 100644 --- a/MainCore/Tasks/Misc/SleepTask.cs +++ b/MainCore/Tasks/Misc/SleepTask.cs @@ -1,5 +1,4 @@ using FluentResults; -using MainCore.Errors; using MainCore.Helper.Interface; using MainCore.Models.Database; using MainCore.Services.Interface; @@ -16,6 +15,8 @@ public class SleepTask : AccountBotTask private readonly IRestClientManager _restClientManager; + private DateTime _sleepEnd; + public SleepTask(int accountId, CancellationToken cancellationToken = default) : base(accountId, cancellationToken) { _accessHelper = Locator.Current.GetService(); @@ -24,84 +25,133 @@ public SleepTask(int accountId, CancellationToken cancellationToken = default) : } public override Result Execute() + { + _logManager.Information(AccountId, "Choosing next proxy ..."); + var access = ChooseNextAccess(); + if (access is null || IsForceSleep()) + { + var sleepTime = GetSleepTime(); + _sleepEnd = DateTime.Now.Add(sleepTime); + _logManager.Information(AccountId, $"No proxy vaild or force sleep is acitve. Bot will sleep {(int)sleepTime.TotalMinutes} mins"); + } + else + { + var sleepTime = TimeSpan.FromSeconds(Random.Shared.Next(14 * 60, 16 * 60)); + _sleepEnd = DateTime.Now.Add(sleepTime); + var proxyHost = string.IsNullOrEmpty(access.ProxyHost) ? "default" : access.ProxyHost; + _logManager.Information(AccountId, $"There is vaild proxy ({proxyHost}). Bot will sleep {(int)sleepTime.TotalMinutes} mins before switching to vaild proxy"); + } + + Sleep(); + var status = _taskManager.GetAccountStatus(AccountId); + if (status != Enums.AccountStatus.Stopping && status != Enums.AccountStatus.Pausing) + { + WakeUp(access); + } + ExecuteAt = DateTime.Now.Add(GetWorkTime()); + return Result.Ok(); + } + + private Access ChooseNextAccess() { var context = _contextFactory.CreateDbContext(); - var accesses = context.Accesses.Where(x => x.AccountId == AccountId).OrderBy(x => x.LastUsed); + var accesses = context.Accesses.Where(x => x.AccountId == AccountId).OrderBy(x => x.LastUsed).ToList(); var currentAccess = accesses.Last(); + accesses.Remove(currentAccess); var setting = context.AccountsSettings.Find(AccountId); - Access selectedAccess = null; foreach (var access in accesses) { if (string.IsNullOrEmpty(access.ProxyHost)) { - selectedAccess = access; - break; + return access; } var result = _accessHelper.IsValid(_restClientManager.Get(new(access))); if (result) { - selectedAccess = access; access.LastUsed = DateTime.Now; context.SaveChanges(); - break; + return access; } else { _logManager.Information(AccountId, $"Proxy {access.ProxyHost} is not working"); } } - if (selectedAccess is null || selectedAccess.Id == currentAccess.Id) + + return null; + } + + private bool IsForceSleep() + { + using var context = _contextFactory.CreateDbContext(); + var setting = context.AccountsSettings.Find(AccountId); + return setting.IsSleepBetweenProxyChanging; + } + + private TimeSpan GetSleepTime() + { + using var context = _contextFactory.CreateDbContext(); + var setting = context.AccountsSettings.Find(AccountId); + (var min, var max) = (setting.SleepTimeMin, setting.SleepTimeMax); + + var time = TimeSpan.FromSeconds(Random.Shared.Next(min * 60, max * 60)); + + return time; + } + + private TimeSpan GetWorkTime() + { + using var context = _contextFactory.CreateDbContext(); + var setting = context.AccountsSettings.Find(AccountId); + (var min, var max) = (setting.WorkTimeMin, setting.WorkTimeMax); + + var time = TimeSpan.FromSeconds(Random.Shared.Next(min * 60, max * 60)); + + return time; + } + + private void Sleep() + { + _chromeBrowser.Close(); + int lastMinute = 0; + + while (true) { - (var min, var max) = (setting.SleepTimeMin, setting.SleepTimeMax); + if (CancellationToken.IsCancellationRequested) + { + _logManager.Information(AccountId, "Cancellation requested"); + return; + } + var timeRemaining = _sleepEnd - DateTime.Now; + if (timeRemaining < TimeSpan.Zero) return; + + Thread.Sleep(TimeSpan.FromSeconds(1)); + var currentMinute = (int)timeRemaining.TotalMinutes; - var time = TimeSpan.FromMinutes(Random.Shared.Next(min, max)); - _chromeBrowser.Close(); - _logManager.Information(AccountId, $"Bot is sleeping in {time.TotalMinutes} minute(s)"); - while (time > TimeSpan.Zero) + if (lastMinute != currentMinute) { - if (CancellationToken.IsCancellationRequested) - { - return Result.Fail(new Cancel()); - } - Thread.Sleep(TimeSpan.FromSeconds(1)); - time -= TimeSpan.FromSeconds(1); - - if (time.Seconds == 0) - { - _logManager.Information(AccountId, $"Bot is sleeping in {time.TotalMinutes} minute(s)"); - } + _logManager.Information(AccountId, $"Chrome will reopen in {currentMinute} mins"); + lastMinute = currentMinute; } } - else + } + + private void WakeUp(Access access) + { + using var context = _contextFactory.CreateDbContext(); + // just use current access + if (access is null) { - _chromeBrowser.Close(); - _logManager.Information(AccountId, $"Bot is sleeping in {3} minute(s)"); - var time = TimeSpan.FromMinutes(3); - while (time > TimeSpan.Zero) - { - if (CancellationToken.IsCancellationRequested) - { - return Result.Fail(new Cancel()); - } - Thread.Sleep(TimeSpan.FromSeconds(1)); - time -= TimeSpan.FromSeconds(1); - - if (time.Seconds == 0) - { - _logManager.Information(AccountId, $"Bot is sleeping in {time.TotalMinutes} minute(s)"); - } - } + var accesses = context.Accesses.Where(x => x.AccountId == AccountId).OrderBy(x => x.LastUsed).ToList(); + access = accesses.Last(); } - _chromeBrowser.Setup(selectedAccess, setting); + var setting = context.AccountsSettings.Find(AccountId); + _chromeBrowser.Setup(access, setting); var currentAccount = context.Accounts.Find(AccountId); _chromeBrowser.Navigate(currentAccount.Server); - _taskManager.Add(AccountId, new LoginTask(AccountId), true); - - var nextExecute = Random.Shared.Next(setting.SleepTimeMin, setting.SleepTimeMax); - ExecuteAt = DateTime.Now.AddMinutes(nextExecute); - return Result.Ok(); + _taskManager.Add(AccountId, new LoginTask(AccountId), first: true); } } } \ No newline at end of file diff --git a/MainCore/Tasks/Sim/UpgradeBuilding.cs b/MainCore/Tasks/Sim/UpgradeBuilding.cs index cf42b79da..3291dca18 100644 --- a/MainCore/Tasks/Sim/UpgradeBuilding.cs +++ b/MainCore/Tasks/Sim/UpgradeBuilding.cs @@ -7,6 +7,7 @@ using MainCore.Tasks.Misc; using MainCore.Tasks.Update; using Splat; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -254,7 +255,7 @@ private Result SelectBuilding() var tasks = _planManager.GetList(VillageId); if (tasks.Count == 0) { - return Result.Fail(new Skip()); + return Result.Fail(new Skip(buildingTask.Reasons[0].Message)); } if (!_chromeBrowser.GetCurrentUrl().Contains("dorf")) { @@ -279,7 +280,13 @@ private Result SelectBuilding() _logManager.Information(AccountId, $"Next building will be contructed after {firstComplete.Type} - level {firstComplete.Level} complete. ({ExecuteAt})"); } } - return Result.Fail(new Skip()); + return Result.Fail(new Skip(buildingTask.Reasons[0].Message)); + } + if (buildingTask.Value is null) + { + ExecuteAt = DateTime.Now.AddSeconds(15); + _logManager.Information(AccountId, "There is somthing wrong, bot cannot decide what to build. Let wait bot in 15 secs"); + return Result.Fail(new Retry("Cannot chose building to build")); } if (buildingTask.Value.Type == PlanTypeEnums.General) diff --git a/WPFUI/Models/AccountSetting.cs b/WPFUI/Models/AccountSetting.cs index 0c51628dd..85f09cb7f 100644 --- a/WPFUI/Models/AccountSetting.cs +++ b/WPFUI/Models/AccountSetting.cs @@ -18,6 +18,7 @@ public void CopyFrom(MainCore.Models.Database.AccountSetting settings) IsClosedIfNoTask = settings.IsClosedIfNoTask; IsMinimized = settings.IsMinimized; IsAutoStartAdventure = settings.IsAutoAdventure; + IsSleepBetweenProxyChanging = settings.IsSleepBetweenProxyChanging; } public void CopyTo(MainCore.Models.Database.AccountSetting settings) @@ -42,6 +43,7 @@ public void CopyTo(MainCore.Models.Database.AccountSetting settings) settings.IsClosedIfNoTask = IsClosedIfNoTask; settings.IsMinimized = IsMinimized; settings.IsAutoAdventure = IsAutoStartAdventure; + settings.IsSleepBetweenProxyChanging = IsSleepBetweenProxyChanging; } private int _clickDelay; @@ -139,5 +141,13 @@ public bool IsAutoStartAdventure get => _isAutoStartAdventure; set => this.RaiseAndSetIfChanged(ref _isAutoStartAdventure, value); } + + private bool _isSleepBetweenProxyChanging; + + public bool IsSleepBetweenProxyChanging + { + get => _isSleepBetweenProxyChanging; + set => this.RaiseAndSetIfChanged(ref _isSleepBetweenProxyChanging, value); + } } } \ No newline at end of file diff --git a/WPFUI/ViewModels/Uc/MainView/MainButtonPanelViewModel.cs b/WPFUI/ViewModels/Uc/MainView/MainButtonPanelViewModel.cs index 788768417..6d78d987d 100644 --- a/WPFUI/ViewModels/Uc/MainView/MainButtonPanelViewModel.cs +++ b/WPFUI/ViewModels/Uc/MainView/MainButtonPanelViewModel.cs @@ -235,6 +235,12 @@ private void DeleteAccount(int index) private async Task Pause(int index) { + var taskList = _taskManager.GetList(index); + var sleep = taskList.OfType().FirstOrDefault(); + + sleep.ExecuteAt = DateTime.Now; + return; + var status = _taskManager.GetAccountStatus(index); if (status == AccountStatus.Paused) { diff --git a/WPFUI/ViewModels/WaitingViewModel.cs b/WPFUI/ViewModels/WaitingViewModel.cs index 9988006fa..138f4cb52 100644 --- a/WPFUI/ViewModels/WaitingViewModel.cs +++ b/WPFUI/ViewModels/WaitingViewModel.cs @@ -12,8 +12,11 @@ public class WaitingViewModel : ReactiveObject public void Show(string message) { - Text = message; - RxApp.MainThreadScheduler.Schedule(ShowWindow); + RxApp.MainThreadScheduler.Schedule(() => + { + Text = message; + ShowWindow(); + }); } public void Close() diff --git a/WPFUI/Views/Tabs/SettingsPage.xaml b/WPFUI/Views/Tabs/SettingsPage.xaml index c01dac7ac..0c47a8993 100644 --- a/WPFUI/Views/Tabs/SettingsPage.xaml +++ b/WPFUI/Views/Tabs/SettingsPage.xaml @@ -36,9 +36,10 @@ + - + diff --git a/WPFUI/Views/Tabs/SettingsPage.xaml.cs b/WPFUI/Views/Tabs/SettingsPage.xaml.cs index e4a694d99..02ae08f04 100644 --- a/WPFUI/Views/Tabs/SettingsPage.xaml.cs +++ b/WPFUI/Views/Tabs/SettingsPage.xaml.cs @@ -35,9 +35,9 @@ public SettingsPage() this.Bind(ViewModel, vm => vm.Settings.SleepTime, v => v.SleepTime.ViewModel.MainValue).DisposeWith(d); this.Bind(ViewModel, vm => vm.Settings.SleepTimeRange, v => v.SleepTime.ViewModel.ToleranceValue).DisposeWith(d); + this.Bind(ViewModel, vm => vm.Settings.IsSleepBetweenProxyChanging, v => v.SleepBetweenChangingProxy.IsChecked).DisposeWith(d); this.Bind(ViewModel, vm => vm.Settings.IsDontLoadImage, v => v.DisableImageCheckBox.IsChecked).DisposeWith(d); this.Bind(ViewModel, vm => vm.Settings.IsMinimized, v => v.MinimizedCheckBox.IsChecked).DisposeWith(d); - this.Bind(ViewModel, vm => vm.Settings.IsClosedIfNoTask, v => v.CloseCheckBox.IsChecked).DisposeWith(d); this.Bind(ViewModel, vm => vm.Settings.IsAutoStartAdventure, v => v.AutoStartAdventureCheckBox.IsChecked).DisposeWith(d); });