diff --git a/MainCore/Commands/Features/UpgradeBuilding/GetBuildPlanCommand.cs b/MainCore/Commands/Features/UpgradeBuilding/GetBuildPlanCommand.cs index af919a9b..74c9b9b3 100644 --- a/MainCore/Commands/Features/UpgradeBuilding/GetBuildPlanCommand.cs +++ b/MainCore/Commands/Features/UpgradeBuilding/GetBuildPlanCommand.cs @@ -15,7 +15,7 @@ private static async ValueTask> HandleAsync( GetLayoutBuildingsCommand.Handler getLayoutBuildingsQuery, DeleteJobByIdCommand.Handler deleteJobByIdCommand, AddJobCommand.Handler addJobCommand, - ValidateJobCompleteCommand.Handler validateJobCompleteCommand, + ValidatePlanCompleteCommand.Handler validatePlanCompleteCommand, ILogger logger, IRxQueue rxQueue, CancellationToken cancellationToken @@ -27,12 +27,6 @@ CancellationToken cancellationToken { if (cancellationToken.IsCancellationRequested) return Cancel.Error; - var result = await toDorfCommand.HandleAsync(new(2), cancellationToken); - if (result.IsFailed) return result; - - result = await updateBuildingCommand.HandleAsync(new(villageId), cancellationToken); - if (result.IsFailed) return result; - var (_, isFailed, job, errors) = await getJobQuery.HandleAsync(new(accountId, villageId), cancellationToken); if (isFailed) return Result.Fail(errors); @@ -56,15 +50,34 @@ CancellationToken cancellationToken } var plan = JsonSerializer.Deserialize(job.Content)!; + Result result; + if (plan.Type.IsResourceBonus()) + { + result = await toDorfCommand.HandleAsync(new(1), cancellationToken); + if (result.IsFailed) return result; + + result = await updateBuildingCommand.HandleAsync(new(villageId), cancellationToken); + if (result.IsFailed) return result; - var dorf = plan.Location < 19 ? 1 : 2; - result = await toDorfCommand.HandleAsync(new(dorf), cancellationToken); - if (result.IsFailed) return result; + result = await toDorfCommand.HandleAsync(new(2), cancellationToken); + if (result.IsFailed) return result; - result = await updateBuildingCommand.HandleAsync(new(villageId), cancellationToken); - if (result.IsFailed) return result; + result = await updateBuildingCommand.HandleAsync(new(villageId), cancellationToken); + if (result.IsFailed) return result; + } + else + { + var dorf = plan.Location < 19 ? 1 : 2; + result = await toDorfCommand.HandleAsync(new(dorf), cancellationToken); + if (result.IsFailed) return result; + + result = await updateBuildingCommand.HandleAsync(new(villageId), cancellationToken); + if (result.IsFailed) return result; + } - if (await validateJobCompleteCommand.HandleAsync(new ValidateJobCompleteCommand.Command(villageId, job), cancellationToken)) + var validateResult = await validatePlanCompleteCommand.HandleAsync(new(villageId, plan), cancellationToken); + if (validateResult.IsFailed) return Result.Fail(validateResult.Errors); + if (!validateResult.Value) { await deleteJobByIdCommand.HandleAsync(new(job.Id), cancellationToken); rxQueue.Enqueue(new JobsModified(villageId)); diff --git a/MainCore/Commands/Features/UpgradeBuilding/GetJobCommand.cs b/MainCore/Commands/Features/UpgradeBuilding/GetJobCommand.cs index b6d8093c..5d35dd41 100644 --- a/MainCore/Commands/Features/UpgradeBuilding/GetJobCommand.cs +++ b/MainCore/Commands/Features/UpgradeBuilding/GetJobCommand.cs @@ -23,10 +23,7 @@ AppDbContext context if (queueBuildings.Count == 0) { - var job = buildJobs[0]; - var result = IsJobValid(job, buildings, queueBuildings); - if (result.IsFailed) return result; - return job; + return buildJobs[0]; } var plusActive = context.AccountsInfo @@ -40,18 +37,13 @@ AppDbContext context { if (plusActive) { - var job = buildJobs[0]; - var result = IsJobValid(job, buildings, queueBuildings); - if (result.IsFailed) return result; - return job; + return buildJobs[0]; } if (applyRomanQueueLogic) { var (_, isFailed, job, errors) = GetJobBasedOnRomanLogic(queueBuildings, buildJobs); if (isFailed) return Result.Fail(errors); - var result = IsJobValid(job, buildings, queueBuildings); - if (result.IsFailed) return result; return job; } return NextExecuteError.ConstructionQueueFull(queueBuildings[0].CompleteTime); @@ -63,8 +55,6 @@ AppDbContext context { var (_, isFailed, job, errors) = GetJobBasedOnRomanLogic(queueBuildings, buildJobs); if (isFailed) return Result.Fail(errors); - var result = IsJobValid(job, buildings, queueBuildings); - if (result.IsFailed) return result; return job; } return NextExecuteError.ConstructionQueueFull(queueBuildings[0].CompleteTime); @@ -198,57 +188,5 @@ private static int CountResourceQueueBuilding(List queueBuildings if (job.Position < resourceBuildJob.Position) return job; return resourceBuildJob; } - - private static Result IsJobValid(JobDto job, List buildings, List queueBuildings) - { - if (job.Type == JobTypeEnums.ResourceBuild) return Result.Ok(); - - var plan = JsonSerializer.Deserialize(job.Content)!; - if (plan.Type.IsResourceField()) return Result.Ok(); - - var oldBuilding = buildings - .FirstOrDefault(x => x.Location == plan.Location); - - if (oldBuilding is not null && oldBuilding.Type == plan.Type) return Result.Ok(); - - var errors = new List(); - var prerequisiteBuildings = plan.Type.GetPrerequisiteBuildings(); - - foreach (var prerequisiteBuilding in prerequisiteBuildings) - { - var vaild = buildings - .Any(x => x.Type == prerequisiteBuilding.Type && x.Level >= prerequisiteBuilding.Level); - - if (!vaild) - { - errors.Add(UpgradeBuildingError.PrerequisiteBuildingMissing(prerequisiteBuilding.Type, prerequisiteBuilding.Level)); - var queueBuilding = queueBuildings.Find(x => x.Type == prerequisiteBuilding.Type && x.Level == prerequisiteBuilding.Level); - if (queueBuilding is not null) - { - errors.Add(NextExecuteError.PrerequisiteBuildingInQueue(prerequisiteBuilding.Type, prerequisiteBuilding.Level, queueBuilding.CompleteTime)); - } - } - } - - if (!plan.Type.IsMultipleBuilding()) return errors.Count == 0 ? Result.Ok() : Result.Fail(errors); - - var firstBuilding = buildings - .Where(x => x.Type == plan.Type) - .OrderByDescending(x => x.Level) - .FirstOrDefault(); - - if (firstBuilding is null) return errors.Count == 0 ? Result.Ok() : Result.Fail(errors); - if (firstBuilding.Location == plan.Location) return errors.Count == 0 ? Result.Ok() : Result.Fail(errors); - if (firstBuilding.Level == firstBuilding.Type.GetMaxLevel()) return errors.Count == 0 ? Result.Ok() : Result.Fail(errors); - - errors.Add(UpgradeBuildingError.PrerequisiteBuildingMissing(firstBuilding.Type, firstBuilding.Level)); - var prerequisiteBuildingUndercontruction = queueBuildings.Find(x => x.Type == firstBuilding.Type && x.Level == firstBuilding.Level); - if (prerequisiteBuildingUndercontruction is not null) - { - errors.Add(NextExecuteError.PrerequisiteBuildingInQueue(firstBuilding.Type, firstBuilding.Level, prerequisiteBuildingUndercontruction.CompleteTime)); - } - - return Result.Fail(errors); - } } } \ No newline at end of file diff --git a/MainCore/Commands/Features/UpgradeBuilding/ValidateJobCompleteCommand.cs b/MainCore/Commands/Features/UpgradeBuilding/ValidateJobCompleteCommand.cs index dbbac359..c807ad17 100644 --- a/MainCore/Commands/Features/UpgradeBuilding/ValidateJobCompleteCommand.cs +++ b/MainCore/Commands/Features/UpgradeBuilding/ValidateJobCompleteCommand.cs @@ -1,41 +1,116 @@ -using System.Text.Json; - -namespace MainCore.Commands.Features.UpgradeBuilding +namespace MainCore.Commands.Features.UpgradeBuilding { [Handler] - public static partial class ValidateJobCompleteCommand + public static partial class ValidatePlanCompleteCommand { - public sealed record Command(VillageId VillageId, JobDto job) : IVillageCommand; + public sealed record Command(VillageId VillageId, NormalBuildPlan Plan) : IVillageCommand; - private static async ValueTask HandleAsync( + private static async ValueTask> HandleAsync( Command command, AppDbContext context, CancellationToken cancellationToken ) { await Task.CompletedTask; - var (villageId, job) = command; - if (job.Type == JobTypeEnums.ResourceBuild) return false; + var (villageId, plan) = command; - var plan = JsonSerializer.Deserialize(job.Content)!; + var (buildings, queueBuildings) = context.GetBuildings(villageId); - var queueBuilding = context.QueueBuildings - .Where(x => x.VillageId == villageId.Value) + var oldBuilding = buildings + .FirstOrDefault(x => x.Location == plan.Location); + + if (oldBuilding is not null && oldBuilding.Type == plan.Type) + { + if (oldBuilding.Level >= plan.Level) return false; + + var queueBuilding = queueBuildings .Where(x => x.Location == plan.Location) .OrderByDescending(x => x.Level) .Select(x => x.Level) .FirstOrDefault(); - if (queueBuilding >= plan.Level) return true; + if (queueBuilding >= plan.Level) return false; + return true; + } - var villageBuilding = context.Buildings - .Where(x => x.VillageId == villageId.Value) - .Where(x => x.Location == plan.Location) - .Select(x => x.Level) + var errors = new List(); + var prerequisiteBuildings = plan.Type.GetPrerequisiteBuildings(); + + foreach (var prerequisiteBuilding in prerequisiteBuildings) + { + var vaild = buildings + .Any(x => x.Type == prerequisiteBuilding.Type && x.Level >= prerequisiteBuilding.Level); + + if (!vaild) + { + errors.Add(UpgradeBuildingError.PrerequisiteBuildingMissing(prerequisiteBuilding.Type, prerequisiteBuilding.Level)); + var queueBuilding = queueBuildings.Find(x => x.Type == prerequisiteBuilding.Type && x.Level == prerequisiteBuilding.Level); + if (queueBuilding is not null) + { + errors.Add(NextExecuteError.PrerequisiteBuildingInQueue(prerequisiteBuilding.Type, prerequisiteBuilding.Level, queueBuilding.CompleteTime)); + } + } + } + + if (!plan.Type.IsMultipleBuilding()) return errors.Count == 0 ? true : Result.Fail(errors); + + var firstBuilding = buildings + .Where(x => x.Type == plan.Type) + .OrderByDescending(x => x.Level) .FirstOrDefault(); - if (villageBuilding >= plan.Level) return true; - return false; + if (firstBuilding is null) return errors.Count == 0 ? true : Result.Fail(errors); + if (firstBuilding.Location == plan.Location) return errors.Count == 0 ? true : Result.Fail(errors); + if (firstBuilding.Level == firstBuilding.Type.GetMaxLevel()) return errors.Count == 0 ? true : Result.Fail(errors); + + errors.Add(UpgradeBuildingError.PrerequisiteBuildingMissing(firstBuilding.Type, firstBuilding.Level)); + var prerequisiteBuildingUndercontruction = queueBuildings.Find(x => x.Type == firstBuilding.Type && x.Level == firstBuilding.Level); + if (prerequisiteBuildingUndercontruction is not null) + { + errors.Add(NextExecuteError.PrerequisiteBuildingInQueue(firstBuilding.Type, firstBuilding.Level, prerequisiteBuildingUndercontruction.CompleteTime)); + } + + return Result.Fail(errors); + } + + private static (List, List) GetBuildings(this AppDbContext context, VillageId villageId) + { + var completeQueueBuildings = context.QueueBuildings + .Where(x => x.VillageId == villageId.Value) + .Where(x => x.CompleteTime < DateTime.Now) + .OrderBy(x => x.Level) + .ToList(); + + if (completeQueueBuildings.Count > 0) + { + foreach (var completeQueueBuilding in completeQueueBuildings) + { + if (completeQueueBuilding.Location == -1) continue; + + var building = context.Buildings + .Where(x => x.VillageId == villageId.Value) + .Where(x => x.Location == completeQueueBuilding.Location) + .FirstOrDefault(); + if (building is null) continue; + + building.Level = completeQueueBuilding.Level; + context.Remove(completeQueueBuilding); + } + context.SaveChanges(); + } + + var buildings = context.Buildings + .AsNoTracking() + .Where(x => x.VillageId == villageId.Value) + .ToList(); + + var queueBuildings = context.QueueBuildings + .AsNoTracking() + .Where(x => x.VillageId == villageId.Value) + .OrderBy(x => x.CompleteTime) + .ToList(); + + return (buildings, queueBuildings); } } } \ No newline at end of file diff --git a/MainCore/Commands/Features/UseHeroItem/ToHeroInventoryCommand.cs b/MainCore/Commands/Features/UseHeroItem/ToHeroInventoryCommand.cs index 3403c7ac..ac20c158 100644 --- a/MainCore/Commands/Features/UseHeroItem/ToHeroInventoryCommand.cs +++ b/MainCore/Commands/Features/UseHeroItem/ToHeroInventoryCommand.cs @@ -10,6 +10,7 @@ public sealed record Command : ICommand; private static async ValueTask HandleAsync( Command command, IChromeBrowser browser, + IDelayService delayService, CancellationToken cancellationToken) { var (_, isFailed, element, errors) = await browser.GetElement(doc => InventoryParser.GetHeroAvatar(doc), cancellationToken); @@ -22,12 +23,14 @@ static bool TabActived(IWebDriver driver) { var doc = new HtmlDocument(); doc.LoadHtml(driver.PageSource); - return InventoryParser.IsInventoryPage(doc); + return InventoryParser.IsInventoryPage(doc) && InventoryParser.IsInventoryLoaded(doc); } result = await browser.Wait(TabActived, cancellationToken); if (result.IsFailed) return result; + await delayService.DelayTask(cancellationToken); + return Result.Ok(); } } diff --git a/MainCore/Commands/Features/UseHeroItem/UseHeroResourceCommand.cs b/MainCore/Commands/Features/UseHeroItem/UseHeroResourceCommand.cs index cfcbc7a2..47e86f34 100644 --- a/MainCore/Commands/Features/UseHeroItem/UseHeroResourceCommand.cs +++ b/MainCore/Commands/Features/UseHeroItem/UseHeroResourceCommand.cs @@ -11,6 +11,7 @@ private static async ValueTask HandleAsync( UpdateInventoryCommand.Handler updateInventoryCommand, ValidateEnoughResourceCommand.Handler validateEnoughResourceCommand, UseHeroItemCommand.Handler useHeroItemCommand, + IDelayService delayService, CancellationToken cancellationToken) { var (accountId, resource) = command; @@ -40,6 +41,7 @@ private static async ValueTask HandleAsync( if (result.IsFailed) return result; } + await delayService.DelayClick(cancellationToken); return Result.Ok(); } diff --git a/MainCore/Enums/BuildingEnums.cs b/MainCore/Enums/BuildingEnums.cs index c6dfbb2c..11f3fb59 100644 --- a/MainCore/Enums/BuildingEnums.cs +++ b/MainCore/Enums/BuildingEnums.cs @@ -260,6 +260,19 @@ public static List GetPrerequisiteBuildings(this BuildingE }; } + public static bool IsResourceBonus(this BuildingEnums building) + { + return building switch + { + BuildingEnums.Sawmill => true, + BuildingEnums.Brickyard => true, + BuildingEnums.IronFoundry => true, + BuildingEnums.Bakery => true, + BuildingEnums.GrainMill => true, + _ => false, + }; + } + public static bool IsResourceField(this BuildingEnums building) { int buildingInt = (int)building; diff --git a/MainCore/Tasks/CompleteImmediatelyTask.cs b/MainCore/Tasks/CompleteImmediatelyTask.cs index c77c4291..50975f34 100644 --- a/MainCore/Tasks/CompleteImmediatelyTask.cs +++ b/MainCore/Tasks/CompleteImmediatelyTask.cs @@ -38,13 +38,11 @@ public override bool CanStart(AppDbContext context) var completeImmediatelyMinimumTime = context.ByName(VillageId, VillageSettingEnums.CompleteImmediatelyTime); var requiredTime = DateTime.Now.AddMinutes(completeImmediatelyMinimumTime); - var firstQueueBuildingCompleteTime = queueBuildings - .OrderBy(x => x.CompleteTime) - .Select(x => x.CompleteTime) - .FirstOrDefault(); + var anyBuilding = queueBuildings + .Where(x => x.CompleteTime > requiredTime) + .Any(); - if (requiredTime > firstQueueBuildingCompleteTime) return false; - return true; + return anyBuilding; } }