From ed7b8b5f038494972bafcd8445cea5ce8265fdbd Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 26 Jun 2024 16:42:03 +0200 Subject: [PATCH 001/117] * fix BuyOfferOfTheDayWorker run only once and isn't rescheduled. * wrong values for fuelConsumption SmallCargo and Recycler Reported by @AlexKidd --- TBot/Includes/CalculationService.cs | 4 ++-- TBot/Workers/Brain/BuyOfferOfTheDayWorker.cs | 25 +++++++------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index b6a4690e..f58d9ff9 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -366,7 +366,7 @@ public int CalcShipConsumption(Buildables buildable, int impulseDrive, int hyper int baseConsumption; switch (buildable) { case Buildables.SmallCargo: - baseConsumption = 20; + baseConsumption = 10; if (impulseDrive >= 5) baseConsumption *= 2; break; @@ -389,7 +389,7 @@ public int CalcShipConsumption(Buildables buildable, int impulseDrive, int hyper baseConsumption = 1000; break; case Buildables.Recycler: - baseConsumption = 2000; + baseConsumption = 300; if (hyperspaceDrive >= 15) baseConsumption *= 3; else if (impulseDrive >= 17) diff --git a/TBot/Workers/Brain/BuyOfferOfTheDayWorker.cs b/TBot/Workers/Brain/BuyOfferOfTheDayWorker.cs index 7b7255e5..16f7abb5 100644 --- a/TBot/Workers/Brain/BuyOfferOfTheDayWorker.cs +++ b/TBot/Workers/Brain/BuyOfferOfTheDayWorker.cs @@ -25,8 +25,6 @@ public BuyOfferOfTheDayWorker(ITBotMain parentInstance, _tbotOgameBridge = tbotOgameBridge; } protected override async Task Execute() { - bool stop = true; - _tbotInstance.log(LogLevel.Information, GetLogSender(), "Buying offer of the day..."); OfferOfTheDayStatus sts = await _ogameService.BuyOfferOfTheDay(); @@ -36,23 +34,16 @@ protected override async Task Execute() { _tbotInstance.log(LogLevel.Information, GetLogSender(), "Offer of the day already bought."); } else { _tbotInstance.log(LogLevel.Information, GetLogSender(), "Error buying Offer of the day. Already bought?"); - stop = false; } - - if (stop) { - _tbotInstance.log(LogLevel.Information, GetLogSender(), $"Stopping BuyOfferOfTheDay."); - await EndExecution(); - } else { - var time = await _tbotOgameBridge.GetDateTime(); - var interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.BuyOfferOfTheDay.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.BuyOfferOfTheDay.CheckIntervalMax); - if (interval <= 0) - interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - var newTime = time.AddMilliseconds(interval); - ChangeWorkerPeriod(interval); - _tbotInstance.log(LogLevel.Information, GetLogSender(), $"Next BuyOfferOfTheDay check at {newTime.ToString()}"); - await _tbotOgameBridge.CheckCelestials(); - } + var time = await _tbotOgameBridge.GetDateTime(); + var interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.BuyOfferOfTheDay.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.BuyOfferOfTheDay.CheckIntervalMax); + if (interval <= 0) + interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + var newTime = time.AddMilliseconds(interval); + ChangeWorkerPeriod(interval); + _tbotInstance.log(LogLevel.Information, GetLogSender(), $"Next BuyOfferOfTheDay check at {newTime.ToString()}"); + await _tbotOgameBridge.CheckCelestials(); } public override bool IsWorkerEnabledBySettings() { try { From 736c18bf8350f57fecd9bef28a98b9161af18e04 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 13 Jul 2024 10:48:00 +0200 Subject: [PATCH 002/117] * prevent using deprecated parameter user-agent --- TBot/Services/TBotMain.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/TBot/Services/TBotMain.cs b/TBot/Services/TBotMain.cs index 6a09f4c5..c217d61e 100644 --- a/TBot/Services/TBotMain.cs +++ b/TBot/Services/TBotMain.cs @@ -185,7 +185,6 @@ private async Task InitializeOgame() { _ogameService.Initialize(GetCredentialsFromSettings(), GetDeviceFromSettings(), proxy, (string) host, int.Parse(port), (string) captchaKey); - await _ogameService.SetUserAgent((string) InstanceSettings.Credentials.DeviceConf.UserAgent); } private async Task ResolveCaptcha() { From 092debb8ba70b33b3d950b43c5ce1643320c2eed Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 13 Jul 2024 14:17:53 +0200 Subject: [PATCH 003/117] * update ogamed --- ogame | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ogame b/ogame index e46c1828..d13bc911 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit e46c1828cc1784e70102304173e44c4cf0a50dd8 +Subproject commit d13bc9116628933692dd75294a5f1624df1cece6 From 807cc85c156d55ee46ccd9840c7d2cf994bfd75c Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Tue, 30 Jul 2024 13:46:44 +0200 Subject: [PATCH 004/117] * AutoFarmer: Issue if no Moon is present! --- TBot/Workers/AutoFarmWorker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TBot/Workers/AutoFarmWorker.cs b/TBot/Workers/AutoFarmWorker.cs index 2aff82c2..4e282f59 100644 --- a/TBot/Workers/AutoFarmWorker.cs +++ b/TBot/Workers/AutoFarmWorker.cs @@ -625,7 +625,7 @@ protected override async Task Execute() { attackTargetsCount++; _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Attacking target {attackTargetsCount}/{attackTargets.Count()} at {target.Celestial.Coordinate.ToString()} for {target.Report.Loot(_tbotInstance.UserData.userInfo.Class).TransportableResources}."); var loot = target.Report.Loot(_tbotInstance.UserData.userInfo.Class); - Celestial tempCelestial = _tbotInstance.UserData.celestials.Where(c => c.Coordinate.Type == Celestials.Moon).First(); + Celestial tempCelestial = _tbotInstance.UserData.celestials.Where(c => c.Coordinate.Type == Celestials.Planet).First(); tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.LFBonuses); float cargoBonus = tempCelestial.LFBonuses.GetShipCargoBonus(cargoShip); var numCargo = _calculationService.CalcShipNumberForPayload(loot, cargoShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, cargoBonus, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); From 819c892c93c7e64078db40a84128bd473e5b9a13 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 1 Aug 2024 20:41:43 +0200 Subject: [PATCH 005/117] * fix Device-Name always ToUpper() don't manipulate string from settings file. --- TBot/Services/TBotMain.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TBot/Services/TBotMain.cs b/TBot/Services/TBotMain.cs index c217d61e..16ea5148 100644 --- a/TBot/Services/TBotMain.cs +++ b/TBot/Services/TBotMain.cs @@ -135,7 +135,7 @@ private Credentials GetCredentialsFromSettings() { private Device GetDeviceFromSettings() { return new() { - Name = ((string) InstanceSettings.Credentials.DeviceConf.Name).ToUpper(), + Name = ((string) InstanceSettings.Credentials.DeviceConf.Name), System = (string) InstanceSettings.Credentials.DeviceConf.System ?? "", Browser = (string) InstanceSettings.Credentials.DeviceConf.Browser ?? "", UserAgent = (string) InstanceSettings.Credentials.DeviceConf.UserAgent ?? "", From b62ba369ba3d34dc7288690190058ff0c4d49433 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 3 Aug 2024 15:59:40 +0200 Subject: [PATCH 006/117] Typo origin.Coordinate.System -> sys We want to use the sys variable we are looking at, not the System from the Origin. --- TBot/Workers/FleetScheduler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 6ae792d7..4498f24c 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -635,7 +635,7 @@ private async Task> GetFleetSaveDestination(List galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); foreach (var planet in galaxyInfo.Planets) { if (planet == null) { - possibleDestinations.Add(new(origin.Coordinate.Galaxy, origin.Coordinate.System, pos)); + possibleDestinations.Add(new(origin.Coordinate.Galaxy, sys, pos)); } pos++; } From 6de0750f803fcc6999c6878ab6b0712cb80bef8b Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Mon, 5 Aug 2024 21:52:40 +0200 Subject: [PATCH 007/117] * minor fix for rerun AutoResearch. Building were nil after first run, will now make sure its up to date! --- TBot/Workers/Brain/AutoResearchWorker.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index b61f57d4..473bff65 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -86,6 +86,7 @@ protected override async Task Execute() { return; } _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Buildings) as Planet; celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Facilities) as Planet; celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Resources) as Planet; celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.ResourcesProduction) as Planet; From 3a221e4c3abed0a026a199a6f33899dc2d5c5f2b Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 11 Sep 2024 10:06:01 +0200 Subject: [PATCH 008/117] * update ogame wrapper --- ogame | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ogame b/ogame index d13bc911..85fc8953 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit d13bc9116628933692dd75294a5f1624df1cece6 +Subproject commit 85fc8953968ed5af623db029d00c46c9c09a2225 From 23b7a5b5ff861bfa89b77417feab0b4c29a3c230 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Fri, 27 Sep 2024 08:54:03 +0200 Subject: [PATCH 009/117] * fix DOIR --- TBot/Workers/Brain/AutoMineWorker.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/TBot/Workers/Brain/AutoMineWorker.cs b/TBot/Workers/Brain/AutoMineWorker.cs index 6e428459..76c51e82 100644 --- a/TBot/Workers/Brain/AutoMineWorker.cs +++ b/TBot/Workers/Brain/AutoMineWorker.cs @@ -110,7 +110,9 @@ protected override async Task Execute() { cel = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBuildings); cel = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses); Planet abaCelestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Fast) as Planet; - var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, int.MaxValue, int.MaxValue, int.MaxValue, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); + + var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, _tbotInstance.InstanceSettings.Brain.AutoMine.MaxMetalMine, _tbotInstance.InstanceSettings.Brain.AutoMine.MaxCrystalMine, _tbotInstance.InstanceSettings.Brain.AutoMine.MaxDeuteriumSynthetizer, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); + //var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, int.MaxValue, int.MaxValue, int.MaxValue, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); var lv = _calculationService.GetNextLevel(cel, nextMine); var DOIR = _calculationService.CalcNextDaysOfInvestmentReturn(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull); DoLog(LogLevel.Debug, $"Celestial {cel.ToString()}: Next Mine: {nextMine.ToString()} lv {lv.ToString()}; DOIR: {DOIR.ToString()}."); From 5064a878aade8a71cebf5f13f8d738aee006d3a6 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Sun, 22 Sep 2024 17:19:47 +0200 Subject: [PATCH 010/117] Ignore sleepMode for expedition (cherry picked from commit 4b12edc174c92b0da3f13e93e718e778c8338ef9) --- TBot/Workers/FleetScheduler.cs | 10 ++++++++-- TBot/instance_settings.json | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 4498f24c..93a764da 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -419,8 +419,14 @@ public async Task SendFleet(Celestial origin, Ships ships, Coordinate desti var flightTime = mission switch { Missions.Deploy => fleetPrediction.Time, - Missions.Expedition => (long) Math.Round((double) (2 * fleetPrediction.Time) + 3600, 0, MidpointRounding.ToPositiveInfinity), - _ => (long) Math.Round((double) (2 * fleetPrediction.Time), 0, MidpointRounding.ToPositiveInfinity), + + // Use a ternary operator to conditionally handle IgnoreSleep setting + Missions.Expedition => (bool) _tbotInstance.InstanceSettings.Expeditions.IgnoreSleep + ? 1 + : (long) Math.Round((double) (2 * fleetPrediction.Time) + 3600, 0, MidpointRounding.ToPositiveInfinity), + + // Default case for other missions + _ => (long) Math.Round((double) (2 * fleetPrediction.Time), 0, MidpointRounding.ToPositiveInfinity) }; _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"Calculated flight time (full trip): {TimeSpan.FromSeconds(flightTime).ToString()}"); _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"Calculated flight fuel: {fleetPrediction.Fuel.ToString()}"); diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index 74cdb7e7..e853c0fe 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -365,6 +365,7 @@ }, "AutoFarm": { "Active": true, + "IgnoreSleep": false, "ExcludeMoons": true, "ScanRange": [ { From 14707039690e1b90e6ca011bdb762ccf98c43ead Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Sun, 22 Sep 2024 17:47:21 +0200 Subject: [PATCH 011/117] oups (cherry picked from commit f163847b0f582e5f723a1fc5b1dd901b0cad9039) --- TBot/instance_settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index e853c0fe..5dd6ae24 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -320,6 +320,7 @@ }, "Expeditions": { "Active": true, + "IgnoreSleep": false, "MinWaitNextFleet": 5, "MaxWaitNextFleet": 15, "PrimaryShip": "LargeCargo", @@ -365,7 +366,6 @@ }, "AutoFarm": { "Active": true, - "IgnoreSleep": false, "ExcludeMoons": true, "ScanRange": [ { From 2945bb0f40051625f5386c69b86e0ef93da888b0 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Thu, 26 Sep 2024 20:05:27 +0200 Subject: [PATCH 012/117] fix slotExpo not use (cherry picked from commit cab5459edf533443fb8fd298504350dee1825ed4) --- TBot/Workers/ExpeditionsWorker.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index fc7f2063..1cca098c 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -147,13 +147,18 @@ protected override async Task Execute() { originExps[origins[i]]++; } LFBonuses lfBonuses = origins.First().LFBonuses; + int delayExpedition = 0; foreach (var origin in originExps.Keys) { int expsToSendFromThisOrigin = originExps[origin]; if (expsToSendFromThisOrigin == 0) { - continue; + if (delayExpedition > 0) + delayExpedition--; + else + continue; } else if (origin.Ships.IsEmpty()) { DoLog(LogLevel.Warning, "Unable to send expeditions: no ships available"); + delayExpedition++; continue; } else { Ships fleet; @@ -179,16 +184,19 @@ protected override async Task Execute() { ); if (!origin.Ships.HasAtLeast(fleet, expsToSendFromThisOrigin)) { DoLog(LogLevel.Warning, $"Unable to send expeditions: not enough ships in origin {origin.ToString()}"); + delayExpedition++; continue; } } else { Buildables primaryShip = Buildables.LargeCargo; if (!Enum.TryParse(_tbotInstance.InstanceSettings.Expeditions.PrimaryShip.ToString(), true, out primaryShip)) { DoLog(LogLevel.Warning, "Unable to parse PrimaryShip. Falling back to default LargeCargo"); + delayExpedition++; primaryShip = Buildables.LargeCargo; } if (primaryShip == Buildables.Null) { DoLog(LogLevel.Warning, "Unable to send expeditions: primary ship is Null"); + delayExpedition++; continue; } @@ -202,6 +210,7 @@ protected override async Task Execute() { fleet.SetAmount(primaryShip, (long) _tbotInstance.InstanceSettings.Expeditions.MinPrimaryToSend); if (!availableShips.HasAtLeast(fleet, expsToSendFromThisOrigin)) { DoLog(LogLevel.Warning, $"Unable to send expeditions: available {primaryShip.ToString()} in origin {origin.ToString()} under set min number of {(long) _tbotInstance.InstanceSettings.Expeditions.MinPrimaryToSend}"); + delayExpedition++; continue; } } @@ -225,11 +234,13 @@ protected override async Task Execute() { ); if (secondaryToSend < (long) _tbotInstance.InstanceSettings.Expeditions.MinSecondaryToSend) { DoLog(LogLevel.Warning, $"Unable to send expeditions: available {secondaryShip.ToString()} in origin {origin.ToString()} under set number of {(long) _tbotInstance.InstanceSettings.Expeditions.MinSecondaryToSend}"); + delayExpedition++; continue; } else { fleet.Add(secondaryShip, secondaryToSend); if (!availableShips.HasAtLeast(fleet, expsToSendFromThisOrigin)) { DoLog(LogLevel.Warning, $"Unable to send expeditions: not enough ships in origin {origin.ToString()}"); + delayExpedition++; continue; } } From b4aa77b72f3a283f85dd13650fd2af6231645d56 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 28 Sep 2024 08:48:09 +0200 Subject: [PATCH 013/117] * fix AutoMine Typo --- TBot/Workers/Brain/AutoMineWorker.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TBot/Workers/Brain/AutoMineWorker.cs b/TBot/Workers/Brain/AutoMineWorker.cs index 76c51e82..f16f15cb 100644 --- a/TBot/Workers/Brain/AutoMineWorker.cs +++ b/TBot/Workers/Brain/AutoMineWorker.cs @@ -110,8 +110,8 @@ protected override async Task Execute() { cel = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBuildings); cel = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses); Planet abaCelestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Fast) as Planet; - - var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, _tbotInstance.InstanceSettings.Brain.AutoMine.MaxMetalMine, _tbotInstance.InstanceSettings.Brain.AutoMine.MaxCrystalMine, _tbotInstance.InstanceSettings.Brain.AutoMine.MaxDeuteriumSynthetizer, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); + + var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxMetalMine, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxCrystalMine, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxDeuteriumSynthetizer, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); //var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, int.MaxValue, int.MaxValue, int.MaxValue, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); var lv = _calculationService.GetNextLevel(cel, nextMine); var DOIR = _calculationService.CalcNextDaysOfInvestmentReturn(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull); From 1c85badcb9a45d646d70cde54b85df27fc47dc2a Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 6 Nov 2024 12:04:46 +0100 Subject: [PATCH 014/117] * update ogamed --- ogame | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ogame b/ogame index 85fc8953..cf1c40f5 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit 85fc8953968ed5af623db029d00c46c9c09a2225 +Subproject commit cf1c40f55d9b4c1a04b5f9473ae84017cf4391ff From a49bd23ecd25388aa0133d539901a3737cef171a Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 23 Nov 2024 09:03:54 +0100 Subject: [PATCH 015/117] * reverse maxInt --- TBot/Workers/Brain/AutoMineWorker.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TBot/Workers/Brain/AutoMineWorker.cs b/TBot/Workers/Brain/AutoMineWorker.cs index f16f15cb..250b8ccd 100644 --- a/TBot/Workers/Brain/AutoMineWorker.cs +++ b/TBot/Workers/Brain/AutoMineWorker.cs @@ -111,8 +111,8 @@ protected override async Task Execute() { cel = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses); Planet abaCelestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Fast) as Planet; - var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxMetalMine, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxCrystalMine, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxDeuteriumSynthetizer, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); - //var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, int.MaxValue, int.MaxValue, int.MaxValue, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); + //var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxMetalMine, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxCrystalMine, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxDeuteriumSynthetizer, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); + var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, int.MaxValue, int.MaxValue, int.MaxValue, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); var lv = _calculationService.GetNextLevel(cel, nextMine); var DOIR = _calculationService.CalcNextDaysOfInvestmentReturn(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull); DoLog(LogLevel.Debug, $"Celestial {cel.ToString()}: Next Mine: {nextMine.ToString()} lv {lv.ToString()}; DOIR: {DOIR.ToString()}."); From 153ed4c0ebb767d74771a566625af946c95bbeee Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 23 Nov 2024 09:27:48 +0100 Subject: [PATCH 016/117] * update submodule --- .gitmodules | 4 ++-- ogame | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 02037af9..c3e8ddcc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "ogame"] path = ogame - url = https://github.com/ogame-tbot-net/ogame.git - branch = develop_v11.9 + url = https://github.com/0xE232FE/ogame.mod.git + branch = develop_v11.15.5-tbot diff --git a/ogame b/ogame index cf1c40f5..a42f3436 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit cf1c40f55d9b4c1a04b5f9473ae84017cf4391ff +Subproject commit a42f3436e51fd2b3096f8714a3e4469e4383363c From 55c54e73e2887f2bcc8b62221a77d8f48590dca2 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Mon, 25 Nov 2024 15:08:25 +0100 Subject: [PATCH 017/117] Improve Brain Transport and Slots Usage --- .../Enums/SendFleetCode.cs | 3 +- .../Models/RankSlotsPriority.cs | 31 ++ TBot/Includes/CalculationService.cs | 11 + TBot/Includes/ICalculationService.cs | 1 + TBot/Workers/AutoDiscoveryWorker.cs | 87 ++++- TBot/Workers/AutoFarmWorker.cs | 105 +++++- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 322 +++++++++++++++-- TBot/Workers/Brain/AutoMineWorker.cs | 18 +- TBot/Workers/Brain/AutoResearchWorker.cs | 321 +++++++++++++++-- .../Brain/LifeformsAutoMineCelestialWorker.cs | 323 ++++++++++++++++-- .../LifeformsAutoResearchCelestialWorker.cs | 300 ++++++++++++++-- TBot/Workers/ColonizeWorker.cs | 80 ++++- TBot/Workers/ExpeditionsWorker.cs | 81 ++++- TBot/Workers/FleetScheduler.cs | 80 +++-- TBot/Workers/HarvestWorker.cs | 82 +++++ TBot/instance_settings.json | 28 +- 16 files changed, 1707 insertions(+), 166 deletions(-) create mode 100644 TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs diff --git a/TBot.Ogame.Infrastructure/Enums/SendFleetCode.cs b/TBot.Ogame.Infrastructure/Enums/SendFleetCode.cs index 79b83a8e..45df11af 100644 --- a/TBot.Ogame.Infrastructure/Enums/SendFleetCode.cs +++ b/TBot.Ogame.Infrastructure/Enums/SendFleetCode.cs @@ -9,6 +9,7 @@ public enum SendFleetCode : int { GenericError = 0, AfterSleepTime = -1, NotEnoughSlots = -2, - QuickerToWaitForProduction = -3 + QuickerToWaitForProduction = -3, + NotEnoughRessources = -4 } } diff --git a/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs b/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs new file mode 100644 index 00000000..1be10a91 --- /dev/null +++ b/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Text.RegularExpressions; +using TBot.Ogame.Infrastructure.Enums; + +namespace TBot.Ogame.Infrastructure.Models { + public class RankSlotsPriority { + public RankSlotsPriority(Feature feature = Feature.Null, int rank = int.MaxValue, bool active = false, int maxSlots = 0, int slotsUsed = 0) { + Rank = rank < 1 ? int.MaxValue : rank; + Active = active; + MaxSlots = maxSlots; + SlotsUsed = slotsUsed; + Feature = feature; + } + public int Rank { get; set; } + public bool Active { get; set; } + public int MaxSlots { get; set; } + public int SlotsUsed { get; set; } + public Feature Feature { get; set; } + public bool HasPriorityOn(RankSlotsPriority feature) { + return this.Rank < feature.Rank; + } + public override string ToString() { + return $"{Rank} -- {Feature.ToString()} is {Active}, using {SlotsUsed}/{MaxSlots}"; + } + } + +} \ No newline at end of file diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index f58d9ff9..61d4c398 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4806,5 +4806,16 @@ public int CountPlanetsInRange(List planets, int galaxy, int minSyste .Where(planet => (planet as Planet).Temperature.Max >= minTemperature && (planet as Planet).Temperature.Max <= maxTemperature) .Count(); } + + public bool IsThereMoonHere(List planets, Celestial celestial) { + Celestial moon = planets.Unique() + .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == Celestials.Moon) + .SingleOrDefault() ?? new() { ID = 0 }; + + return moon.ID == 0 ? false: true; + } } } diff --git a/TBot/Includes/ICalculationService.cs b/TBot/Includes/ICalculationService.cs index 0ca15f86..4adf934f 100644 --- a/TBot/Includes/ICalculationService.cs +++ b/TBot/Includes/ICalculationService.cs @@ -152,6 +152,7 @@ public interface ICalculationService { bool ShouldAbandon(Planet celestial, int maxCases, int Temperature, Fields fieldsSettings, Temperature temperaturesSettings); int CountPlanetsInRange(List planets, int galaxy, int minSystem, int maxSystem, int minPosition, int maxPositions, int minSlots, int minTemperature, int maxTemperature); int CountPlanetsInRange(List planets, int galaxy, int minSystem, int maxSystem, int minPosition, int maxPositions, int minSlots, int minTemperature, int maxTemperature); + bool IsThereMoonHere(List planets, Celestial celestial); } diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index ba48bdca..d8554e36 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -45,8 +45,83 @@ protected override async Task Execute() { } if (!_tbotInstance.UserData.isSleeping) { DoLog(LogLevel.Information, $"Starting AutoDiscovery..."); - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + List rankSlotsPriority = new(); + RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && + (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); + RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); + RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); + RankSlotsPriority ColonizeRank = new(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); + RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); + RankSlotsPriority presentFeature = AutoDiscoveryRank; + rankSlotsPriority.Add(BrainRank); + rankSlotsPriority.Add(ExpeditionsRank); + rankSlotsPriority.Add(AutoFarmRank); + rankSlotsPriority.Add(ColonizeRank); + rankSlotsPriority.Add(AutoDiscoveryRank); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + string msg = ""; + int reservedSlots = 0; + int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; + int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery) + ).Count(); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + foreach (RankSlotsPriority feature in rankSlotsPriority) { + if (feature == presentFeature) + continue; + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + if (feature.Active && feature.HasPriorityOn(presentFeature)) { + msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; + reservedSlots += feature.MaxSlots; + } else { + otherSlots += feature.SlotsUsed; + } + } + if (otherSlots > 0) + msg = $"{msg}, {otherSlots} are used for Other"; + int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; + tempsValue = tempsValue < 0 ? 0 : tempsValue; + DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); + if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); + MaxSlots = 0; + } else if (MaxSlots > tempsValue) { + MaxSlots = tempsValue; + DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); + } + Celestial origin = _tbotInstance.UserData.celestials .Unique() @@ -84,10 +159,12 @@ protected override async Task Execute() { } possibleDestinations = possibleDestinations .Shuffle() + .OrderBy(c => c.Position) + .OrderBy(c => c.System) .OrderBy(c => _calculationService.CalcDistance(origin.Coordinate, c, _tbotInstance.UserData.serverData)) .ToList(); - while (possibleDestinations.Count > 0 && _tbotInstance.UserData.fleets.Where(s => s.Mission == Missions.Discovery).Count() < (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots && _tbotInstance.UserData.slots.Free > (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + while (possibleDestinations.Count > 0 && _tbotInstance.UserData.fleets.Where(s => s.Mission == Missions.Discovery).Count() < MaxSlots && _tbotInstance.UserData.slots.Free > (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { Coordinate dest = possibleDestinations.First(); possibleDestinations.Remove(dest); @@ -136,7 +213,7 @@ protected override async Task Execute() { _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - if (_tbotInstance.UserData.slots.Free <= 1) { + if (_tbotInstance.UserData.slots.Free <= _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { DoLog(LogLevel.Information, $"AutoDiscoveryWorker: No slots left, dealying"); delay = true; break; @@ -155,11 +232,11 @@ protected override async Task Execute() { DoLog(LogLevel.Information, $"Stopping feature."); await EndExecution(); } else { - long interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax); + long interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); if (delay) { DoLog(LogLevel.Information, $"Delaying..."); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + interval = interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax); } if (interval <= 0) interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); diff --git a/TBot/Workers/AutoFarmWorker.cs b/TBot/Workers/AutoFarmWorker.cs index 4e282f59..4aa4b21b 100644 --- a/TBot/Workers/AutoFarmWorker.cs +++ b/TBot/Workers/AutoFarmWorker.cs @@ -334,13 +334,11 @@ private async Task WaitForFreeSlots(int freeSlots, int slotsToLeaveFree) { protected override async Task Execute() { bool stop = false; try { - _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, "Running autofarm..."); - if ((bool) _tbotInstance.InstanceSettings.AutoFarm.Active) { - // If not enough slots are free, the farmer cannot run. + // If not enough slots are free, the farmer cannot run. _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - + int freeSlots = _tbotInstance.UserData.slots.Free; int slotsToLeaveFree = (int) _tbotInstance.InstanceSettings.AutoFarm.SlotsToLeaveFree; if (freeSlots <= slotsToLeaveFree) { @@ -582,6 +580,83 @@ protected override async Task Execute() { /// Process reports. await AutoFarmProcessReports(); + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + List rankSlotsPriority = new(); + RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && + (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); + RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); + RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); + RankSlotsPriority ColonizeRank = new(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); + RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); + RankSlotsPriority presentFeature = AutoFarmRank; + rankSlotsPriority.Add(BrainRank); + rankSlotsPriority.Add(ExpeditionsRank); + rankSlotsPriority.Add(AutoFarmRank); + rankSlotsPriority.Add(ColonizeRank); + rankSlotsPriority.Add(AutoDiscoveryRank); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + string msg = ""; + int reservedSlots = 0; + int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; + int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery) + ).Count(); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + foreach (RankSlotsPriority feature in rankSlotsPriority) { + if (feature == presentFeature) + continue; + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + if (feature.Active && feature.HasPriorityOn(presentFeature)) { + msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; + reservedSlots += feature.MaxSlots; + } else { + otherSlots += feature.SlotsUsed; + } + } + if (otherSlots > 0) + msg = $"{msg}, {otherSlots} are used for Other"; + int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; + tempsValue = tempsValue < 0 ? 0 : tempsValue; + DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); + if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); + MaxSlots = 0; + } else if (MaxSlots > tempsValue) { + MaxSlots = tempsValue; + DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); + } + /// Send attacks. List attackTargets; if (_tbotInstance.InstanceSettings.AutoFarm.PreferedResource == "Metal") @@ -808,7 +883,7 @@ protected override async Task Execute() { .Where(fleet => fleet.Mission == Missions.Attack) .ToList(); - if (_tbotInstance.UserData.slots.Free > slotsToLeaveFree && slotUsed.Count() < (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots) { + if (_tbotInstance.UserData.slots.Free > slotsToLeaveFree && slotUsed.Count() < MaxSlots) { _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Attacking {target.ToString()} from {fromCelestial} with {numCargo} {cargoShip.ToString()}."); Ships ships = new(); fromCelestial = await _tbotOgameBridge.UpdatePlanet(fromCelestial, UpdateTypes.LFBonuses); @@ -850,7 +925,7 @@ protected override async Task Execute() { target.State = FarmState.AttackSent; _tbotInstance.UserData.farmTargets.Add(target); } else { - _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Unable to attack {target.Celestial.Coordinate}: {slotUsed.Count()} slots used by AutoFarm, {_tbotInstance.InstanceSettings.AutoFarm.MaxSlots} slots usable by AutoFarm, {_tbotInstance.UserData.slots.Free} slots free, {slotsToLeaveFree} must remain free."); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Unable to attack {target.Celestial.Coordinate}: {slotUsed.Count()} slots used by AutoFarm, {MaxSlots} slots usable by AutoFarm, {_tbotInstance.UserData.slots.Free} slots free, {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free."); return; } } @@ -867,9 +942,21 @@ protected override async Task Execute() { await EndExecution(); } else { var time = await _tbotOgameBridge.GetDateTime(); - var interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoFarm.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoFarm.CheckIntervalMax); - if (interval <= 0) - interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + List orderedFleets = _tbotInstance.UserData.fleets + .Where(fleet => fleet.Mission == Missions.Attack) + .ToList(); + orderedFleets = orderedFleets + .OrderByDescending(fleet => fleet.BackIn) + .ToList(); + long interval; + try { + interval = (int) ((1000 * orderedFleets.First().BackIn) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds)); + } catch { + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoFarm.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoFarm.CheckIntervalMax); + if (interval <= 0) + interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + } var newTime = time.AddMilliseconds(interval); ChangeWorkerPeriod(interval); _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Next autofarm check at {newTime.ToString()}"); diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index bc3aa727..7d119956 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -302,27 +302,271 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings DoLog(LogLevel.Information, $"Not enough resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {celestial.Resources.TransportableResources}"); } if ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Transports.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active) { + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { - Celestial origin = _tbotInstance.UserData.celestials - .Unique() - .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) - .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) - .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) - .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) - .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, xCostBuildable, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); - - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; - return; + List rankSlotsPriority = new(); + RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && + (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); + RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); + RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); + RankSlotsPriority ColonizeRank = new(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); + RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); + RankSlotsPriority presentFeature = BrainRank; + rankSlotsPriority.Add(BrainRank); + rankSlotsPriority.Add(ExpeditionsRank); + rankSlotsPriority.Add(AutoFarmRank); + rankSlotsPriority.Add(ColonizeRank); + rankSlotsPriority.Add(AutoDiscoveryRank); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + string msg = ""; + int reservedSlots = 0; + int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; + int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery) + ).Count(); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + foreach (RankSlotsPriority feature in rankSlotsPriority) { + if (feature == presentFeature) + continue; + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + if (feature.Active && feature.HasPriorityOn(presentFeature)) { + msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; + reservedSlots += feature.MaxSlots; + } else { + otherSlots += feature.SlotsUsed; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; - return; + } + if (otherSlots > 0) + msg = $"{msg}, {otherSlots} are used for Other"; + int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; + tempsValue = tempsValue < 0 ? 0 : tempsValue; + DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); + if (reservedSlots + otherSlots + presentFeature.SlotsUsed > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); + MaxSlots = 0; + } else if (MaxSlots > tempsValue) { + MaxSlots = tempsValue; + DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); + } + + if (MaxSlots > 0) { + if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { + Celestial origin; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + .SingleOrDefault() ?? new() { ID = 0 }; + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, xCostBuildable, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } + + if (fleetId <= 0) { + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active) { + var resultOrigins = new Dictionary(); + List allCelestials = _tbotInstance.UserData.celestials; + List celestialsToExclude = _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Exclude, allCelestials); + for (int i = 0; i < allCelestials.Count(); i++) { + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + } + List closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons ? + allCelestials + .Where(planet => !celestialsToExclude.Has(planet)) + .Where(planet => planet.Resources.TotalResources > 0) + .Where(planet => planet.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) + .ToList(): + allCelestials + .Where(c => !celestialsToExclude.Has(c)) + .Where(c => c.Resources.TotalResources > 0) + .Where(c => c.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) + .ToList(); + + closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity ? + closestCelestials.OrderBy(c => _calculationService.CalcDistance(c.Coordinate, celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList() : + closestCelestials.OrderByDescending(c => c.Resources.TotalResources).ToList(); + + Resources missingResources = xCostBuildable.Difference(celestial.Resources); + Resources resourcesTotalAvailable = new(); + Resources possibleResources = new(); + + Celestial destination; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + destination = allCelestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .First(); + } else { + destination = allCelestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) + .First(); + } + if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { + DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); + return; + } + + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; + } + long idealShips; + + foreach (var possibleOrigin in closestCelestials) { + //if (!celestialsToExclude.Has(possibleOrigin)) // if .Where(planet => !celestialsToExclude.Has(planet)) don't work + if (!_calculationService.IsThereTransportTowardsCelestial(possibleOrigin, _tbotInstance.UserData.fleets)) + possibleResources = possibleResources.Sum(possibleOrigin.Resources); + } + if (!possibleResources.IsEnoughFor(xCostBuildable)) { + possibleResources = possibleResources.Sum(celestial.Resources); + DoLog(LogLevel.Information, $"Not enough resources available on all celestials to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); + return; + } + + Celestial moonDestination = new(); + foreach (var possibleOrigin in closestCelestials) { + possibleResources = new(); + Celestial tempPossibleOrigin = possibleOrigin; + tempPossibleOrigin.Resources.Deuterium = (tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) > 0 ? tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave : 0; + if (tempPossibleOrigin.Resources.Metal < missingResources.Metal - resourcesTotalAvailable.Metal) + possibleResources.Metal = tempPossibleOrigin.Resources.Metal; + else + possibleResources.Metal = missingResources.Metal - resourcesTotalAvailable.Metal; + if (tempPossibleOrigin.Resources.Crystal < missingResources.Crystal - resourcesTotalAvailable.Crystal) + possibleResources.Crystal = tempPossibleOrigin.Resources.Crystal; + else + possibleResources.Crystal = missingResources.Crystal - resourcesTotalAvailable.Crystal; + if (tempPossibleOrigin.Resources.Deuterium < missingResources.Deuterium - resourcesTotalAvailable.Deuterium) + possibleResources.Deuterium = tempPossibleOrigin.Resources.Deuterium; + else + possibleResources.Deuterium = missingResources.Deuterium - resourcesTotalAvailable.Deuterium; + + idealShips = _calculationService.CalcShipNumberForPayload(possibleResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (idealShips > possibleOrigin.Ships.GetAmount(preferredShip) || + possibleResources.TotalResources <= (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend || + _calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)) + continue; + + resourcesTotalAvailable = resourcesTotalAvailable.Sum(possibleResources); + resultOrigins.Add(tempPossibleOrigin, possibleResources); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{tempPossibleOrigin.ToString()} add with {possibleResources.TotalResources} - ({resultOrigins.Count}) {_calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)}"); + if (resourcesTotalAvailable.IsEnoughFor(missingResources)) + break; + } + + if (resultOrigins.Count > MaxSlots) { + DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + return; + } + + possibleResources = new(); + foreach (var (originMultiple, resourcesValue) in resultOrigins) { + possibleResources = possibleResources.Sum(resourcesValue); + } + if (!possibleResources.IsEnoughFor(missingResources)) { + possibleResources = possibleResources.Sum(celestial.Resources); + DoLog(LogLevel.Information, $"Not enough cargo available on all celestials to transport resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); + return; + } + + Ships ships = new(); + var fleetID = 0; + foreach (var (originMultiple, resourcesValue) in resultOrigins) { + ships = new(); + ships.Add(preferredShip, _calculationService.CalcShipNumberForPayload(resourcesValue, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); + + fleetID = await _fleetScheduler.SendFleet(originMultiple, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, resourcesValue); + + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + return; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + return; + } + } + } else { + Celestial destination; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + destination = _tbotInstance.UserData.celestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .First(); + } else { + destination = _tbotInstance.UserData.celestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) + .First(); + } + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) + .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) + .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) + .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) + .SingleOrDefault() ?? new() { ID = 0 }; + fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, xCostBuildable, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } + } + } else { + DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); } - } else { - DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); } } } @@ -415,14 +659,24 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings } else { long interval = await CalcAutoMineTimer(celestial, buildable, level, started, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); - - if (fleetId != 0 && fleetId != -1 && fleetId != -2) { - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + if (fleetId > 0) { + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMax); + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + } + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) + .Where(f => f.Destination.IsSame(celestial.Coordinate)) + .Where(f => f.Origin.Galaxy == celestial.Coordinate.Galaxy) + .Where(f => f.Origin.System == celestial.Coordinate.System) + .Where(f => f.Origin.Position == celestial.Coordinate.Position) + .Where(f => f.Origin.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + .ToList(); + if (transportfleet2.Count() > 0) { + interval = (long) (transportfleet2.First().BackIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + } } if (interval == long.MaxValue || interval == long.MinValue) @@ -525,17 +779,19 @@ private async Task CalcAutoMineTimer(Celestial celestial, Buildables build .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - var returningExpoOrigin = _calculationService.GetFirstReturningExpedition(origin.Coordinate, _tbotInstance.UserData.fleets); - if (returningExpoOrigin != null) { - returningExpoOriginTime = (long) (returningExpoOrigin.BackIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo); - //DoLog(LogLevel.Debug, $"Next expedition returning in transport origin celestial by {now.AddMilliseconds(returningExpoOriginTime).ToString()}"); - } + if (origin.ID != 0) { + var returningExpoOrigin = _calculationService.GetFirstReturningExpedition(origin.Coordinate, _tbotInstance.UserData.fleets); + if (returningExpoOrigin != null) { + returningExpoOriginTime = (long) (returningExpoOrigin.BackIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo); + //DoLog(LogLevel.Debug, $"Next expedition returning in transport origin celestial by {now.AddMilliseconds(returningExpoOriginTime).ToString()}"); + } - var incomingOriginFleets = _calculationService.GetIncomingFleetsWithResources(origin, _tbotInstance.UserData.fleets); - if (incomingOriginFleets.Any()) { - var fleet = incomingOriginFleets.First(); - transportOriginTime = ((fleet.Mission == Missions.Transport || fleet.Mission == Missions.Deploy) && !fleet.ReturnFlight ? (long) fleet.ArriveIn : (long) fleet.BackIn) * 1000; - //DoLog(LogLevel.Debug, $"Next fleet with resources arriving in transport origin celestial by {DateTime.Now.AddMilliseconds(transportOriginTime).ToString()}"); + var incomingOriginFleets = _calculationService.GetIncomingFleetsWithResources(origin, _tbotInstance.UserData.fleets); + if (incomingOriginFleets.Any()) { + var fleet = incomingOriginFleets.First(); + transportOriginTime = ((fleet.Mission == Missions.Transport || fleet.Mission == Missions.Deploy) && !fleet.ReturnFlight ? (long) fleet.ArriveIn : (long) fleet.BackIn) * 1000; + //DoLog(LogLevel.Debug, $"Next fleet with resources arriving in transport origin celestial by {DateTime.Now.AddMilliseconds(transportOriginTime).ToString()}"); + } } } diff --git a/TBot/Workers/Brain/AutoMineWorker.cs b/TBot/Workers/Brain/AutoMineWorker.cs index 250b8ccd..0fe83276 100644 --- a/TBot/Workers/Brain/AutoMineWorker.cs +++ b/TBot/Workers/Brain/AutoMineWorker.cs @@ -110,15 +110,15 @@ protected override async Task Execute() { cel = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBuildings); cel = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses); Planet abaCelestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Fast) as Planet; - - //var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxMetalMine, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxCrystalMine, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.MaxDeuteriumSynthetizer, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); - var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, int.MaxValue, int.MaxValue, int.MaxValue, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); - var lv = _calculationService.GetNextLevel(cel, nextMine); - var DOIR = _calculationService.CalcNextDaysOfInvestmentReturn(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull); - DoLog(LogLevel.Debug, $"Celestial {cel.ToString()}: Next Mine: {nextMine.ToString()} lv {lv.ToString()}; DOIR: {DOIR.ToString()}."); - if (DOIR < _tbotInstance.UserData.nextDOIR || _tbotInstance.UserData.nextDOIR == 0) { - _tbotInstance.UserData.nextDOIR = DOIR; - } + var nextMine = _calculationService.GetNextMineToBuild(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, maxBuildings.MetalMine, maxBuildings.CrystalMine, maxBuildings.DeuteriumSynthesizer, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull, true, int.MaxValue); + if (nextMine != Buildables.Null) { + var lv = _calculationService.GetNextLevel(cel, nextMine); + var DOIR = _calculationService.CalcNextDaysOfInvestmentReturn(cel as Planet, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData.Speed, 1, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.IsFull); + DoLog(LogLevel.Debug, $"Celestial {cel.ToString()}: Next Mine: {nextMine.ToString()} lv {lv.ToString()}; DOIR: {DOIR.ToString()}."); + if (DOIR < _tbotInstance.UserData.nextDOIR || _tbotInstance.UserData.nextDOIR == 0) { + _tbotInstance.UserData.nextDOIR = DOIR; + } + } if (celestial.Coordinate.Type == Celestials.Planet && celestial.Fields.Built == 0 && (bool) _tbotInstance.InstanceSettings.AutoColonize.Abandon.Active) { if (_calculationService.ShouldAbandon(celestial as Planet, celestial.Fields.Total, abaCelestial.Temperature.Max, fieldsSettings, temperaturesSettings)) { DoLog(LogLevel.Debug, $"Skipping {celestial.ToString()}: planet should be abandoned."); diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 473bff65..f205c34b 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -90,6 +90,8 @@ protected override async Task Execute() { celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Facilities) as Planet; celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Resources) as Planet; celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.ResourcesProduction) as Planet; + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses) as Planet; + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Ships) as Planet; Buildables research; @@ -161,6 +163,7 @@ protected override async Task Execute() { int level = _calculationService.GetNextLevel(_tbotInstance.UserData.researches, research); if (research != Buildables.Null) { celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Resources) as Planet; + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Ships) as Planet; Resources cost = _calculationService.CalcPrice(research, level); if (celestial.Resources.IsEnoughFor(cost)) { try { @@ -172,35 +175,281 @@ protected override async Task Execute() { } else { DoLog(LogLevel.Information, $"Not enough resources to build: {research.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {cost.TransportableResources} - Available: {celestial.Resources.TransportableResources}"); if ((bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Transports.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active) { + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { - Celestial origin = _tbotInstance.UserData.celestials - .Unique() - .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) - .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) - .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) - .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) - .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, cost, Buildables.Null); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; + List rankSlotsPriority = new(); + RankSlotsPriority BrainRank = new(Feature.BrainAutoResearch, + (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && + (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); + RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); + RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); + RankSlotsPriority ColonizeRank = new(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); + RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); + RankSlotsPriority presentFeature = BrainRank; + rankSlotsPriority.Add(BrainRank); + rankSlotsPriority.Add(ExpeditionsRank); + rankSlotsPriority.Add(AutoFarmRank); + rankSlotsPriority.Add(ColonizeRank); + rankSlotsPriority.Add(AutoDiscoveryRank); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + string msg = ""; + int reservedSlots = 0; + int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; + int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery) + ).Count(); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + foreach (RankSlotsPriority feature in rankSlotsPriority) { + if (feature == presentFeature) + continue; + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + if (feature.Active && feature.HasPriorityOn(presentFeature)) { + msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; + reservedSlots += feature.MaxSlots; + } else { + otherSlots += feature.SlotsUsed; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + } + if (otherSlots > 0) + msg = $"{msg}, {otherSlots} are used for Other"; + int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; + tempsValue = tempsValue < 0 ? 0 : tempsValue; + DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); + if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); + MaxSlots = 0; + } else if (MaxSlots > tempsValue) { + MaxSlots = tempsValue; + DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); + } + + if (MaxSlots > 0) { + if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { + Celestial origin; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + .SingleOrDefault() ?? new() { ID = 0 }; + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, cost, Buildables.Null); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } + + if (fleetId <= 0) { + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active) { + var resultOrigins = new Dictionary(); + List allCelestials = _tbotInstance.UserData.celestials; + List celestialsToExclude = _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Exclude, allCelestials); + for (int i = 0; i < allCelestials.Count(); i++) { + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + } + List closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons ? + allCelestials + .Where(planet => !celestialsToExclude.Has(planet)) + .Where(planet => planet.Resources.TotalResources > 0) + .Where(planet => planet.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) + .ToList(): + allCelestials + .Where(c => !celestialsToExclude.Has(c)) + .Where(c => c.Resources.TotalResources > 0) + .Where(c => c.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) + .ToList(); + + closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity ? + closestCelestials.OrderBy(c => _calculationService.CalcDistance(c.Coordinate, celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList() : + closestCelestials.OrderByDescending(c => c.Resources.TotalResources).ToList(); + + Resources missingResources = cost.Difference(celestial.Resources); + Resources resourcesTotalAvailable = new(); + Resources possibleResources = new(); + + Celestial destination; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + destination = allCelestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .First(); + } else { + destination = allCelestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) + .First(); + } + if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { + DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); + return; + } + + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; + } + long idealShips; + + foreach (var possibleOrigin in closestCelestials) { + //if (!celestialsToExclude.Has(possibleOrigin)) // if .Where(planet => !celestialsToExclude.Has(planet)) don't work + if (!_calculationService.IsThereTransportTowardsCelestial(possibleOrigin, _tbotInstance.UserData.fleets)) + possibleResources = possibleResources.Sum(possibleOrigin.Resources); + } + if (!possibleResources.IsEnoughFor(cost)) { + possibleResources = possibleResources.Sum(celestial.Resources); + DoLog(LogLevel.Information, $"Not enough resources available on all celestials to build: {research.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {cost.TransportableResources} - Available: {possibleResources.TransportableResources}"); + return; + } + + Celestial moonDestination = new(); + foreach (var possibleOrigin in closestCelestials) { + possibleResources = new(); + Celestial tempPossibleOrigin = possibleOrigin; + tempPossibleOrigin.Resources.Deuterium = (tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) > 0 ? tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave : 0; + if (tempPossibleOrigin.Resources.Metal < missingResources.Metal - resourcesTotalAvailable.Metal) + possibleResources.Metal = tempPossibleOrigin.Resources.Metal; + else + possibleResources.Metal = missingResources.Metal - resourcesTotalAvailable.Metal; + if (tempPossibleOrigin.Resources.Crystal < missingResources.Crystal - resourcesTotalAvailable.Crystal) + possibleResources.Crystal = tempPossibleOrigin.Resources.Crystal; + else + possibleResources.Crystal = missingResources.Crystal - resourcesTotalAvailable.Crystal; + if (tempPossibleOrigin.Resources.Deuterium < missingResources.Deuterium - resourcesTotalAvailable.Deuterium) + possibleResources.Deuterium = tempPossibleOrigin.Resources.Deuterium; + else + possibleResources.Deuterium = missingResources.Deuterium - resourcesTotalAvailable.Deuterium; + + idealShips = _calculationService.CalcShipNumberForPayload(possibleResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (idealShips > possibleOrigin.Ships.GetAmount(preferredShip) || + possibleResources.TotalResources <= (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend || + _calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)) + continue; + + resourcesTotalAvailable = resourcesTotalAvailable.Sum(possibleResources); + resultOrigins.Add(tempPossibleOrigin, possibleResources); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{tempPossibleOrigin.ToString()} add with {possibleResources.TotalResources} - ({resultOrigins.Count}) {_calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)}"); + if (resourcesTotalAvailable.IsEnoughFor(missingResources)) + break; + } + + if (resultOrigins.Count > MaxSlots) { + DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {research.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + return; + } + + possibleResources = new(); + foreach (var (originMultiple, resourcesValue) in resultOrigins) { + possibleResources = possibleResources.Sum(resourcesValue); + } + if (!possibleResources.IsEnoughFor(missingResources)) { + possibleResources = possibleResources.Sum(celestial.Resources); + DoLog(LogLevel.Information, $"Not enough cargo available on all celestials to transport resources to build: {research.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {cost.TransportableResources} - Available: {possibleResources.TransportableResources}"); + return; + } + + Ships ships = new(); + var fleetID = 0; + foreach (var (originMultiple, resourcesValue) in resultOrigins) { + ships = new(); + ships.Add(preferredShip, _calculationService.CalcShipNumberForPayload(resourcesValue, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); + + fleetID = await _fleetScheduler.SendFleet(originMultiple, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, resourcesValue); + + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + return; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + return; + } + } + } else { + Celestial destination; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + destination = _tbotInstance.UserData.celestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .First(); + } else { + destination = _tbotInstance.UserData.celestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) + .First(); + } + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) + .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) + .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) + .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) + .SingleOrDefault() ?? new() { ID = 0 }; + fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, cost, Buildables.Null); if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } + } + } else { + DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); + fleetId = (_tbotInstance.UserData.fleets + .Where(f => f.Mission == Missions.Transport) + .Where(f => f.Resources.TotalResources > 0) + .Where(f => f.ReturnFlight == false) + .Where(f => f.Destination.Galaxy == celestial.Coordinate.Galaxy) + .Where(f => f.Destination.System == celestial.Coordinate.System) + .Where(f => f.Destination.Position == celestial.Coordinate.Position) + .Where(f => f.Destination.Type == celestial.Coordinate.Type) + .OrderByDescending(f => f.ArriveIn) + .FirstOrDefault() ?? new() { ID = 0 }) + .ID; } - } else { - DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); - fleetId = (_tbotInstance.UserData.fleets - .Where(f => f.Mission == Missions.Transport) - .Where(f => f.Resources.TotalResources > 0) - .Where(f => f.ReturnFlight == false) - .Where(f => f.Destination.Galaxy == celestial.Coordinate.Galaxy) - .Where(f => f.Destination.System == celestial.Coordinate.System) - .Where(f => f.Destination.Position == celestial.Coordinate.Position) - .Where(f => f.Destination.Type == celestial.Coordinate.Type) - .OrderByDescending(f => f.ArriveIn) - .FirstOrDefault() ?? new() { ID = 0 }) - .ID; } } } @@ -262,7 +511,25 @@ protected override async Task Execute() { .First(); interval = (((fleet.Mission == Missions.Transport || fleet.Mission == Missions.Deploy) ? (long) fleet.ArriveIn : (long) fleet.BackIn) * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.AutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.CheckIntervalMax); + if (fleetId > 0) { + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); + interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + } else { + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + } + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) + .Where(f => f.Destination.IsSame(celestial.Coordinate)) + .Where(f => f.Origin.Galaxy == celestial.Coordinate.Galaxy) + .Where(f => f.Origin.System == celestial.Coordinate.System) + .Where(f => f.Origin.Position == celestial.Coordinate.Position) + .Where(f => f.Origin.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + .ToList(); + if (transportfleet2.Count() > 0) { + interval = (long) (transportfleet2.First().BackIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + } + } } } if (interval <= 0) diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 63e285f3..31f8d083 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -101,6 +101,8 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBuildings); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Buildings); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Constructions); + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses); + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Ships); bool preventTechBuilding = false; if (celestial.Constructions.LFResearchCountdown > 0) { @@ -180,37 +182,279 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { DoLog(LogLevel.Information, $"Not enough resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.LFBuildingCostResources.ToString()} - Available: {celestial.Resources.LFBuildingCostResources.ToString()}"); if ((bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Transports.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active) { + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { - Celestial origin = _tbotInstance.UserData.celestials - .Unique() - .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) - .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) - .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) - .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) - .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, xCostBuildable, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; - return; - } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; - return; + List rankSlotsPriority = new(); + RankSlotsPriority BrainRank = new(Feature.BrainLifeformAutoMine, + (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && + (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); + RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); + RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); + RankSlotsPriority ColonizeRank = new(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); + RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); + RankSlotsPriority presentFeature = BrainRank; + rankSlotsPriority.Add(BrainRank); + rankSlotsPriority.Add(ExpeditionsRank); + rankSlotsPriority.Add(AutoFarmRank); + rankSlotsPriority.Add(ColonizeRank); + rankSlotsPriority.Add(AutoDiscoveryRank); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + string msg = ""; + int reservedSlots = 0; + int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; + int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery) + ).Count(); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + foreach (RankSlotsPriority feature in rankSlotsPriority) { + if (feature == presentFeature) + continue; + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + if (feature.Active && feature.HasPriorityOn(presentFeature)) { + msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; + reservedSlots += feature.MaxSlots; + } else { + otherSlots += feature.SlotsUsed; } - } else { - DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); - try { + } + if (otherSlots > 0) + msg = $"{msg}, {otherSlots} are used for Other"; + int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; + tempsValue = tempsValue < 0 ? 0 : tempsValue; + DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); + if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); + MaxSlots = 0; + } else if (MaxSlots > tempsValue) { + MaxSlots = tempsValue; + DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); + } + + if (MaxSlots > 0) { + if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { + Celestial origin; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + .SingleOrDefault() ?? new() { ID = 0 }; + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, xCostBuildable, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } + + if (fleetId <= 0) { + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active) { + var resultOrigins = new Dictionary(); + List allCelestials = _tbotInstance.UserData.celestials; + List celestialsToExclude = _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Exclude, allCelestials); + for (int i = 0; i < allCelestials.Count(); i++) { + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + } + List closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons ? + allCelestials + .Where(planet => !celestialsToExclude.Has(planet)) + .Where(planet => planet.Resources.TotalResources > 0) + .Where(planet => planet.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) + .ToList(): + allCelestials + .Where(c => !celestialsToExclude.Has(c)) + .Where(c => c.Resources.TotalResources > 0) + .Where(c => c.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) + .ToList(); + + closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity ? + closestCelestials.OrderBy(c => _calculationService.CalcDistance(c.Coordinate, celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList() : + closestCelestials.OrderByDescending(c => c.Resources.TotalResources).ToList(); + + Resources missingResources = xCostBuildable.Difference(celestial.Resources); + Resources resourcesTotalAvailable = new(); + Resources possibleResources = new(); + + Celestial destination; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + destination = allCelestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .First(); + } else { + destination = allCelestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) + .First(); + } + if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { + DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); + return; + } + + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; + } + long idealShips; + + foreach (var possibleOrigin in closestCelestials) { + //if (!celestialsToExclude.Has(possibleOrigin)) // if .Where(planet => !celestialsToExclude.Has(planet)) don't work + if (!_calculationService.IsThereTransportTowardsCelestial(possibleOrigin, _tbotInstance.UserData.fleets)) + possibleResources = possibleResources.Sum(possibleOrigin.Resources); + } + if (!possibleResources.IsEnoughFor(xCostBuildable)) { + possibleResources = possibleResources.Sum(celestial.Resources); + DoLog(LogLevel.Information, $"Not enough resources available on all celestials to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); + return; + } + + Celestial moonDestination = new(); + foreach (var possibleOrigin in closestCelestials) { + possibleResources = new(); + Celestial tempPossibleOrigin = possibleOrigin; + tempPossibleOrigin.Resources.Deuterium = (tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) > 0 ? tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave : 0; + if (tempPossibleOrigin.Resources.Metal < missingResources.Metal - resourcesTotalAvailable.Metal) + possibleResources.Metal = tempPossibleOrigin.Resources.Metal; + else + possibleResources.Metal = missingResources.Metal - resourcesTotalAvailable.Metal; + if (tempPossibleOrigin.Resources.Crystal < missingResources.Crystal - resourcesTotalAvailable.Crystal) + possibleResources.Crystal = tempPossibleOrigin.Resources.Crystal; + else + possibleResources.Crystal = missingResources.Crystal - resourcesTotalAvailable.Crystal; + if (tempPossibleOrigin.Resources.Deuterium < missingResources.Deuterium - resourcesTotalAvailable.Deuterium) + possibleResources.Deuterium = tempPossibleOrigin.Resources.Deuterium; + else + possibleResources.Deuterium = missingResources.Deuterium - resourcesTotalAvailable.Deuterium; + + idealShips = _calculationService.CalcShipNumberForPayload(possibleResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (idealShips > possibleOrigin.Ships.GetAmount(preferredShip) || + possibleResources.TotalResources <= (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend || + _calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)) + continue; + + resourcesTotalAvailable = resourcesTotalAvailable.Sum(possibleResources); + resultOrigins.Add(tempPossibleOrigin, possibleResources); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{tempPossibleOrigin.ToString()} add with {possibleResources.TotalResources} - ({resultOrigins.Count}) {_calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)}"); + if (resourcesTotalAvailable.IsEnoughFor(missingResources)) + break; + } + + if (resultOrigins.Count > MaxSlots) { + DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + return; + } + + possibleResources = new(); + foreach (var (originMultiple, resourcesValue) in resultOrigins) { + possibleResources = possibleResources.Sum(resourcesValue); + } + if (!possibleResources.IsEnoughFor(missingResources)) { + possibleResources = possibleResources.Sum(celestial.Resources); + DoLog(LogLevel.Information, $"Not enough cargo available on all celestials to transport resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); + return; + } + + Ships ships = new(); + var fleetID = 0; + foreach (var (originMultiple, resourcesValue) in resultOrigins) { + ships = new(); + ships.Add(preferredShip, _calculationService.CalcShipNumberForPayload(resourcesValue, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); + + fleetID = await _fleetScheduler.SendFleet(originMultiple, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, resourcesValue); + + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + return; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + return; + } + } + } else { + Celestial destination; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + destination = _tbotInstance.UserData.celestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .First(); + } else { + destination = _tbotInstance.UserData.celestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) + .First(); + } + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) + .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) + .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) + .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) + .SingleOrDefault() ?? new() { ID = 0 }; + fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, xCostBuildable, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } + } + } else { + DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); fleetId = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) - .Where(f => f.Resources.TotalResources > 0) - .Where(f => f.ReturnFlight == false) - .Where(f => f.Destination.Galaxy == celestial.Coordinate.Galaxy) - .Where(f => f.Destination.System == celestial.Coordinate.System) - .Where(f => f.Destination.Position == celestial.Coordinate.Position) - .Where(f => f.Destination.Type == celestial.Coordinate.Type) - .First().ID; + .Where(f => f.Resources.TotalResources > 0) + .Where(f => f.ReturnFlight == false) + .Where(f => f.Destination.Galaxy == celestial.Coordinate.Galaxy) + .Where(f => f.Destination.System == celestial.Coordinate.System) + .Where(f => f.Destination.Position == celestial.Coordinate.Position) + .Where(f => f.Destination.Type == celestial.Coordinate.Type) + .First().ID; } - catch { } } } } @@ -283,13 +527,26 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { } } interval = productionTime + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - } - else if (fleetId != 0 && fleetId != -1 && fleetId != -2) { - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); - interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMax); + if (fleetId > 0) { + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); + interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + } else { + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + } + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) + .Where(f => f.Destination.IsSame(celestial.Coordinate)) + .Where(f => f.Origin.Galaxy == celestial.Coordinate.Galaxy) + .Where(f => f.Origin.System == celestial.Coordinate.System) + .Where(f => f.Origin.Position == celestial.Coordinate.Position) + .Where(f => f.Origin.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + .ToList(); + if (transportfleet2.Count() > 0) { + interval = (long) (transportfleet2.First().BackIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + } + } } } time = await _tbotOgameBridge.GetDateTime(); diff --git a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs index f396d81d..91fdcbfc 100644 --- a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs @@ -86,12 +86,15 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { bool delayProduction = false; long delayTime = 0; long interval = 0; + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); try { DoLog(LogLevel.Information, $"Running Lifeform AutoResearch on {celestial.ToString()}"); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Fast); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Resources); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFTechs); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Constructions); + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses); + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Ships); int maxResearchLevel = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Brain.LifeformAutoResearch, "MaxResearchLevel") ? (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.MaxResearchLevel : 1; int maxTechs11 = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Brain.LifeformAutoResearch, "MaxTechs11") ? (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.MaxTechs11 : maxResearchLevel; @@ -180,26 +183,271 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { DoLog(LogLevel.Information, $"Not enough resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.LFBuildingCostResources.ToString()} - Available: {celestial.Resources.LFBuildingCostResources.ToString()}"); if ((bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Transports.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active) { + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { - Celestial origin = _tbotInstance.UserData.celestials - .Unique() - .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) - .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) - .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) - .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) - .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, xCostBuildable, Buildables.Null); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; - return; + List rankSlotsPriority = new(); + RankSlotsPriority BrainRank = new(Feature.BrainLifeformAutoResearch, + (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && + (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); + RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); + RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); + RankSlotsPriority ColonizeRank = new(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); + RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); + RankSlotsPriority presentFeature = BrainRank; + rankSlotsPriority.Add(BrainRank); + rankSlotsPriority.Add(ExpeditionsRank); + rankSlotsPriority.Add(AutoFarmRank); + rankSlotsPriority.Add(ColonizeRank); + rankSlotsPriority.Add(AutoDiscoveryRank); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + string msg = ""; + int reservedSlots = 0; + int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; + int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery) + ).Count(); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + foreach (RankSlotsPriority feature in rankSlotsPriority) { + if (feature == presentFeature) + continue; + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + if (feature.Active && feature.HasPriorityOn(presentFeature)) { + msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; + reservedSlots += feature.MaxSlots; + } else { + otherSlots += feature.SlotsUsed; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; - return; + } + if (otherSlots > 0) + msg = $"{msg}, {otherSlots} are used for Other"; + int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; + tempsValue = tempsValue < 0 ? 0 : tempsValue; + DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); + if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); + MaxSlots = 0; + } else if (MaxSlots > tempsValue) { + MaxSlots = tempsValue; + DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); + } + + if (MaxSlots > 0) { + if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { + Celestial origin; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + .SingleOrDefault() ?? new() { ID = 0 }; + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, xCostBuildable, LFBuildables.None); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } + + if (fleetId <= 0) { + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active) { + var resultOrigins = new Dictionary(); + List allCelestials = _tbotInstance.UserData.celestials; + List celestialsToExclude = _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Exclude, allCelestials); + for (int i = 0; i < allCelestials.Count(); i++) { + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + } + List closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons ? + allCelestials + .Where(planet => !celestialsToExclude.Has(planet)) + .Where(planet => planet.Resources.TotalResources > 0) + .Where(planet => planet.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) + .ToList(): + allCelestials + .Where(c => !celestialsToExclude.Has(c)) + .Where(c => c.Resources.TotalResources > 0) + .Where(c => c.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) + .ToList(); + + closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity ? + closestCelestials.OrderBy(c => _calculationService.CalcDistance(c.Coordinate, celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList() : + closestCelestials.OrderByDescending(c => c.Resources.TotalResources).ToList(); + + Resources missingResources = xCostBuildable.Difference(celestial.Resources); + Resources resourcesTotalAvailable = new(); + Resources possibleResources = new(); + + Celestial destination; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + destination = allCelestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .First(); + } else { + destination = allCelestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) + .First(); + } + if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { + DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); + return; + } + + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; + } + long idealShips; + + foreach (var possibleOrigin in closestCelestials) { + //if (!celestialsToExclude.Has(possibleOrigin)) // if .Where(planet => !celestialsToExclude.Has(planet)) don't work + if (!_calculationService.IsThereTransportTowardsCelestial(possibleOrigin, _tbotInstance.UserData.fleets)) + possibleResources = possibleResources.Sum(possibleOrigin.Resources); + } + if (!possibleResources.IsEnoughFor(xCostBuildable)) { + possibleResources = possibleResources.Sum(celestial.Resources); + DoLog(LogLevel.Information, $"Not enough resources available on all celestials to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); + return; + } + + Celestial moonDestination = new(); + foreach (var possibleOrigin in closestCelestials) { + possibleResources = new(); + Celestial tempPossibleOrigin = possibleOrigin; + tempPossibleOrigin.Resources.Deuterium = (tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) > 0 ? tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave : 0; + if (tempPossibleOrigin.Resources.Metal < missingResources.Metal - resourcesTotalAvailable.Metal) + possibleResources.Metal = tempPossibleOrigin.Resources.Metal; + else + possibleResources.Metal = missingResources.Metal - resourcesTotalAvailable.Metal; + if (tempPossibleOrigin.Resources.Crystal < missingResources.Crystal - resourcesTotalAvailable.Crystal) + possibleResources.Crystal = tempPossibleOrigin.Resources.Crystal; + else + possibleResources.Crystal = missingResources.Crystal - resourcesTotalAvailable.Crystal; + if (tempPossibleOrigin.Resources.Deuterium < missingResources.Deuterium - resourcesTotalAvailable.Deuterium) + possibleResources.Deuterium = tempPossibleOrigin.Resources.Deuterium; + else + possibleResources.Deuterium = missingResources.Deuterium - resourcesTotalAvailable.Deuterium; + + idealShips = _calculationService.CalcShipNumberForPayload(possibleResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (idealShips > possibleOrigin.Ships.GetAmount(preferredShip) || + possibleResources.TotalResources <= (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend || + _calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)) + continue; + + resourcesTotalAvailable = resourcesTotalAvailable.Sum(possibleResources); + resultOrigins.Add(tempPossibleOrigin, possibleResources); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{tempPossibleOrigin.ToString()} add with {possibleResources.TotalResources} - ({resultOrigins.Count}) {_calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)}"); + if (resourcesTotalAvailable.IsEnoughFor(missingResources)) + break; + } + + if (resultOrigins.Count > MaxSlots) { + DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + return; + } + + possibleResources = new(); + foreach (var (originMultiple, resourcesValue) in resultOrigins) { + possibleResources = possibleResources.Sum(resourcesValue); + } + if (!possibleResources.IsEnoughFor(missingResources)) { + possibleResources = possibleResources.Sum(celestial.Resources); + DoLog(LogLevel.Information, $"Not enough cargo available on all celestials to transport resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); + return; + } + + Ships ships = new(); + var fleetID = 0; + foreach (var (originMultiple, resourcesValue) in resultOrigins) { + ships = new(); + ships.Add(preferredShip, _calculationService.CalcShipNumberForPayload(resourcesValue, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); + + fleetID = await _fleetScheduler.SendFleet(originMultiple, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, resourcesValue); + + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + return; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + return; + } + } + } else { + Celestial destination; + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + destination = _tbotInstance.UserData.celestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .First(); + } else { + destination = _tbotInstance.UserData.celestials + .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) + .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) + .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) + .First(); + } + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) + .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) + .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) + .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) + .SingleOrDefault() ?? new() { ID = 0 }; + fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, xCostBuildable, LFBuildables.None); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } + } + } else { + DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); } - } else { - DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); } } } @@ -232,12 +480,24 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { } else if (started) { interval = ((long) celestial.Constructions.LFResearchCountdown * (long) 1000) + (long) RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds); } else { - if (fleetId != 0 && fleetId != -1 && fleetId != -2) { - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + if (fleetId > 0) { + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMax); + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + } + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) + .Where(f => f.Destination.IsSame(celestial.Coordinate)) + .Where(f => f.Origin.Galaxy == celestial.Coordinate.Galaxy) + .Where(f => f.Origin.System == celestial.Coordinate.System) + .Where(f => f.Origin.Position == celestial.Coordinate.Position) + .Where(f => f.Origin.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + .ToList(); + if (transportfleet2.Count() > 0) { + interval = (long) (transportfleet2.First().BackIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + } } } diff --git a/TBot/Workers/ColonizeWorker.cs b/TBot/Workers/ColonizeWorker.cs index b10ec365..912ddb29 100644 --- a/TBot/Workers/ColonizeWorker.cs +++ b/TBot/Workers/ColonizeWorker.cs @@ -98,7 +98,83 @@ protected override async Task Execute() { if (currentPlanets + slotsToLeaveFree < maxPlanets) { _tbotInstance.log(LogLevel.Information, LogSender.Colonize, "A new planet is needed."); + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + List rankSlotsPriority = new(); + RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && + (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); + RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); + RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); + RankSlotsPriority ColonizeRank = new(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); + RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); + RankSlotsPriority presentFeature = ColonizeRank; + rankSlotsPriority.Add(BrainRank); + rankSlotsPriority.Add(ExpeditionsRank); + rankSlotsPriority.Add(AutoFarmRank); + rankSlotsPriority.Add(ColonizeRank); + rankSlotsPriority.Add(AutoDiscoveryRank); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + string msg = ""; + int reservedSlots = 0; + int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; + int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery) + ).Count(); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + foreach (RankSlotsPriority feature in rankSlotsPriority) { + if (feature == presentFeature) + continue; + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + if (feature.Active && feature.HasPriorityOn(presentFeature)) { + msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; + reservedSlots += feature.MaxSlots; + } else { + otherSlots += feature.SlotsUsed; + } + } + if (otherSlots > 0) + msg = $"{msg}, {otherSlots} are used for Other"; + int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; + tempsValue = tempsValue < 0 ? 0 : tempsValue; + DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); + if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); + MaxSlots = 0; + } else if (MaxSlots > tempsValue) { + MaxSlots = tempsValue; + DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); + } + if ( (!(bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active && _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize && !f.ReturnFlight) >= maxPlanets - currentPlanets) || ((bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active && _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize && !f.ReturnFlight) > 0) @@ -169,7 +245,7 @@ protected override async Task Execute() { } filteredTargets = (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? filteredTargetsRdm - .Take((int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots) + .Take(MaxSlots) .ToList() : filteredTargetsRdm .Take(maxPlanets - currentPlanets) @@ -178,7 +254,7 @@ protected override async Task Execute() { filteredTargets = (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? filteredTargets .OrderBy(t => _calculationService.CalcDistance(origin.Coordinate, t, _tbotInstance.UserData.serverData)) - .Take((int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots) + .Take(MaxSlots) .ToList() : filteredTargets .OrderBy(t => _calculationService.CalcDistance(origin.Coordinate, t, _tbotInstance.UserData.serverData)) diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index 1cca098c..7df7a5ad 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -75,6 +75,81 @@ protected override async Task Execute() { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); _tbotInstance.UserData.serverData = await _ogameService.GetServerData(); + List rankSlotsPriority = new(); + RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && + (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); + RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); + RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); + RankSlotsPriority ColonizeRank = new(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); + RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); + RankSlotsPriority presentFeature = ExpeditionsRank; + rankSlotsPriority.Add(BrainRank); + rankSlotsPriority.Add(ExpeditionsRank); + rankSlotsPriority.Add(AutoFarmRank); + rankSlotsPriority.Add(ColonizeRank); + rankSlotsPriority.Add(AutoDiscoveryRank); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + string msg = ""; + int reservedSlots = 0; + int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; + int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery) + ).Count(); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + foreach (RankSlotsPriority feature in rankSlotsPriority) { + if (feature == presentFeature) + continue; + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + if (feature.Active && feature.HasPriorityOn(presentFeature)) { + msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; + reservedSlots += feature.MaxSlots; + } else { + otherSlots += feature.SlotsUsed; + } + } + if (otherSlots > 0) + msg = $"{msg}, {otherSlots} are used for Other"; + int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; + tempsValue = tempsValue < 0 ? 0 : tempsValue; + DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); + if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); + MaxSlots = 0; + } else if (MaxSlots > tempsValue) { + MaxSlots = tempsValue; + DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); + } + int expsToSend; if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForAllExpeditions") && (bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { if (_tbotInstance.UserData.slots.ExpInUse == 0) @@ -91,7 +166,7 @@ protected override async Task Execute() { expsToSend = 0; } } - + expsToSend = expsToSend < MaxSlots ? expsToSend : MaxSlots; if (expsToSend > 0) { if (_tbotInstance.UserData.slots.ExpFree > 0) { if (_tbotInstance.UserData.slots.Free > 0) { @@ -137,6 +212,8 @@ protected override async Task Execute() { if ((bool) _tbotInstance.InstanceSettings.Expeditions.RandomizeOrder) { origins = origins.Shuffle().ToList(); } + + LFBonuses lfBonuses = origins.First().LFBonuses; Dictionary originExps = new(); int quot = (int) Math.Floor((float) expsToSend / (float) origins.Count()); foreach (var origin in origins) { @@ -146,7 +223,6 @@ protected override async Task Execute() { for (int i = 0; i < rest; i++) { originExps[origins[i]]++; } - LFBonuses lfBonuses = origins.First().LFBonuses; int delayExpedition = 0; foreach (var origin in originExps.Keys) { int expsToSendFromThisOrigin = originExps[origin]; @@ -191,7 +267,6 @@ protected override async Task Execute() { Buildables primaryShip = Buildables.LargeCargo; if (!Enum.TryParse(_tbotInstance.InstanceSettings.Expeditions.PrimaryShip.ToString(), true, out primaryShip)) { DoLog(LogLevel.Warning, "Unable to parse PrimaryShip. Falling back to default LargeCargo"); - delayExpedition++; primaryShip = Buildables.LargeCargo; } if (primaryShip == Buildables.Null) { diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 93a764da..9e8432d6 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -789,7 +789,6 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat tempShips.Add(preferredShip, 1); var flightPrediction = _calcService.CalcFleetPrediction(origin.Coordinate, destination.Coordinate, tempShips, Missions.Transport, Speeds.HundredPercent, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.allianceClass); long flightTime = flightPrediction.Time; - idealShips = _calcService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, cargoBonus, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); var availableShips = origin.Ships.GetAmount(preferredShip); if (buildable != Buildables.Null) { int level = _calcService.GetNextLevel(destination, buildable); @@ -842,8 +841,19 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat idealShips = _calcService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, cargoBonus, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); } - if (idealShips <= origin.Ships.GetAmount(preferredShip)) { - ships.Add(preferredShip, idealShips); + bool doMultipleTransports = (idealShips > origin.Ships.GetAmount(preferredShip) && (bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) && + (origin.Coordinate.Galaxy == destination.Coordinate.Galaxy && + origin.Coordinate.System == destination.Coordinate.System && + origin.Coordinate.Position == destination.Coordinate.Position) ? + true: + false; + + if (idealShips <= origin.Ships.GetAmount(preferredShip) || (doMultipleTransports && !origin.Ships.IsEmpty())) { + if (doMultipleTransports) { + ships.Add(preferredShip, origin.Ships.GetAmount(preferredShip)); + } else { + ships.Add(preferredShip, idealShips); + } if (destination.Coordinate.Type == Celestials.Planet) { destination = await _tbotOgameBridge.UpdatePlanet(destination, UpdateTypes.ResourceSettings); @@ -883,8 +893,8 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat return 0; } } else { - _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping transport: not enough resources in origin. Needed: {missingResources.TransportableResources} - Available: {origin.Resources.TransportableResources}"); - return 0; + _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping transport: not enough resources in {origin.ToString()}. Needed: {missingResources.TransportableResources} - Available: {origin.Resources.TransportableResources}"); + return (int) SendFleetCode.NotEnoughRessources; } } } catch (Exception e) { @@ -981,8 +991,19 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat idealShips = _calcService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, cargoBonus, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); } - if (idealShips <= origin.Ships.GetAmount(preferredShip)) { - ships.Add(preferredShip, idealShips); + bool doMultipleTransports = (idealShips > origin.Ships.GetAmount(preferredShip) && (bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) && + (origin.Coordinate.Galaxy == destination.Coordinate.Galaxy && + origin.Coordinate.System == destination.Coordinate.System && + origin.Coordinate.Position == destination.Coordinate.Position) ? + true: + false; + + if (idealShips <= origin.Ships.GetAmount(preferredShip) || (doMultipleTransports && !origin.Ships.IsEmpty())) { + if (doMultipleTransports) { + ships.Add(preferredShip, origin.Ships.GetAmount(preferredShip)); + } else { + ships.Add(preferredShip, idealShips); + } if (destination.Coordinate.Type == Celestials.Planet) { destination = await _tbotOgameBridge.UpdatePlanet(destination, UpdateTypes.ResourceSettings); @@ -1022,8 +1043,8 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat return 0; } } else { - _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping transport: not enough resources in origin. Needed: {missingResources.TransportableResources} - Available: {origin.Resources.TransportableResources}"); - return 0; + _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping transport: not enough resources in {origin.ToString()}. Needed: {missingResources.TransportableResources} - Available: {origin.Resources.TransportableResources}"); + return (int) SendFleetCode.NotEnoughRessources; } } } catch (Exception e) { @@ -1121,8 +1142,6 @@ public async Task CollectDeut(long MinAmount = 0) { } public async Task CollectImpl(bool fromTelegram) { - bool stop = false; - bool delay = false; try { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, "Repatriating resources..."); @@ -1134,16 +1153,35 @@ public async Task CollectImpl(bool fromTelegram) { long TotalMet = 0; long TotalCri = 0; long TotalDeut = 0; - Coordinate destinationCoordinate = new( - (int) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Galaxy, - (int) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.System, - (int) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Position, - Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Type) - ); + bool samePosition = (bool) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.TargetAssociateMoon; + Coordinate destinationCoordinate = new(); + if (!samePosition) { + destinationCoordinate = new( + (int) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Galaxy, + (int) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.System, + (int) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Position, + Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Type) + ); + } List newCelestials = _tbotInstance.UserData.celestials.ToList(); List celestialsToExclude = _calcService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.AutoRepatriate.Exclude, _tbotInstance.UserData.celestials); - - foreach (Celestial celestial in (bool) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.RandomOrder ? _tbotInstance.UserData.celestials.Shuffle().ToList() : _tbotInstance.UserData.celestials.OrderBy(c => _calcService.CalcDistance(c.Coordinate, destinationCoordinate, _tbotInstance.UserData.serverData)).ToList()) { + List celestialList = _tbotInstance.UserData.celestials.ToList(); + if (!samePosition) + celestialList = (bool) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.RandomOrder ? celestialList.Shuffle().ToList() : celestialList.OrderBy(c => _calcService.CalcDistance(c.Coordinate, destinationCoordinate, _tbotInstance.UserData.serverData)).ToList(); + + foreach (Celestial celestial in celestialList) { + if (samePosition) { + if (celestial.Coordinate.Type == Celestials.Planet && !_calcService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { + _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping {celestial.ToString()}: There is no moon."); + continue; + } + destinationCoordinate = new( + (int) celestial.Coordinate.Galaxy, + (int) celestial.Coordinate.System, + (int) celestial.Coordinate.Position, + celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet + ); + } if (celestialsToExclude.Has(celestial)) { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping {celestial.ToString()}: celestial in exclude list."); continue; @@ -1202,15 +1240,13 @@ public async Task CollectImpl(bool fromTelegram) { ships.Add(preferredShip, tempCelestial.Ships.GetAmount(preferredShip)); } payload = _calcService.CalcMaxTransportableResources(ships, payload, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, tempCelestial.LFBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - + if (payload.TotalResources > 0) { var fleetId = await SendFleet(tempCelestial, ships, destinationCoordinate, Missions.Transport, Speeds.HundredPercent, payload); if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; return RepatriateCode.Stop; } if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; return RepatriateCode.Delay; } TotalMet += payload.Metal; diff --git a/TBot/Workers/HarvestWorker.cs b/TBot/Workers/HarvestWorker.cs index ba70ca2d..9b9be114 100644 --- a/TBot/Workers/HarvestWorker.cs +++ b/TBot/Workers/HarvestWorker.cs @@ -141,10 +141,92 @@ protected override async Task Execute() { newCelestials.Add(tempCelestial); } _tbotInstance.UserData.celestials = newCelestials; + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + List rankSlotsPriority = new(); + RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && + (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); + RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); + RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); + RankSlotsPriority ColonizeRank = new(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); + RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); + RankSlotsPriority presentFeature = new(Feature.Harvest); + rankSlotsPriority.Add(BrainRank); + rankSlotsPriority.Add(ExpeditionsRank); + rankSlotsPriority.Add(AutoFarmRank); + rankSlotsPriority.Add(ColonizeRank); + rankSlotsPriority.Add(AutoDiscoveryRank); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + string msg = ""; + int reservedSlots = 0; + int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; + int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery) + ).Count(); + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + foreach (RankSlotsPriority feature in rankSlotsPriority) { + if (feature == presentFeature) + continue; + _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + if (feature.Active && feature.HasPriorityOn(presentFeature)) { + msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; + reservedSlots += feature.MaxSlots; + } else { + otherSlots += feature.SlotsUsed; + } + } + if (otherSlots > 0) + msg = $"{msg}, {otherSlots} are used for Other"; + int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; + tempsValue = tempsValue < 0 ? 0 : tempsValue; + DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); + if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); + MaxSlots = 0; + } else { + MaxSlots = tempsValue; + } if (dic.Count() == 0) DoLog(LogLevel.Information, "Skipping harvest: there are no fields to harvest."); + if (dic.Count() > MaxSlots) { + var pairsToRemove = dic.Take(dic.Count() - MaxSlots); + foreach (var pair in pairsToRemove) { + dic.Remove(pair.Key); + } + } + foreach (Coordinate destination in dic.Keys) { var fleetId = (int) SendFleetCode.GenericError; Celestial origin = dic[destination]; diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index 5dd6ae24..f9ff3f4a 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -21,7 +21,7 @@ "Height": 1080, "Timezone": "Europe/London", "Lang": "en" - } + } }, "General": { "Host": "localhost", @@ -107,16 +107,35 @@ }, "Brain": { "Active": true, + "SlotPriorityLevel": 2, "Transports": { "Active": true, "CargoType": "SmallCargo", "DeutToLeave": 1000000, "RoundResources": true, + "SendToTheMoonIfPossible": true, "Origin": { "Galaxy": 3, "System": 333, "Position": 8, "Type": "Moon" + }, + "MaxSlots": 10, + "CheckMoonOrPlanetFirst": true, + "DoMultipleTransportIsNotEnoughShipButSamePosition": true, + "MultipleOrigins": { + "Active": false, + "OnlyFromMoons": true, + "MinimumResourcesToSend": 10000000, + "PriorityToProximityOverQuantity": true, + "Exclude": [ + { + "Galaxy": 1, + "System": 1, + "Position": 1, + "Type": "Planet" + } + ] } }, "AutoMine": { @@ -298,6 +317,7 @@ "Position": 8, "Type": "Moon" }, + "TargetAssociateMoon": true, "CargoType": "LargeCargo", "RandomOrder": true, "SkipIfIncomingTransport": true, @@ -320,6 +340,7 @@ }, "Expeditions": { "Active": true, + "SlotPriorityLevel": 1, "IgnoreSleep": false, "MinWaitNextFleet": 5, "MaxWaitNextFleet": 15, @@ -366,6 +387,7 @@ }, "AutoFarm": { "Active": true, + "SlotPriorityLevel": 0, "ExcludeMoons": true, "ScanRange": [ { @@ -421,6 +443,7 @@ }, "AutoColonize": { "Active": true, + "SlotPriorityLevel": 0, "Origin": { "Galaxy": 5, "System": 64, @@ -464,6 +487,7 @@ }, "AutoDiscovery": { "Active": true, + "SlotPriorityLevel": 0, "Origin": { "Galaxy": 5, "System": 64, @@ -475,4 +499,4 @@ "CheckIntervalMin": 30, "CheckIntervalMax": 60 } -} +} \ No newline at end of file From 74f46135ec8a460723ec0b5fe806110466e515f7 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Mon, 25 Nov 2024 16:32:14 +0100 Subject: [PATCH 018/117] remove debug log --- TBot/Workers/AutoDiscoveryWorker.cs | 4 ++-- TBot/Workers/AutoFarmWorker.cs | 4 ++-- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 4 ++-- TBot/Workers/Brain/AutoResearchWorker.cs | 4 ++-- TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs | 4 ++-- TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs | 4 ++-- TBot/Workers/ColonizeWorker.cs | 4 ++-- TBot/Workers/ExpeditionsWorker.cs | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index d8554e36..eba4669f 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -97,11 +97,11 @@ protected override async Task Execute() { fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery) ).Count(); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); foreach (RankSlotsPriority feature in rankSlotsPriority) { if (feature == presentFeature) continue; - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); if (feature.Active && feature.HasPriorityOn(presentFeature)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; diff --git a/TBot/Workers/AutoFarmWorker.cs b/TBot/Workers/AutoFarmWorker.cs index 4aa4b21b..fbcf30f0 100644 --- a/TBot/Workers/AutoFarmWorker.cs +++ b/TBot/Workers/AutoFarmWorker.cs @@ -632,11 +632,11 @@ protected override async Task Execute() { fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery) ).Count(); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); foreach (RankSlotsPriority feature in rankSlotsPriority) { if (feature == presentFeature) continue; - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); if (feature.Active && feature.HasPriorityOn(presentFeature)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index 7d119956..37837e48 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -354,11 +354,11 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery) ).Count(); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); foreach (RankSlotsPriority feature in rankSlotsPriority) { if (feature == presentFeature) continue; - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); if (feature.Active && feature.HasPriorityOn(presentFeature)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index f205c34b..02a03a60 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -227,11 +227,11 @@ protected override async Task Execute() { fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery) ).Count(); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); foreach (RankSlotsPriority feature in rankSlotsPriority) { if (feature == presentFeature) continue; - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); if (feature.Active && feature.HasPriorityOn(presentFeature)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 31f8d083..76815b53 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -234,11 +234,11 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery) ).Count(); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); foreach (RankSlotsPriority feature in rankSlotsPriority) { if (feature == presentFeature) continue; - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); if (feature.Active && feature.HasPriorityOn(presentFeature)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; diff --git a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs index 91fdcbfc..1cb19b36 100644 --- a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs @@ -235,11 +235,11 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery) ).Count(); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); foreach (RankSlotsPriority feature in rankSlotsPriority) { if (feature == presentFeature) continue; - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); if (feature.Active && feature.HasPriorityOn(presentFeature)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; diff --git a/TBot/Workers/ColonizeWorker.cs b/TBot/Workers/ColonizeWorker.cs index 912ddb29..f102cafd 100644 --- a/TBot/Workers/ColonizeWorker.cs +++ b/TBot/Workers/ColonizeWorker.cs @@ -150,11 +150,11 @@ protected override async Task Execute() { fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery) ).Count(); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); foreach (RankSlotsPriority feature in rankSlotsPriority) { if (feature == presentFeature) continue; - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); if (feature.Active && feature.HasPriorityOn(presentFeature)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index 7df7a5ad..12d9a3a0 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -125,11 +125,11 @@ protected override async Task Execute() { fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery) ).Count(); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); foreach (RankSlotsPriority feature in rankSlotsPriority) { if (feature == presentFeature) continue; - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); + //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); if (feature.Active && feature.HasPriorityOn(presentFeature)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; From c51d57916b952b628d79afc0d9bc925c2f5d8fb6 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Wed, 27 Nov 2024 14:08:18 +0100 Subject: [PATCH 019/117] update discovery & brain interval --- TBot/Workers/AutoDiscoveryWorker.cs | 4 ++-- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 5 +++++ TBot/Workers/Brain/AutoResearchWorker.cs | 5 +++++ TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs | 5 +++++ TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs | 5 +++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index eba4669f..9afeaba0 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -232,11 +232,11 @@ protected override async Task Execute() { DoLog(LogLevel.Information, $"Stopping feature."); await EndExecution(); } else { - long interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + long interval = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); if (delay) { DoLog(LogLevel.Information, $"Delaying..."); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - interval = interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax); + interval = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } if (interval <= 0) interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index 37837e48..8f558c95 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -438,6 +438,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .First(); + missingResources = xCostBuildable.Difference(destination.Resources); } else { destination = allCelestials .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) @@ -446,6 +447,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) .First(); } + closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); return; @@ -502,6 +504,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings if (resultOrigins.Count > MaxSlots) { DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + delay = true; return; } @@ -567,6 +570,8 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings } else { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); } + } else { + delay = true; } } } diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 02a03a60..446c8cb1 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -311,6 +311,7 @@ protected override async Task Execute() { .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .First(); + missingResources = cost.Difference(destination.Resources); } else { destination = allCelestials .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) @@ -319,6 +320,7 @@ protected override async Task Execute() { .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) .First(); } + closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); return; @@ -375,6 +377,7 @@ protected override async Task Execute() { if (resultOrigins.Count > MaxSlots) { DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {research.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + delay = true; return; } @@ -450,6 +453,8 @@ protected override async Task Execute() { .FirstOrDefault() ?? new() { ID = 0 }) .ID; } + } else { + delay = true; } } } diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 76815b53..03900ca4 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -318,6 +318,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .First(); + missingResources = xCostBuildable.Difference(destination.Resources); } else { destination = allCelestials .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) @@ -326,6 +327,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) .First(); } + closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); return; @@ -382,6 +384,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { if (resultOrigins.Count > MaxSlots) { DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + delay = true; return; } @@ -455,6 +458,8 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .Where(f => f.Destination.Type == celestial.Coordinate.Type) .First().ID; } + } else { + delay = true; } } } diff --git a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs index 1cb19b36..23efb46d 100644 --- a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs @@ -319,6 +319,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .First(); + missingResources = xCostBuildable.Difference(destination.Resources); } else { destination = allCelestials .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) @@ -327,6 +328,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) .First(); } + closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); return; @@ -383,6 +385,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { if (resultOrigins.Count > MaxSlots) { DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + delay = true; return; } @@ -448,6 +451,8 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { } else { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); } + } else { + delay = true; } } } From b319ef97271157cded779f3eaf6d69a643c9ac0c Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 28 Nov 2024 16:05:20 +0100 Subject: [PATCH 020/117] * update ogame-wrapper --- ogame | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ogame b/ogame index a42f3436..3f648fad 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit a42f3436e51fd2b3096f8714a3e4469e4383363c +Subproject commit 3f648fad63acfc703b48c225e1a58fc70ccdf411 From c85fb30cab3bc12751b8a9889cd234072bed42fb Mon Sep 17 00:00:00 2001 From: 0xE232FE Date: Wed, 5 Feb 2025 17:45:15 +0100 Subject: [PATCH 021/117] Update release.yml * fix develop version of osx-arm64 build process --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 190bb4db..7f8c0d27 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -126,7 +126,7 @@ jobs: - name: Build ogamed osx-arm64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed - env GOOS=darwin GOARCH=amd64 go build -o ogamed + env GOOS=darwin GOARCH=amr64 go build -o ogamed cd ${{ github.workspace }} mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/osx-arm64/ chmod +x ${{ github.workspace }}/publish/osx-arm64/TBot From 83266fb551dcef84afe7d085714968082449ef16 Mon Sep 17 00:00:00 2001 From: 0xE232FE Date: Wed, 5 Feb 2025 17:47:32 +0100 Subject: [PATCH 022/117] Update release.yml typo --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7f8c0d27..09ad5c50 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -126,7 +126,7 @@ jobs: - name: Build ogamed osx-arm64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed - env GOOS=darwin GOARCH=amr64 go build -o ogamed + env GOOS=darwin GOARCH=arm64 go build -o ogamed cd ${{ github.workspace }} mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/osx-arm64/ chmod +x ${{ github.workspace }}/publish/osx-arm64/TBot From fd7a8d69e543e1cbfea3d06f3cb55075c378b5b9 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Sun, 16 Feb 2025 10:43:33 +0100 Subject: [PATCH 023/117] fix autoFarm probe --- .../Models/EspionageReport.cs | 27 +++++++++++++++++-- TBot/Workers/AutoFarmWorker.cs | 5 +++- TBot/Workers/ExpeditionsWorker.cs | 7 ++++- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/TBot.Ogame.Infrastructure/Models/EspionageReport.cs b/TBot.Ogame.Infrastructure/Models/EspionageReport.cs index 051f5a75..88298908 100644 --- a/TBot.Ogame.Infrastructure/Models/EspionageReport.cs +++ b/TBot.Ogame.Infrastructure/Models/EspionageReport.cs @@ -112,8 +112,8 @@ public override string ToString() { /// Get whether or not the scanned planet has any defence (either ships or defence) against an attack. /// /// Returns true if the target is defenceless, false otherwise. - public bool IsDefenceless() { - if (HasDefensesInformation && HasFleetInformation) { + public bool IsDefenceless(bool isUsingProbes = false) { + if (HasDefensesInformation && HasFleetInformation && !isUsingProbes) { return LightFighter == null && HeavyFighter == null && Cruiser == null @@ -135,6 +135,29 @@ public bool IsDefenceless() { && PlasmaTurret == null && SmallShieldDome == null && LargeShieldDome == null; + } else if (HasDefensesInformation && HasFleetInformation && isUsingProbes) { + return SolarSatellite == null + && LightFighter == null + && HeavyFighter == null + && Cruiser == null + && Battleship == null + && Battlecruiser == null + && Bomber == null + && Destroyer == null + && Deathstar == null + && SmallCargo == null + && LargeCargo == null + && Recycler == null + && Reaper == null + && Pathfinder == null + && RocketLauncher == null + && LightLaser == null + && HeavyLaser == null + && GaussCannon == null + && IonCannon == null + && PlasmaTurret == null + && SmallShieldDome == null + && LargeShieldDome == null; } return false; } diff --git a/TBot/Workers/AutoFarmWorker.cs b/TBot/Workers/AutoFarmWorker.cs index fbcf30f0..cd5665cf 100644 --- a/TBot/Workers/AutoFarmWorker.cs +++ b/TBot/Workers/AutoFarmWorker.cs @@ -1012,6 +1012,9 @@ private async Task AutoFarmProcessReports() { continue; } + Buildables cargoShip; + Enum.TryParse((string) _tbotInstance.InstanceSettings.AutoFarm.CargoType, true, out cargoShip); + bool isUsingProbes = cargoShip == Buildables.EspionageProbe && _tbotInstance.UserData.serverData.ProbeCargo == 1 ? true : false; newFarmTarget.Report = report; if (_tbotInstance.InstanceSettings.AutoFarm.PreferedResource == "Metal" && report.Loot(_tbotInstance.UserData.userInfo.Class).Metal > _tbotInstance.InstanceSettings.AutoFarm.MinimumResources || _tbotInstance.InstanceSettings.AutoFarm.PreferedResource == "Crystal" && report.Loot(_tbotInstance.UserData.userInfo.Class).Crystal > _tbotInstance.InstanceSettings.AutoFarm.MinimumResources @@ -1026,7 +1029,7 @@ private async Task AutoFarmProcessReports() { newFarmTarget.State = FarmState.ProbesRequired; _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Need more probes on {report.Coordinate}. Loot: {report.Loot(_tbotInstance.UserData.userInfo.Class)}"); - } else if (report.IsDefenceless()) { + } else if (report.IsDefenceless(isUsingProbes)) { newFarmTarget.State = FarmState.AttackPending; _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Attack pending on {report.Coordinate}. Loot: {report.Loot(_tbotInstance.UserData.userInfo.Class)}"); } else { diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index 12d9a3a0..9d1ebee3 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -281,8 +281,13 @@ protected override async Task Execute() { } DoLog(LogLevel.Warning, $"Available {primaryShip.ToString()} in origin {origin.ToString()}: {availableShips.GetAmount(primaryShip)} ({_tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep} must be kept at dock)"); fleet = _calculationService.CalcFullExpeditionShips(availableShips, primaryShip, expsToSendFromThisOrigin, _tbotInstance.UserData.serverData, _tbotInstance.UserData.researches, lfBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (fleet.GetAmount(primaryShip) < (long) _tbotInstance.InstanceSettings.Expeditions.MinPrimaryToSend) { + if (fleet.GetAmount(primaryShip) < (long) _tbotInstance.InstanceSettings.Expeditions.MinPrimaryToSend || availableShips.GetAmount(primaryShip) < 1) { fleet.SetAmount(primaryShip, (long) _tbotInstance.InstanceSettings.Expeditions.MinPrimaryToSend); + if (availableShips.GetAmount(primaryShip) < 1) { + DoLog(LogLevel.Warning, $"Unable to send expeditions: no ships available in origin {origin.ToString()}"); + delayExpedition++; + continue; + } if (!availableShips.HasAtLeast(fleet, expsToSendFromThisOrigin)) { DoLog(LogLevel.Warning, $"Unable to send expeditions: available {primaryShip.ToString()} in origin {origin.ToString()} under set min number of {(long) _tbotInstance.InstanceSettings.Expeditions.MinPrimaryToSend}"); delayExpedition++; From ff540c0799d609bf1ab419663f6c560dbd186fd8 Mon Sep 17 00:00:00 2001 From: 0xE232FE Date: Wed, 5 Feb 2025 17:47:32 +0100 Subject: [PATCH 024/117] Update release.yml typo --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 190bb4db..09ad5c50 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -126,7 +126,7 @@ jobs: - name: Build ogamed osx-arm64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed - env GOOS=darwin GOARCH=amd64 go build -o ogamed + env GOOS=darwin GOARCH=arm64 go build -o ogamed cd ${{ github.workspace }} mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/osx-arm64/ chmod +x ${{ github.workspace }}/publish/osx-arm64/TBot From 1015c401a5d045e0db8ffbc460bc196f86742c4c Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Sat, 22 Feb 2025 16:49:31 +0100 Subject: [PATCH 025/117] fix Brain.Transports --- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 12 ++++++++---- TBot/instance_settings.json | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index 8f558c95..029e7259 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -433,19 +433,21 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { destination = allCelestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; missingResources = xCostBuildable.Difference(destination.Resources); } else { destination = allCelestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { @@ -538,18 +540,20 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { destination = _tbotInstance.UserData.celestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } else { destination = _tbotInstance.UserData.celestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } origin = _tbotInstance.UserData.celestials .Unique() diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index f9ff3f4a..e8f06863 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -317,7 +317,7 @@ "Position": 8, "Type": "Moon" }, - "TargetAssociateMoon": true, + "TargetAssociateMoon": false, "CargoType": "LargeCargo", "RandomOrder": true, "SkipIfIncomingTransport": true, From 24deb25ff6d5b3a5bc2997b91a40f9a94f8d236f Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Mon, 24 Feb 2025 05:24:44 +0100 Subject: [PATCH 026/117] fix autoDiscovery Crashes ? --- TBot/Workers/AutoDiscoveryWorker.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index 9afeaba0..06163829 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -232,7 +232,10 @@ protected override async Task Execute() { DoLog(LogLevel.Information, $"Stopping feature."); await EndExecution(); } else { - long interval = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + long interval = 0; + if (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count() > 0) + interval = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + if (delay) { DoLog(LogLevel.Information, $"Delaying..."); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); From 4232313c81443d9ae692e09e5603f1e07e39d906 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 27 Feb 2025 17:35:20 +0100 Subject: [PATCH 027/117] * upgrade to .Net Framework 9.0 --- TBot.Common/TBot.Common.csproj | 12 ++++++------ .../TBot.Ogame.Infrastructure.csproj | 8 ++++---- TBot.WebUI/TBot.WebUI.csproj | 8 ++++---- TBot/Services/TelegramMessenger.cs | 6 +++--- TBot/TBot.csproj | 12 ++++++------ 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/TBot.Common/TBot.Common.csproj b/TBot.Common/TBot.Common.csproj index 3f439b8a..522fb7e0 100644 --- a/TBot.Common/TBot.Common.csproj +++ b/TBot.Common/TBot.Common.csproj @@ -1,18 +1,18 @@ - net6.0 + net9.0 enable enable - - - + + + - - + + diff --git a/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj b/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj index 469351a1..d8b49ffa 100644 --- a/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj +++ b/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj @@ -1,17 +1,17 @@ - net6.0 + net9.0 enable enable - + - + - + diff --git a/TBot.WebUI/TBot.WebUI.csproj b/TBot.WebUI/TBot.WebUI.csproj index d019a0f1..b7c9c3b2 100644 --- a/TBot.WebUI/TBot.WebUI.csproj +++ b/TBot.WebUI/TBot.WebUI.csproj @@ -1,7 +1,7 @@  - net6.0 + net9.0 enable enable Library @@ -35,9 +35,9 @@ - - - + + + diff --git a/TBot/Services/TelegramMessenger.cs b/TBot/Services/TelegramMessenger.cs index effe657e..1a326ce7 100644 --- a/TBot/Services/TelegramMessenger.cs +++ b/TBot/Services/TelegramMessenger.cs @@ -180,7 +180,7 @@ public Task SendTyping(CancellationToken cancellationToken) { while (isTyping) { await Client.SendChatActionAsync( chatId: Channel, - chatAction: ChatAction.Typing, + action: ChatAction.Typing, cancellationToken: cancellationToken); await Task.Delay(3000); } @@ -202,7 +202,7 @@ await Client.SendTextMessageAsync( public async Task SendMessage(ITelegramBotClient client, Chat chat, string message, ParseMode parseMode = ParseMode.Html) { try { isTyping = false; - await client.SendTextMessageAsync(chat, message, parseMode); + await client.SendTextMessageAsync(chat, message, ((int)parseMode)); } catch (Exception e) { _logger.WriteLog(LogLevel.Error, LogSender.Tbot, $"Could not send Telegram message: an exception has occurred: {e.Message}"); } @@ -1291,7 +1291,7 @@ public async Task TelegramBot() { var receiverOptions = new ReceiverOptions { AllowedUpdates = Array.Empty(), - ThrowPendingUpdates = true + //ThrowPendingUpdates = true }; receivingTask = Client.ReceiveAsync(HandleUpdateAsync, HandleErrorAsync, receiverOptions, ct); diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index b6845c3b..c97be498 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net9.0 disable TBot 0.3.4 @@ -42,12 +42,12 @@ - - + + - - - + + + From f95311b8b0bca764ba3e58f41d3717f8bffcd895 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 27 Feb 2025 17:40:53 +0100 Subject: [PATCH 028/117] * try to fix github actions --- .github/workflows/release.yml | 2 +- .github/workflows/snapshot.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 09ad5c50..8f1bbec5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 9.0.x - name: Restore dependencies run: dotnet restore - name: Setup GO diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index eac931ff..b880dc40 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -22,7 +22,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 9.0.x - name: Restore dependencies run: dotnet restore - name: Setup GO From 1d9103a991c33fe841b4748c4a13154570f0acf9 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 27 Feb 2025 17:45:54 +0100 Subject: [PATCH 029/117] * change action to build TBot with self-contained .Net Framework --- .github/workflows/release.yml | 14 +++++++------- .github/workflows/snapshot.yml | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8f1bbec5..45b686f7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,7 @@ jobs: go-version: '~1.18.0' - name: Build TBot win64 - run: dotnet publish TBot -c Release -r win-x64 -o publish/win64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r win-x64 -o publish/win64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed win64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -44,7 +44,7 @@ jobs: args: zip -qq -r TBot-${{ env.SNAP_VERSION }}-win64.zip publish/win64/ - name: Build TBot win32 - run: dotnet publish TBot -c Release -r win-x86 -o publish/win32/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r win-x86 -o publish/win32/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed win32 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -58,7 +58,7 @@ jobs: args: zip -qq -r TBot-${{ env.SNAP_VERSION }}-win32.zip publish/win32/ - name: Build TBot TBot linux64 - run: dotnet publish TBot -c Release -r linux-x64 -o publish/linux64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r linux-x64 -o publish/linux64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linux64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -74,7 +74,7 @@ jobs: args: zip -qq -r TBot-${{ env.SNAP_VERSION }}-linux64.zip publish/linux64/ - name: Build TBot TBot linuxarm - run: dotnet publish TBot -c Release -r linux-arm -o publish/linuxarm/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r linux-arm -o publish/linuxarm/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linuxarm run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -90,7 +90,7 @@ jobs: args: zip -qq -r TBot-${{ env.SNAP_VERSION }}-linuxarm.zip publish/linuxarm/ - name: Build TBot TBot linuxarm64 - run: dotnet publish TBot -c Release -r linux-arm64 -o publish/linuxarm64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r linux-arm64 -o publish/linuxarm64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linuxarm64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -106,7 +106,7 @@ jobs: args: zip -qq -r TBot-${{ env.SNAP_VERSION }}-linuxarm64.zip publish/linuxarm64/ - name: Build TBot TBot osx64 - run: dotnet publish TBot -c Release -r osx-x64 -o publish/osx64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r osx-x64 -o publish/osx64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed osx64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -122,7 +122,7 @@ jobs: args: zip -qq -r TBot-${{ env.SNAP_VERSION }}-osx64.zip publish/osx64/ - name: Build TBot TBot osx-arm64 - run: dotnet publish TBot -c Release -r osx-arm64 -o publish/osx-arm64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r osx-arm64 -o publish/osx-arm64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed osx-arm64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index b880dc40..94c1d93d 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -31,7 +31,7 @@ jobs: go-version: '~1.18.0' - name: Build TBot win64 - run: dotnet publish TBot -c Release -r win-x64 -o publish/win64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r win-x64 -o publish/win64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed win64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -49,7 +49,7 @@ jobs: path: ${{ github.workspace }}/TBot-${{ env.SNAP_VERSION }}-win64.zip - name: Build TBot win32 - run: dotnet publish TBot -c Release -r win-x86 -o publish/win32/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r win-x86 -o publish/win32/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed win32 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -67,7 +67,7 @@ jobs: path: ${{ github.workspace }}/TBot-${{ env.SNAP_VERSION }}-win32.zip - name: Build TBot linux64 - run: dotnet publish TBot -c Release -r linux-x64 -o publish/linux64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r linux-x64 -o publish/linux64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linux64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -87,7 +87,7 @@ jobs: path: ${{ github.workspace }}/TBot-${{ env.SNAP_VERSION }}-linux64.zip - name: Build TBot linuxarm - run: dotnet publish TBot -c Release -r linux-arm -o publish/linuxarm/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r linux-arm -o publish/linuxarm/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linuxarm run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -107,7 +107,7 @@ jobs: path: ${{ github.workspace }}/TBot-${{ env.SNAP_VERSION }}-linuxarm.zip - name: Build TBot linuxarm64 - run: dotnet publish TBot -c Release -r linux-arm64 -o publish/linuxarm64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r linux-arm64 -o publish/linuxarm64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linuxarm64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -127,7 +127,7 @@ jobs: path: ${{ github.workspace }}/TBot-${{ env.SNAP_VERSION }}-linuxarm64.zip - name: Build TBot osx64 - run: dotnet publish TBot -c Release -r osx-x64 -o publish/osx64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r osx-x64 -o publish/osx64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed osx64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed @@ -147,7 +147,7 @@ jobs: path: ${{ github.workspace }}/TBot-${{ env.SNAP_VERSION }}-osx64.zip - name: Build TBot osx-arm64 - run: dotnet publish TBot -c Release -r osx-arm64 -o publish/osx-arm64/ -p:PublishSingleFile=true --self-contained false + run: dotnet publish TBot -c Release -r osx-arm64 -o publish/osx-arm64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed osx-arm64 run: | cd ${{ github.workspace }}/ogame/cmd/ogamed From ff4f9d21e968b39656b5cc3b338083a4069f9952 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 27 Feb 2025 18:01:05 +0100 Subject: [PATCH 030/117] * adjust versioning --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index c97be498..69d868c5 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 0.3.4 + 3.0.7 Tbot.Program AnyCPU;x64;x86 2023 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 0.3.4.0 - 0.3.4.0 + 3.0.7 + 3.0.7 OGame Bot False ELK-Lab.pfx From d9c2c828a2c2cafe11e3758297f1ff0264948439 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 27 Feb 2025 18:50:36 +0100 Subject: [PATCH 031/117] * fix TelegramBot --- TBot/Services/TelegramMessenger.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/TBot/Services/TelegramMessenger.cs b/TBot/Services/TelegramMessenger.cs index 1a326ce7..05b4d8f4 100644 --- a/TBot/Services/TelegramMessenger.cs +++ b/TBot/Services/TelegramMessenger.cs @@ -180,7 +180,7 @@ public Task SendTyping(CancellationToken cancellationToken) { while (isTyping) { await Client.SendChatActionAsync( chatId: Channel, - action: ChatAction.Typing, + action: ChatAction.Typing,//ChatAction.Typing, cancellationToken: cancellationToken); await Task.Delay(3000); } @@ -202,7 +202,8 @@ await Client.SendTextMessageAsync( public async Task SendMessage(ITelegramBotClient client, Chat chat, string message, ParseMode parseMode = ParseMode.Html) { try { isTyping = false; - await client.SendTextMessageAsync(chat, message, ((int)parseMode)); + //await client.SendTextMessageAsync(chat, message, parseMode); + await client.SendTextMessageAsync(chat, message, null, parseMode); } catch (Exception e) { _logger.WriteLog(LogLevel.Error, LogSender.Tbot, $"Could not send Telegram message: an exception has occurred: {e.Message}"); } @@ -1291,6 +1292,7 @@ public async Task TelegramBot() { var receiverOptions = new ReceiverOptions { AllowedUpdates = Array.Empty(), + DropPendingUpdates = false, //ThrowPendingUpdates = true }; From 6673c77a4dbd084e55716b02b81a7424c1088f46 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 27 Feb 2025 18:51:28 +0100 Subject: [PATCH 032/117] * v3.0.8 --- TBot/TBot.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 69d868c5..3aa24a4e 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,14 +5,14 @@ net9.0 disable TBot - 3.0.7 + 3.0.8 Tbot.Program AnyCPU;x64;x86 2023 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.0.7 + 3.0.8 3.0.7 OGame Bot False From c68bbdf89dc68ba43917e21fafbb68af88c547cb Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Fri, 28 Feb 2025 12:55:56 +0100 Subject: [PATCH 033/117] * Improve FleetSaver to use Transport Mission as last option. This is for new Players with only Homeplanet where SPY, HARVEST, DEPLOY or EXPEDITION is not available yet. --- TBot/TBot.csproj | 2 +- TBot/Workers/FleetScheduler.cs | 74 +++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 3aa24a4e..7ceeb36b 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -13,7 +13,7 @@ https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot 3.0.8 - 3.0.7 + 3.0.8 OGame Bot False ELK-Lab.pfx diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 9e8432d6..08b9ba5b 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -289,6 +289,7 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = } } } + //Doing Spy if (!AlreadySent && celestial.Ships.EspionageProbe > 0) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Fleetsave from {celestial.ToString()} no {mission} found, checking Spy destination..."); @@ -312,6 +313,29 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = } } + //Doing Transport + if (!AlreadySent) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Fleetsave from {celestial.ToString()} no {mission} found, checking Transport destination..."); + mission = Missions.Transport; + fleetHypotesis = await GetFleetSaveDestination(_tbotInstance.UserData.celestials, celestial, departureTime, minDuration, mission, maxDeuterium); + if (fleetHypotesis.Count > 0) { + foreach (FleetHypotesis fleet in fleetHypotesis.OrderBy(pf => pf.Fuel).ThenBy(pf => pf.Duration <= minDuration)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"checking {mission} fleet to: {fleet.Destination}"); + if (CheckFuel(fleet, celestial)) { + fleetId = await SendFleet(fleet.Origin, fleet.Ships, fleet.Destination, fleet.Mission, fleet.Speed, payload, _tbotInstance.UserData.userInfo.Class, true); + + if (fleetId != (int) SendFleetCode.GenericError || + fleetId != (int) SendFleetCode.AfterSleepTime || + fleetId != (int) SendFleetCode.NotEnoughSlots) { + possibleFleet = fleet; + AlreadySent = true; + break; + } + } + } + } + } + //Doing switch bool hasMoon = _tbotInstance.UserData.celestials.Count(c => c.HasCoords(new Coordinate(celestial.Coordinate.Galaxy, celestial.Coordinate.System, celestial.Coordinate.Position, Celestials.Moon))) == 1; if (!AlreadySent && hasMoon && !timers.TryGetValue("GhostSleepTimer", out Timer val)) { @@ -599,7 +623,55 @@ private async Task> GetFleetSaveDestination(List origin = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.LFBonuses); int sys = 0; + int playerid = _tbotInstance.UserData.userInfo.PlayerID; + switch (mission) { + case Missions.Transport: + //if (origin.Ships.Recycler == 0) { + // _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"No recycler available, skipping to next mission..."); + // break; + //} + //int playerid = _tbotInstance.UserData.userInfo.PlayerID; + for (sys = origin.Coordinate.System - 5; sys <= origin.Coordinate.System + 5; sys++) { + if (possibleDestinations.Count() == 10) { + break; + } + sys = GeneralHelper.ClampSystem(sys); + galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); + foreach (var planet in galaxyInfo.Planets) { + //if (planet != null && planet.Inactive && !planet.Vacation && !planet.Administrator && !planet.Banned && !planet.StrongPlayer) { + if (planet != null && !planet.Vacation && !planet.Administrator && !planet.Banned && !planet.StrongPlayer) { + possibleDestinations.Add(new(planet.Coordinate.Galaxy, planet.Coordinate.System, planet.Coordinate.Position, Celestials.Planet)); + //if (planet.Moon != null) { + // possibleDestinations.Add(new(planet.Coordinate.Galaxy, planet.Coordinate.System, planet.Coordinate.Position, Celestials.Moon)); + //} + } + } + } + + if (possibleDestinations.Count() > 0) { + foreach (var possibleDestination in possibleDestinations) { + foreach (var currentSpeed in validSpeeds) { + FleetPrediction fleetPrediction = _calcService.CalcFleetPrediction(origin.Coordinate, possibleDestination, origin.Ships.GetMovableShips(), mission, currentSpeed, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.allianceClass); + + FleetHypotesis fleetHypotesis = new() { + Origin = origin, + Destination = possibleDestination, + Ships = origin.Ships.GetMovableShips(), + Mission = mission, + Speed = currentSpeed, + Duration = fleetPrediction.Time, + Fuel = fleetPrediction.Fuel + }; + if (fleetHypotesis.Duration >= minFlightTime / 2 && fleetHypotesis.Fuel <= maxFuel) { + possibleFleets.Add(fleetHypotesis); + break; + } + } + } + } + break; + case Missions.Spy: if (origin.Ships.EspionageProbe == 0) { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"No espionageprobe available, skipping to next mission..."); @@ -675,7 +747,7 @@ private async Task> GetFleetSaveDestination(List _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"No recycler available, skipping to next mission..."); break; } - int playerid = _tbotInstance.UserData.userInfo.PlayerID; + //int playerid = _tbotInstance.UserData.userInfo.PlayerID; for (sys = origin.Coordinate.System - 5; sys <= origin.Coordinate.System + 5; sys++) { sys = GeneralHelper.ClampSystem(sys); galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); From d111316eb871f14e23acad3f2afcf6e14cf9275a Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Fri, 28 Feb 2025 12:57:39 +0100 Subject: [PATCH 034/117] v3.0.9 --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 7ceeb36b..5bb60fa9 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.0.8 + 3.0.9 Tbot.Program AnyCPU;x64;x86 2023 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.0.8 - 3.0.8 + 3.0.9 + 3.0.9 OGame Bot False ELK-Lab.pfx From b7cf509c5dc588fc8b41a235515aed358a208f74 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Mon, 3 Mar 2025 19:02:01 +0100 Subject: [PATCH 035/117] * fix Brain AutoTransport nil pointer reference. --- TBot/TBot.csproj | 8 ++++---- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 5bb60fa9..a3df1815 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.0.9 + 3.0.10 Tbot.Program AnyCPU;x64;x86 - 2023 © TBot + 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.0.9 - 3.0.9 + 3.1.0 + 3.1.0 OGame Bot False ELK-Lab.pfx diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index 029e7259..4a8fcc9d 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -562,6 +562,9 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; + + //destination = await _tbotOgameBridge.UpdatePlanet(destination, UpdateTypes.Resources); + destination = await _tbotOgameBridge.UpdatePlanet(destination, UpdateTypes.Full); fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, xCostBuildable, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; From cba245ef61225fb856c7edcd04a3acfadfa8d135 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Wed, 5 Mar 2025 16:12:59 +0100 Subject: [PATCH 036/117] fix for other feature.transports --- TBot/Workers/Brain/AutoResearchWorker.cs | 13 +++++++++---- .../Brain/LifeformsAutoMineCelestialWorker.cs | 12 ++++++++---- .../Brain/LifeformsAutoResearchCelestialWorker.cs | 12 ++++++++---- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 446c8cb1..40a4e435 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -283,6 +283,7 @@ protected override async Task Execute() { } List closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons ? allCelestials + .Unique() .Where(planet => !celestialsToExclude.Has(planet)) .Where(planet => planet.Resources.TotalResources > 0) .Where(planet => planet.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) @@ -306,19 +307,21 @@ protected override async Task Execute() { Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { destination = allCelestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; missingResources = cost.Difference(destination.Resources); } else { destination = allCelestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { @@ -411,18 +414,20 @@ protected override async Task Execute() { Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { destination = _tbotInstance.UserData.celestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } else { destination = _tbotInstance.UserData.celestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } origin = _tbotInstance.UserData.celestials .Unique() diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 03900ca4..05c83574 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -313,19 +313,21 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { destination = allCelestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; missingResources = xCostBuildable.Difference(destination.Resources); } else { destination = allCelestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { @@ -418,18 +420,20 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { destination = _tbotInstance.UserData.celestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } else { destination = _tbotInstance.UserData.celestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } origin = _tbotInstance.UserData.celestials .Unique() diff --git a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs index 23efb46d..8e81de36 100644 --- a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs @@ -314,19 +314,21 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { destination = allCelestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; missingResources = xCostBuildable.Difference(destination.Resources); } else { destination = allCelestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { @@ -419,18 +421,20 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { destination = _tbotInstance.UserData.celestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } else { destination = _tbotInstance.UserData.celestials + .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .First(); + .SingleOrDefault() ?? new() { ID = 0 }; } origin = _tbotInstance.UserData.celestials .Unique() From fd6374a2ae74bc451edc27baf0b7e7fc074c0872 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 5 Mar 2025 20:30:52 +0100 Subject: [PATCH 037/117] * v3.1.1 - fix one more TransportHandler nil pointer exception. --- TBot/TBot.csproj | 4 ++-- TBot/Workers/Brain/AutoResearchWorker.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index a3df1815..ea932caa 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,14 +5,14 @@ net9.0 disable TBot - 3.0.10 + 3.1.1 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.1.0 + 3.1.1 3.1.0 OGame Bot False diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 446c8cb1..0a3d68ea 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -431,6 +431,7 @@ protected override async Task Execute() { .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; + destination = await _tbotOgameBridge.UpdatePlanet(destination, UpdateTypes.Full); fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, cost, Buildables.Null); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } From 5c16a787669a0736bc2d74e3d73e2e5262470624 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 5 Mar 2025 21:11:01 +0100 Subject: [PATCH 038/117] * fix nil pointer exception --- TBot/TBot.csproj | 4 ++-- TBot/Workers/FleetScheduler.cs | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index ea932caa..675f3717 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -12,8 +12,8 @@ https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.1.1 - 3.1.0 + 3.1.2 + 3.1.2 OGame Bot False ELK-Lab.pfx diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 08b9ba5b..541bf866 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -1015,6 +1015,9 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat idealShips = _calcService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, cargoBonus, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); var availableShips = origin.Ships.GetAmount(preferredShip); if (buildable != LFBuildables.None) { + destination = await _tbotOgameBridge.UpdatePlanet(destination, UpdateTypes.LFBuildings); + destination = await _tbotOgameBridge.UpdatePlanet(destination, UpdateTypes.LFTechs); + destination = await _tbotOgameBridge.UpdatePlanet(destination, UpdateTypes.LFBonuses); int level = _calcService.GetNextLevel(destination, buildable); long buildTime = _calcService.CalcProductionTime(buildable, level, _tbotInstance.UserData.serverData, destination); var tempCelestial = destination; From d121f8c891e4888fac998eb564884c61c71180b9 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Wed, 12 Mar 2025 20:24:35 +0100 Subject: [PATCH 039/117] fix SlotPriorityLevel 0 --- TBot/Workers/AutoDiscoveryWorker.cs | 2 +- TBot/Workers/AutoFarmWorker.cs | 2 +- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 9 ++++++++- TBot/Workers/Brain/AutoResearchWorker.cs | 9 ++++++++- TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs | 9 ++++++++- .../Brain/LifeformsAutoResearchCelestialWorker.cs | 9 ++++++++- TBot/Workers/ColonizeWorker.cs | 2 +- TBot/Workers/ExpeditionsWorker.cs | 2 +- TBot/Workers/HarvestWorker.cs | 2 +- 9 files changed, 37 insertions(+), 9 deletions(-) diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index 06163829..ef1304c8 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -102,7 +102,7 @@ protected override async Task Execute() { if (feature == presentFeature) continue; //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Active && feature.HasPriorityOn(presentFeature)) { + if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; } else { diff --git a/TBot/Workers/AutoFarmWorker.cs b/TBot/Workers/AutoFarmWorker.cs index cd5665cf..69e7700b 100644 --- a/TBot/Workers/AutoFarmWorker.cs +++ b/TBot/Workers/AutoFarmWorker.cs @@ -637,7 +637,7 @@ protected override async Task Execute() { if (feature == presentFeature) continue; //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Active && feature.HasPriorityOn(presentFeature)) { + if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; } else { diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index 029e7259..ab9518b2 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -359,7 +359,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings if (feature == presentFeature) continue; //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Active && feature.HasPriorityOn(presentFeature)) { + if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; } else { @@ -575,6 +575,13 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); } } else { + if (_tbotInstance.InstanceSettings.Brain.SlotPriorityLevel > 0) { + if (_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots == 0) + DoLog(LogLevel.Information, $"Transports.MaxSlots is set to 0, you should increase it."); + else + DoLog(LogLevel.Information, $"0 slots available."); + } + DoLog(LogLevel.Information, $"Not enough slots: Transports.MaxSlots"); delay = true; } } diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 40a4e435..a314a4e0 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -232,7 +232,7 @@ protected override async Task Execute() { if (feature == presentFeature) continue; //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Active && feature.HasPriorityOn(presentFeature)) { + if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; } else { @@ -459,6 +459,13 @@ protected override async Task Execute() { .ID; } } else { + if (_tbotInstance.InstanceSettings.Brain.SlotPriorityLevel > 0) { + if (_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots == 0) + DoLog(LogLevel.Information, $"Transports.MaxSlots is set to 0, you should increase it."); + else + DoLog(LogLevel.Information, $"0 slots available."); + } + DoLog(LogLevel.Information, $"Not enough slots: Transports.MaxSlots"); delay = true; } } diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 05c83574..c9e5eede 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -239,7 +239,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { if (feature == presentFeature) continue; //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Active && feature.HasPriorityOn(presentFeature)) { + if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; } else { @@ -463,6 +463,13 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .First().ID; } } else { + if (_tbotInstance.InstanceSettings.Brain.SlotPriorityLevel > 0) { + if (_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots == 0) + DoLog(LogLevel.Information, $"Transports.MaxSlots is set to 0, you should increase it."); + else + DoLog(LogLevel.Information, $"0 slots available."); + } + DoLog(LogLevel.Information, $"Not enough slots: Transports.MaxSlots"); delay = true; } } diff --git a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs index 8e81de36..a9ac434a 100644 --- a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs @@ -240,7 +240,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { if (feature == presentFeature) continue; //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Active && feature.HasPriorityOn(presentFeature)) { + if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; } else { @@ -456,6 +456,13 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); } } else { + if (_tbotInstance.InstanceSettings.Brain.SlotPriorityLevel > 0) { + if (_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots == 0) + DoLog(LogLevel.Information, $"Transports.MaxSlots is set to 0, you should increase it."); + else + DoLog(LogLevel.Information, $"0 slots available."); + } + DoLog(LogLevel.Information, $"Not enough slots: Transports.MaxSlots"); delay = true; } } diff --git a/TBot/Workers/ColonizeWorker.cs b/TBot/Workers/ColonizeWorker.cs index f102cafd..569b68df 100644 --- a/TBot/Workers/ColonizeWorker.cs +++ b/TBot/Workers/ColonizeWorker.cs @@ -155,7 +155,7 @@ protected override async Task Execute() { if (feature == presentFeature) continue; //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Active && feature.HasPriorityOn(presentFeature)) { + if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; } else { diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index 9d1ebee3..22b2c7a9 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -130,7 +130,7 @@ protected override async Task Execute() { if (feature == presentFeature) continue; //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Active && feature.HasPriorityOn(presentFeature)) { + if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; } else { diff --git a/TBot/Workers/HarvestWorker.cs b/TBot/Workers/HarvestWorker.cs index 9b9be114..b4959336 100644 --- a/TBot/Workers/HarvestWorker.cs +++ b/TBot/Workers/HarvestWorker.cs @@ -198,7 +198,7 @@ protected override async Task Execute() { if (feature == presentFeature) continue; _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Active && feature.HasPriorityOn(presentFeature)) { + if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; reservedSlots += feature.MaxSlots; } else { From e94a125216faf8bae06bc034ee5994a01a97ac04 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 16 Mar 2025 17:12:41 +0100 Subject: [PATCH 040/117] v3.1.3 - fix price calculation for LfBuilding AntimatterCondenser --- TBot/Includes/CalculationService.cs | 4 ++-- TBot/TBot.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 61d4c398..db249970 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -1612,8 +1612,8 @@ public Resources CalcPrice(LFBuildables buildable, int level, double costReducti metalBaseCost = 6; crystalbaseCost = 3; energyBaseCost = 9; - metalFactor = 1.21; - crystalFactor = 1.21; + metalFactor = 1.20; + crystalFactor = 1.20; energyFactor = 1.02; break; case LFBuildables.VortexChamber: diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 675f3717..b121bfba 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,14 +5,14 @@ net9.0 disable TBot - 3.1.1 + 3.1.3 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.1.2 + 3.1.3 3.1.2 OGame Bot False From 5e2ab03f6dcb3b2d53c0332446683e1111154efe Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Mon, 5 May 2025 17:21:34 +0200 Subject: [PATCH 041/117] Fix transport instance's error --- TBot.Ogame.Infrastructure/Models/Transport.cs | 52 +++ TBot/Includes/CalculationService.cs | 195 +++++++++- TBot/Includes/ICalculationService.cs | 4 +- TBot/Workers/AutoDiscoveryWorker.cs | 107 ++---- TBot/Workers/AutoFarmWorker.cs | 103 ++--- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 358 ++++++++---------- TBot/Workers/Brain/AutoResearchWorker.cs | 345 +++++++---------- .../Brain/LifeformsAutoMineCelestialWorker.cs | 331 +++++++--------- .../LifeformsAutoResearchCelestialWorker.cs | 346 ++++++++--------- TBot/Workers/ColonizeWorker.cs | 103 ++--- TBot/Workers/ExpeditionsWorker.cs | 103 ++--- TBot/Workers/HarvestWorker.cs | 102 ++--- TBot/instance_settings.json | 28 +- 13 files changed, 992 insertions(+), 1185 deletions(-) create mode 100644 TBot.Ogame.Infrastructure/Models/Transport.cs diff --git a/TBot.Ogame.Infrastructure/Models/Transport.cs b/TBot.Ogame.Infrastructure/Models/Transport.cs new file mode 100644 index 00000000..9ec16a2a --- /dev/null +++ b/TBot.Ogame.Infrastructure/Models/Transport.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Text.RegularExpressions; +using TBot.Ogame.Infrastructure.Enums; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace TBot.Ogame.Infrastructure.Models { + public class TransportSettings { + public TransportSettings(bool active = false, Buildables cargoType = Buildables.SmallCargo, long deutToLeave = 0, bool roundResources = true, bool sendToTheMoonIfPossible = true, Celestial origin = null, long maxSlots = 0, bool checkMoonOrPlanetFirst = false, bool multipleTransports = false, MultipleOrigins multipleOrigins = null) { + Active = active; + CargoType = cargoType; + DeutToLeave = deutToLeave; + RoundResources = roundResources; + SendToTheMoonIfPossible = sendToTheMoonIfPossible; + Origin = origin ?? new(); + MaxSlots = maxSlots; + CheckMoonOrPlanetFirst = checkMoonOrPlanetFirst; + DoMultipleTransportIsNotEnoughShipButSamePosition = multipleTransports; + MultipleOrigin = multipleOrigins ?? new(); + } + public bool Active { get; set; } + public Buildables CargoType { get; set; } + public long DeutToLeave { get; set; } + public bool RoundResources { get; set; } + public bool SendToTheMoonIfPossible { get; set; } + public Celestial Origin { get; set; } + public long MaxSlots { get; set; } + public bool CheckMoonOrPlanetFirst { get; set; } + public bool DoMultipleTransportIsNotEnoughShipButSamePosition { get; set; } + public MultipleOrigins MultipleOrigin { get; set; } + } + + public class MultipleOrigins { + public MultipleOrigins(bool active = false, bool onlyFromMoons = true, long minimumResourcesToSend = 0, bool priorityToP = true, List exclude = null) { + Active = active; + OnlyFromMoons = onlyFromMoons; + MinimumResourcesToSend = minimumResourcesToSend; + PriorityToProximityOverQuantity = priorityToP; + Exclude = exclude ?? new(); + } + public bool Active { get; set; } + public bool OnlyFromMoons { get; set; } + public long MinimumResourcesToSend { get; set; } + public bool PriorityToProximityOverQuantity { get; set; } + public List Exclude { get; set; } + } + +} \ No newline at end of file diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 61d4c398..cac09590 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4809,13 +4809,202 @@ public int CountPlanetsInRange(List planets, int galaxy, int minSyste public bool IsThereMoonHere(List planets, Celestial celestial) { Celestial moon = planets.Unique() - .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) + .Single(c => c.HasCoords(new( + (int) celestial.Coordinate.Galaxy, + (int) celestial.Coordinate.System, + (int) celestial.Coordinate.Position, + Celestials.Moon + ) + )) ?? new() { ID = 0 }; + /*.Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) .Where(c => c.Coordinate.Type == Celestials.Moon) - .SingleOrDefault() ?? new() { ID = 0 }; + .SingleOrDefault() ?? new() { ID = 0 };*/ return moon.ID == 0 ? false: true; } + + public int CalcSlotsPriority(Feature feature, List rankSlotsPriority, Slots slots, List fleets, int slotsToLeaveFree = 0) { + + RankSlotsPriority actualFeature = rankSlotsPriority.Where(f => (f.Feature == feature)).SingleOrDefault(); + int slotsAvailable = 0; + int reservedSlots = slotsToLeaveFree; + int otherSlots = (int) fleets.Where(fleet => (fleet.Mission != Missions.Transport && fleet.Mission != Missions.Expedition && fleet.Mission != Missions.Attack && fleet.Mission != Missions.Spy && fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery)).Count(); + if (slots.Free - slotsToLeaveFree > 0) { + rankSlotsPriority.Where(f => (f.Feature == Feature.BrainAutoMine || f.Feature == Feature.BrainAutoResearch || f.Feature == Feature.BrainLifeformAutoMine || f.Feature == Feature.BrainLifeformAutoResearch)).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Transport).Count(); + rankSlotsPriority.Where(f => f.Feature == Feature.Expeditions).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count(); + rankSlotsPriority.Where(f => f.Feature == Feature.AutoFarm).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Attack).Count(); + rankSlotsPriority.Where(f => f.Feature == Feature.Colonize).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count(); + rankSlotsPriority.Where(f => f.Feature == Feature.AutoDiscovery).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count(); + rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + + if (actualFeature.Rank > 0) { + reservedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Where(f => f.Rank < actualFeature.Rank).Sum(f => f.MaxSlots); + otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank >= actualFeature.Rank).Sum(f => f.SlotsUsed); + otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed); + slotsAvailable = slots.Total - reservedSlots - otherSlots; + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Total slots: {slots.Total}. {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other."); + if (slotsAvailable > 0) { + if (slotsAvailable < actualFeature.MaxSlots) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Less slots available. Steping back to {slotsAvailable} instead of {actualFeature.MaxSlots}"); + return slotsAvailable; + } else { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"{slots.Free} are availables and {actualFeature.MaxSlots} can be used for {feature.ToString()}"); + return actualFeature.MaxSlots; + } + } else { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"No slots available."); + return 0; + } + } else { + reservedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Sum(f => f.MaxSlots); + otherSlots += rankSlotsPriority.Where(f => !f.Active).Where(f => f.Rank > 0).Sum(f => f.SlotsUsed); + otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed); + slotsAvailable = slots.Total - reservedSlots - otherSlots; + if (slotsAvailable > 0) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Total slots: {slots.Total} and {slotsToLeaveFree} must remain free. {reservedSlots} slots are reserved and {otherSlots} are used for other. {slotsAvailable} are availables and can be used for {feature.ToString()}"); + return actualFeature.MaxSlots; + } else { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"No slots available. Total slots: {slots.Total}, {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other."); + return 0; + } + } + } else { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, "No slots left, delaying"); + return 0; + } + } + + public List> CalcMultipleOrigin(Celestial celestialToBuild, List allCelestials, Resources missingResources, TransportSettings transportSettings, List fleets, UserData userData) { + List> result = new(); + bool roundRes = transportSettings.RoundResources; + Resources resources = new(); + List closestCelestials = transportSettings.MultipleOrigin.OnlyFromMoons ? + allCelestials + .Where(planet => !transportSettings.MultipleOrigin.Exclude.Has(planet)) + .Where(planet => planet.Resources.TotalResources > 0) + .Where(planet => planet.Coordinate.Type == Celestials.Moon) + .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) + .ToList(): + allCelestials + .Where(c => !transportSettings.MultipleOrigin.Exclude.Has(c)) + .Where(c => c.Resources.TotalResources > 0) + .ToList(); + + Resources TotalResources = allCelestials.Aggregate(new Resources(), (total, celestial) => total.Sum(celestial.Resources)); + if (!TotalResources.IsEnoughFor(missingResources)) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Not enough resources available on all celestials: Needed: {missingResources.TransportableResources} - Available: {TotalResources.TransportableResources}"); + return new(); + } else { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Enough resources available on all celestials: Needed: {missingResources.TransportableResources} - Available: {TotalResources.TransportableResources}"); + } + + closestCelestials = transportSettings.MultipleOrigin.PriorityToProximityOverQuantity ? + closestCelestials.OrderBy(c => CalcDistance(c.Coordinate, celestialToBuild.Coordinate, userData.serverData)).ToList() : + closestCelestials.OrderByDescending(c => c.Resources.TotalResources).ToList(); + + Celestial destination = celestialToBuild; + if ((bool) transportSettings.SendToTheMoonIfPossible && celestialToBuild.Coordinate.Type == Celestials.Planet && IsThereMoonHere(allCelestials, celestialToBuild) && (!celestialToBuild.Ships.IsEmpty() || celestialToBuild.Resources.TotalResources > 0)) { + destination = allCelestials.Unique() + .Single(c => c.HasCoords(new( + (int) celestialToBuild.Coordinate.Galaxy, + (int) celestialToBuild.Coordinate.System, + (int) celestialToBuild.Coordinate.Position, + Celestials.Moon + ) + )); + destination.Resources = roundRes ? destination.Resources.Round() : destination.Resources; + if (destination.Resources.IsEnoughFor(missingResources)) { + if (destination.Ships.GetAmount(transportSettings.CargoType) >= CalcShipNumberForPayload(missingResources, transportSettings.CargoType, userData.researches.HyperspaceTechnology, userData.serverData, destination.LFBonuses.GetShipCargoBonus(transportSettings.CargoType), userData.userInfo.Class, userData.serverData.ProbeCargo)) { + result.Add(new Dictionary { { destination, missingResources } } ); + return result; + } else if (transportSettings.DoMultipleTransportIsNotEnoughShipButSamePosition) { + result.Add(new Dictionary { { destination, CalcMaxTransportableResources(destination.Ships, missingResources, userData.researches.HyperspaceTechnology, userData.serverData, destination.LFBonuses, userData.userInfo.Class, 0, userData.serverData.ProbeCargo) } } ); + return result; + } else { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Enough Resources on {destination.ToString()}, but not enough transporters and \"DoMultipleTransportIsNotEnoughShipButSamePosition\" is false."); + return new(); + } + } else { + missingResources = missingResources.Difference(destination.Resources); + } + } else { + destination = celestialToBuild; + } + closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)) + .Where(c => !IsThereTransportTowardsCelestial(c, fleets)) + .ToList(); + if (closestCelestials.Count() == 0) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Skipping transport: no celestial available"); + return new(); + } + if (IsThereTransportTowardsCelestial(destination, fleets)) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); + return new(); + } + TotalResources = closestCelestials.Aggregate(new Resources(), (total, celestial) => { + if (celestial.Ships.GetAmount(transportSettings.CargoType) >= CalcShipNumberForPayload(celestial.Resources, transportSettings.CargoType, userData.researches.HyperspaceTechnology, userData.serverData, celestial.LFBonuses.GetShipCargoBonus(transportSettings.CargoType), userData.userInfo.Class, userData.serverData.ProbeCargo)) { + return total.Sum(celestial.Resources); + } else { + Ships ships = new(); + ships.Add(transportSettings.CargoType, celestial.Ships.GetAmount(transportSettings.CargoType)); + Resources res = CalcMaxTransportableResources(ships, missingResources.Difference(total), userData.researches.HyperspaceTechnology, userData.serverData, celestial.LFBonuses, userData.userInfo.Class, 0, userData.serverData.ProbeCargo); + return total.Sum(res); + } + } ); + if (!TotalResources.IsEnoughFor(missingResources)) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Not enough resources available on all celestials: Needed: {missingResources.TransportableResources} - Available: {TotalResources.TransportableResources}"); + return new(); + } + + for (int i = 0; i < closestCelestials.Count(); i++) { + Celestial cel = closestCelestials[i]; + Resources celResources = cel.Resources.Difference(new Resources(0, 0, transportSettings.DeutToLeave)); + if (resources.Sum(celResources).IsEnoughFor(missingResources)) { + celResources = roundRes ? missingResources.Difference(resources).Round() : missingResources.Difference(resources); + } else { + celResources = roundRes ? + celResources.Difference(celResources.Difference(missingResources.Difference(resources))).Round(): + celResources.Difference(celResources.Difference(missingResources.Difference(resources))); + } + if (celResources.TotalResources < transportSettings.MultipleOrigin.MinimumResourcesToSend || celResources.TotalResources == 0) + continue; + if (cel.Ships.GetAmount(transportSettings.CargoType) >= CalcShipNumberForPayload(celResources, transportSettings.CargoType, userData.researches.HyperspaceTechnology, userData.serverData, cel.LFBonuses.GetShipCargoBonus(transportSettings.CargoType), userData.userInfo.Class, userData.serverData.ProbeCargo)) { + resources = resources.Sum(celResources); + result.Add(new Dictionary { { cel, celResources } } ); + } else { + if (i < closestCelestials.Count() - 1) { + Ships ships = new(); + ships.Add(transportSettings.CargoType, cel.Ships.GetAmount(transportSettings.CargoType)); + Resources res = CalcMaxTransportableResources(ships, celResources, userData.researches.HyperspaceTechnology, userData.serverData, cel.LFBonuses, userData.userInfo.Class, 0, userData.serverData.ProbeCargo); + if (resources.Sum(res).IsEnoughFor(missingResources)) { + resources = resources.Sum(res); + celResources = res; + if (celResources.TotalResources == 0) + continue; + result.Add(new Dictionary { { cel, celResources } } ); + } else { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Not enough resources transportable"); + return new(); + } + } else { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Not enough resources transportable"); + return new(); + } + } + _logger.WriteLog(LogLevel.Information, LogSender.Tbot, $"Sending resources from: {cel.Coordinate.ToString()} to {destination.Coordinate.ToString()} - Resources: {celResources.TransportableResources}"); + if (resources.IsEnoughFor(missingResources)) { + return result; + } + } + if (resources.IsEnoughFor(missingResources)) { + _logger.WriteLog(LogLevel.Information, LogSender.Tbot, $"{result.Count()} transports will be send to {destination.ToString()}"); + return result; + } else { + _logger.WriteLog(LogLevel.Information, LogSender.Tbot, $"Not enough resources transportable"); + return new(); + } + } } -} +} \ No newline at end of file diff --git a/TBot/Includes/ICalculationService.cs b/TBot/Includes/ICalculationService.cs index 4adf934f..c0bc89ef 100644 --- a/TBot/Includes/ICalculationService.cs +++ b/TBot/Includes/ICalculationService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Tbot.Services; using TBot.Model; using TBot.Ogame.Infrastructure; using TBot.Ogame.Infrastructure.Enums; @@ -153,7 +154,8 @@ public interface ICalculationService { int CountPlanetsInRange(List planets, int galaxy, int minSystem, int maxSystem, int minPosition, int maxPositions, int minSlots, int minTemperature, int maxTemperature); int CountPlanetsInRange(List planets, int galaxy, int minSystem, int maxSystem, int minPosition, int maxPositions, int minSlots, int minTemperature, int maxTemperature); bool IsThereMoonHere(List planets, Celestial celestial); - + int CalcSlotsPriority(Feature feature, List rankSlotsPriority, Slots slots, List fleets, int slotsToLeaveFree = 0); + List> CalcMultipleOrigin(Celestial celestialToBuild, List allCelestials, Resources missingResources, TransportSettings transportSettings, List fleets, UserData userData); } } diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index ef1304c8..b9e03b6a 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -47,81 +47,35 @@ protected override async Task Execute() { DoLog(LogLevel.Information, $"Starting AutoDiscovery..."); _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new(); - RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, - (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && - (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && - ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); - RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); - RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); - RankSlotsPriority ColonizeRank = new(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); - RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); - RankSlotsPriority presentFeature = AutoDiscoveryRank; - rankSlotsPriority.Add(BrainRank); - rankSlotsPriority.Add(ExpeditionsRank); - rankSlotsPriority.Add(AutoFarmRank); - rankSlotsPriority.Add(ColonizeRank); - rankSlotsPriority.Add(AutoDiscoveryRank); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - string msg = ""; - int reservedSlots = 0; - int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; - int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && - fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && - fleet.Mission != Missions.Spy && - fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery) - ).Count(); - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); - foreach (RankSlotsPriority feature in rankSlotsPriority) { - if (feature == presentFeature) - continue; - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { - msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; - reservedSlots += feature.MaxSlots; - } else { - otherSlots += feature.SlotsUsed; - } - } - if (otherSlots > 0) - msg = $"{msg}, {otherSlots} are used for Other"; - int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; - tempsValue = tempsValue < 0 ? 0 : tempsValue; - DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); - if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); - MaxSlots = 0; - } else if (MaxSlots > tempsValue) { - MaxSlots = tempsValue; - DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); - } - + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + new RankSlotsPriority(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal), + new RankSlotsPriority(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + new RankSlotsPriority(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1), + new RankSlotsPriority(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + new RankSlotsPriority(Feature.Harvest, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.AutoDiscovery, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); Celestial origin = _tbotInstance.UserData.celestials .Unique() @@ -200,8 +154,7 @@ protected override async Task Execute() { failures++; DoLog(LogLevel.Warning, $"Failed to send discovery fleet to {dest.ToString()} from {origin.ToString()}."); _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(1)); - } - else { + } else { DoLog(LogLevel.Information, $"Sent discovery fleet to {dest.ToString()} from {origin.ToString()}."); _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(7)); } diff --git a/TBot/Workers/AutoFarmWorker.cs b/TBot/Workers/AutoFarmWorker.cs index 69e7700b..105508dd 100644 --- a/TBot/Workers/AutoFarmWorker.cs +++ b/TBot/Workers/AutoFarmWorker.cs @@ -582,80 +582,35 @@ protected override async Task Execute() { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new(); - RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, - (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && - (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && - ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); - RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); - RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); - RankSlotsPriority ColonizeRank = new(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); - RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); - RankSlotsPriority presentFeature = AutoFarmRank; - rankSlotsPriority.Add(BrainRank); - rankSlotsPriority.Add(ExpeditionsRank); - rankSlotsPriority.Add(AutoFarmRank); - rankSlotsPriority.Add(ColonizeRank); - rankSlotsPriority.Add(AutoDiscoveryRank); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - string msg = ""; - int reservedSlots = 0; - int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; - int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && - fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && - fleet.Mission != Missions.Spy && - fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery) - ).Count(); - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); - foreach (RankSlotsPriority feature in rankSlotsPriority) { - if (feature == presentFeature) - continue; - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { - msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; - reservedSlots += feature.MaxSlots; - } else { - otherSlots += feature.SlotsUsed; - } - } - if (otherSlots > 0) - msg = $"{msg}, {otherSlots} are used for Other"; - int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; - tempsValue = tempsValue < 0 ? 0 : tempsValue; - DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); - if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); - MaxSlots = 0; - } else if (MaxSlots > tempsValue) { - MaxSlots = tempsValue; - DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); - } + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + new RankSlotsPriority(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal), + new RankSlotsPriority(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + new RankSlotsPriority(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1), + new RankSlotsPriority(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + new RankSlotsPriority(Feature.Harvest, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.AutoFarm, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); /// Send attacks. List attackTargets; diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index ab9518b2..d666848e 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -134,6 +134,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBuildings); Planet abaCelestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Fast) as Planet; + _tbotInstance.UserData.celestials = await _tbotOgameBridge.UpdateCelestials(); if ( (!SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Brain.AutoMine, "BuildCrawlers") || (bool) _tbotInstance.InstanceSettings.Brain.AutoMine.BuildCrawlers) && celestial.Coordinate.Type == Celestials.Planet && @@ -297,141 +298,140 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings } if (buildable == Buildables.SolarSatellite || buildable == Buildables.Crawler) { DoLog(LogLevel.Information, $"Not enough resources to build: {level.ToString()}x {buildable.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {celestial.Resources.TransportableResources}"); - } else { DoLog(LogLevel.Information, $"Not enough resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {celestial.Resources.TransportableResources}"); } if ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Transports.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active) { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new(); - RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, - (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && - (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && - ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); - RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); - RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); - RankSlotsPriority ColonizeRank = new(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); - RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); - RankSlotsPriority presentFeature = BrainRank; - rankSlotsPriority.Add(BrainRank); - rankSlotsPriority.Add(ExpeditionsRank); - rankSlotsPriority.Add(AutoFarmRank); - rankSlotsPriority.Add(ColonizeRank); - rankSlotsPriority.Add(AutoDiscoveryRank); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - string msg = ""; - int reservedSlots = 0; - int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; - int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && - fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && - fleet.Mission != Missions.Spy && - fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery) - ).Count(); - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); - foreach (RankSlotsPriority feature in rankSlotsPriority) { - if (feature == presentFeature) - continue; - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { - msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; - reservedSlots += feature.MaxSlots; - } else { - otherSlots += feature.SlotsUsed; - } - } - if (otherSlots > 0) - msg = $"{msg}, {otherSlots} are used for Other"; - int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; - tempsValue = tempsValue < 0 ? 0 : tempsValue; - DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); - if (reservedSlots + otherSlots + presentFeature.SlotsUsed > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); - MaxSlots = 0; - } else if (MaxSlots > tempsValue) { - MaxSlots = tempsValue; - DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); - } - + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + new RankSlotsPriority(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal), + new RankSlotsPriority(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + new RankSlotsPriority(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1), + new RankSlotsPriority(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + new RankSlotsPriority(Feature.Harvest, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.BrainAutoMine, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); + if (MaxSlots > 0) { - if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { - Celestial origin; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { - origin = _tbotInstance.UserData.celestials - .Unique() - .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) - .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) - .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) - .Where(c => c.Coordinate.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { + Celestial origin = new() { ID = 0 }; + List allCelestials = _tbotInstance.UserData.celestials; + for (int i = 0; i < allCelestials.Count(); i++) { + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.LFBonuses); + } + Resources missingResources = xCostBuildable.Difference(celestial.Resources); + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst) { + if (celestial.Coordinate.Type == Celestials.Planet && ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(allCelestials, celestial))) { + origin = allCelestials.Unique() + .Where(c => c.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, xCostBuildable, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + if (celestial.Coordinate.Type == Celestials.Moon) { + origin = allCelestials.Unique() + .Where(c => c.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == Celestials.Planet) + .SingleOrDefault() ?? new() { ID = 0 }; + } + if (origin.Resources.IsEnoughFor(missingResources) && origin.ID != 0) { + missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; + } + long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { + Ships ships = new(); + ships.Add((Buildables) preferredShip, shipsNeeded); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); + Ships ships = new(); + ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); + Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); + } + } else { + DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); } } if (fleetId <= 0) { if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active) { - var resultOrigins = new Dictionary(); - List allCelestials = _tbotInstance.UserData.celestials; + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) + .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) + .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) + .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) + .SingleOrDefault() ?? new() { ID = 0 }; List celestialsToExclude = _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Exclude, allCelestials); - for (int i = 0; i < allCelestials.Count(); i++) { - allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); - allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; } - List closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons ? - allCelestials - .Where(planet => !celestialsToExclude.Has(planet)) - .Where(planet => planet.Resources.TotalResources > 0) - .Where(planet => planet.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) - .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) - .ToList(): - allCelestials - .Where(c => !celestialsToExclude.Has(c)) - .Where(c => c.Resources.TotalResources > 0) - .Where(c => c.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) - .ToList(); - - closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity ? - closestCelestials.OrderBy(c => _calculationService.CalcDistance(c.Coordinate, celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList() : - closestCelestials.OrderByDescending(c => c.Resources.TotalResources).ToList(); - - Resources missingResources = xCostBuildable.Difference(celestial.Resources); - Resources resourcesTotalAvailable = new(); - Resources possibleResources = new(); - + TransportSettings transportsSettings = new((bool) _tbotInstance.InstanceSettings.Brain.Transports.Active, + preferredShip, + (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeaveOnMoons, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.RoundResources, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible, + origin, + (long) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition, + new MultipleOrigins((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons, + (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity, + celestialsToExclude) + ); + Celestial destination; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + if ((bool) transportsSettings.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial)) { destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) @@ -439,7 +439,8 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; - missingResources = xCostBuildable.Difference(destination.Resources); + if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) + destination = celestial; } else { destination = allCelestials .Unique() @@ -449,84 +450,29 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) .SingleOrDefault() ?? new() { ID = 0 }; } - closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); - if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { - DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); - return; - } - Buildables preferredShip = Buildables.SmallCargo; - if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); - preferredShip = Buildables.SmallCargo; - } - long idealShips; + var resultOrigins = _calculationService.CalcMultipleOrigin(celestial, allCelestials, missingResources, transportsSettings, _tbotInstance.UserData.fleets, _tbotInstance.UserData); - foreach (var possibleOrigin in closestCelestials) { - //if (!celestialsToExclude.Has(possibleOrigin)) // if .Where(planet => !celestialsToExclude.Has(planet)) don't work - if (!_calculationService.IsThereTransportTowardsCelestial(possibleOrigin, _tbotInstance.UserData.fleets)) - possibleResources = possibleResources.Sum(possibleOrigin.Resources); - } - if (!possibleResources.IsEnoughFor(xCostBuildable)) { - possibleResources = possibleResources.Sum(celestial.Resources); - DoLog(LogLevel.Information, $"Not enough resources available on all celestials to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); + if (resultOrigins.Count() == 0) { + DoLog(LogLevel.Information, $"No origin is available. This may be due to a lack of resources or cargo."); + delay = true; return; } - - Celestial moonDestination = new(); - foreach (var possibleOrigin in closestCelestials) { - possibleResources = new(); - Celestial tempPossibleOrigin = possibleOrigin; - tempPossibleOrigin.Resources.Deuterium = (tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) > 0 ? tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave : 0; - if (tempPossibleOrigin.Resources.Metal < missingResources.Metal - resourcesTotalAvailable.Metal) - possibleResources.Metal = tempPossibleOrigin.Resources.Metal; - else - possibleResources.Metal = missingResources.Metal - resourcesTotalAvailable.Metal; - if (tempPossibleOrigin.Resources.Crystal < missingResources.Crystal - resourcesTotalAvailable.Crystal) - possibleResources.Crystal = tempPossibleOrigin.Resources.Crystal; - else - possibleResources.Crystal = missingResources.Crystal - resourcesTotalAvailable.Crystal; - if (tempPossibleOrigin.Resources.Deuterium < missingResources.Deuterium - resourcesTotalAvailable.Deuterium) - possibleResources.Deuterium = tempPossibleOrigin.Resources.Deuterium; - else - possibleResources.Deuterium = missingResources.Deuterium - resourcesTotalAvailable.Deuterium; - - idealShips = _calculationService.CalcShipNumberForPayload(possibleResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (idealShips > possibleOrigin.Ships.GetAmount(preferredShip) || - possibleResources.TotalResources <= (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend || - _calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)) - continue; - - resourcesTotalAvailable = resourcesTotalAvailable.Sum(possibleResources); - resultOrigins.Add(tempPossibleOrigin, possibleResources); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{tempPossibleOrigin.ToString()} add with {possibleResources.TotalResources} - ({resultOrigins.Count}) {_calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)}"); - if (resourcesTotalAvailable.IsEnoughFor(missingResources)) - break; - } - - if (resultOrigins.Count > MaxSlots) { + if (resultOrigins.Count() > MaxSlots) { DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); delay = true; return; } - - possibleResources = new(); - foreach (var (originMultiple, resourcesValue) in resultOrigins) { - possibleResources = possibleResources.Sum(resourcesValue); - } - if (!possibleResources.IsEnoughFor(missingResources)) { - possibleResources = possibleResources.Sum(celestial.Resources); - DoLog(LogLevel.Information, $"Not enough cargo available on all celestials to transport resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); - return; - } Ships ships = new(); - var fleetID = 0; - foreach (var (originMultiple, resourcesValue) in resultOrigins) { + + foreach (var item in resultOrigins) { ships = new(); - ships.Add(preferredShip, _calculationService.CalcShipNumberForPayload(resourcesValue, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); - - fleetID = await _fleetScheduler.SendFleet(originMultiple, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, resourcesValue); + ships.Add((Buildables) transportsSettings.CargoType, _calculationService.CalcShipNumberForPayload(item.FirstOrDefault().Value, (Buildables) transportsSettings.CargoType, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(transportsSettings.CargoType), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); + if (item.FirstOrDefault().Key.Coordinate.IsSame(destination.Coordinate) && transportsSettings.SendToTheMoonIfPossible && destination.Coordinate.Type == Celestials.Moon) + fleetId= await _fleetScheduler.SendFleet(item.FirstOrDefault().Key, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, item.FirstOrDefault().Value); + else + fleetId= await _fleetScheduler.SendFleet(item.FirstOrDefault().Key, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, item.FirstOrDefault().Value); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; @@ -539,15 +485,18 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings } else { Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { - destination = _tbotInstance.UserData.celestials + destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; + if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) + destination = celestial; + missingResources = missingResources.Difference(destination.Resources); } else { - destination = _tbotInstance.UserData.celestials + destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) @@ -555,14 +504,14 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) .SingleOrDefault() ?? new() { ID = 0 }; } - origin = _tbotInstance.UserData.celestials + origin = allCelestials .Unique() .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, xCostBuildable, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); + fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, missingResources, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } @@ -573,9 +522,17 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings } } else { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); + fleetId = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) + .Where(f => f.Resources.TotalResources > 0) + .Where(f => f.ReturnFlight == false) + .Where(f => f.Destination.Galaxy == celestial.Coordinate.Galaxy) + .Where(f => f.Destination.System == celestial.Coordinate.System) + .Where(f => f.Destination.Position == celestial.Coordinate.Position) + .Where(f => f.Destination.Type == celestial.Coordinate.Type) + .First().ID; } } else { - if (_tbotInstance.InstanceSettings.Brain.SlotPriorityLevel > 0) { + if (_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain > 0) { if (_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots == 0) DoLog(LogLevel.Information, $"Transports.MaxSlots is set to 0, you should increase it."); else @@ -683,15 +640,16 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); } if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { - var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) - .Where(f => f.Destination.IsSame(celestial.Coordinate)) - .Where(f => f.Origin.Galaxy == celestial.Coordinate.Galaxy) - .Where(f => f.Origin.System == celestial.Coordinate.System) - .Where(f => f.Origin.Position == celestial.Coordinate.Position) - .Where(f => f.Origin.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) - .ToList(); - if (transportfleet2.Count() > 0) { - interval = (long) (transportfleet2.First().BackIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + if (_tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport).Count() > 0) { + var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) + .Where(f => f.Destination.IsSame(celestial.Coordinate)) + .Where(f => f.Origin.Galaxy == celestial.Coordinate.Galaxy) + .Where(f => f.Origin.System == celestial.Coordinate.System) + .Where(f => f.Origin.Position == celestial.Coordinate.Position) + .Where(f => f.Origin.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + .ToList(); + if (transportfleet2.Count() > 0) + interval = (long) (transportfleet2.First().BackIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } } diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index a314a4e0..660e3c7d 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -41,6 +41,7 @@ protected override async Task Execute() { DoLog(LogLevel.Information, "Running autoresearch..."); _tbotInstance.UserData.researches = await _ogameService.GetResearches(); + _tbotInstance.UserData.celestials = await _tbotOgameBridge.UpdateCelestials(); _tbotInstance.UserData.celestials = await _tbotOgameBridge.UpdatePlanets(UpdateTypes.LFBonuses); Planet celestial; var parseSucceded = _tbotInstance.UserData.celestials @@ -177,135 +178,134 @@ protected override async Task Execute() { if ((bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Transports.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active) { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new(); - RankSlotsPriority BrainRank = new(Feature.BrainAutoResearch, - (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && - (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && - ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); - RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); - RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); - RankSlotsPriority ColonizeRank = new(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); - RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); - RankSlotsPriority presentFeature = BrainRank; - rankSlotsPriority.Add(BrainRank); - rankSlotsPriority.Add(ExpeditionsRank); - rankSlotsPriority.Add(AutoFarmRank); - rankSlotsPriority.Add(ColonizeRank); - rankSlotsPriority.Add(AutoDiscoveryRank); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - string msg = ""; - int reservedSlots = 0; - int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; - int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && - fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && - fleet.Mission != Missions.Spy && - fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery) - ).Count(); - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); - foreach (RankSlotsPriority feature in rankSlotsPriority) { - if (feature == presentFeature) - continue; - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { - msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; - reservedSlots += feature.MaxSlots; - } else { - otherSlots += feature.SlotsUsed; - } - } - if (otherSlots > 0) - msg = $"{msg}, {otherSlots} are used for Other"; - int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; - tempsValue = tempsValue < 0 ? 0 : tempsValue; - DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); - if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); - MaxSlots = 0; - } else if (MaxSlots > tempsValue) { - MaxSlots = tempsValue; - DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); - } - + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainAutoResearch, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + new RankSlotsPriority(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal), + new RankSlotsPriority(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + new RankSlotsPriority(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1), + new RankSlotsPriority(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + new RankSlotsPriority(Feature.Harvest, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.BrainAutoResearch, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); + if (MaxSlots > 0) { if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { - Celestial origin; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { - origin = _tbotInstance.UserData.celestials - .Unique() - .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) - .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) - .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) - .Where(c => c.Coordinate.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + Celestial origin = new() { ID = 0 }; + List allCelestials = _tbotInstance.UserData.celestials; + for (int i = 0; i < allCelestials.Count(); i++) { + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.LFBonuses); + } + Resources missingResources = cost.Difference(celestial.Resources); + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst) { + if (celestial.Coordinate.Type == Celestials.Planet && ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(allCelestials, celestial))) { + origin = allCelestials.Unique() + .Where(c => c.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, cost, Buildables.Null); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + if (celestial.Coordinate.Type == Celestials.Moon) { + origin = allCelestials.Unique() + .Where(c => c.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == Celestials.Planet) + .SingleOrDefault() ?? new() { ID = 0 }; + } + if (origin.Resources.IsEnoughFor(missingResources) && origin.ID != 0) { + missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; + } + long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { + Ships ships = new(); + ships.Add((Buildables) preferredShip, shipsNeeded); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); + Ships ships = new(); + ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); + Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); + } + } else { + DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); } } if (fleetId <= 0) { if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active) { - var resultOrigins = new Dictionary(); - List allCelestials = _tbotInstance.UserData.celestials; + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) + .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) + .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) + .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) + .SingleOrDefault() ?? new() { ID = 0 }; List celestialsToExclude = _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Exclude, allCelestials); - for (int i = 0; i < allCelestials.Count(); i++) { - allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); - allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; } - List closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons ? - allCelestials - .Unique() - .Where(planet => !celestialsToExclude.Has(planet)) - .Where(planet => planet.Resources.TotalResources > 0) - .Where(planet => planet.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) - .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) - .ToList(): - allCelestials - .Where(c => !celestialsToExclude.Has(c)) - .Where(c => c.Resources.TotalResources > 0) - .Where(c => c.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) - .ToList(); - - closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity ? - closestCelestials.OrderBy(c => _calculationService.CalcDistance(c.Coordinate, celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList() : - closestCelestials.OrderByDescending(c => c.Resources.TotalResources).ToList(); - - Resources missingResources = cost.Difference(celestial.Resources); - Resources resourcesTotalAvailable = new(); - Resources possibleResources = new(); - + TransportSettings transportsSettings = new((bool) _tbotInstance.InstanceSettings.Brain.Transports.Active, + preferredShip, + (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeaveOnMoons, + (bool)_tbotInstance.InstanceSettings.Brain.Transports.RoundResources, + (bool)_tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible, + origin, + (long) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (bool)_tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst, + (bool)_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition, + new MultipleOrigins((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons, + (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity, + celestialsToExclude) + ); + Celestial destination; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + if ((bool) transportsSettings.SendToTheMoonIfPossible && _calculationService.IsThereMoonHere(allCelestials, celestial)) { destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) @@ -313,94 +313,34 @@ protected override async Task Execute() { .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; - missingResources = cost.Difference(destination.Resources); + if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) + destination = celestial; } else { - destination = allCelestials - .Unique() - .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) - .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) - .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) - .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .SingleOrDefault() ?? new() { ID = 0 }; - } - closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); - if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { - DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); - return; + destination = celestial; } - Buildables preferredShip = Buildables.SmallCargo; - if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); - preferredShip = Buildables.SmallCargo; - } - long idealShips; + var resultOrigins = _calculationService.CalcMultipleOrigin(celestial, allCelestials, missingResources, transportsSettings, _tbotInstance.UserData.fleets, _tbotInstance.UserData); - foreach (var possibleOrigin in closestCelestials) { - //if (!celestialsToExclude.Has(possibleOrigin)) // if .Where(planet => !celestialsToExclude.Has(planet)) don't work - if (!_calculationService.IsThereTransportTowardsCelestial(possibleOrigin, _tbotInstance.UserData.fleets)) - possibleResources = possibleResources.Sum(possibleOrigin.Resources); - } - if (!possibleResources.IsEnoughFor(cost)) { - possibleResources = possibleResources.Sum(celestial.Resources); - DoLog(LogLevel.Information, $"Not enough resources available on all celestials to build: {research.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {cost.TransportableResources} - Available: {possibleResources.TransportableResources}"); + if (resultOrigins.Count() == 0) { + DoLog(LogLevel.Information, $"No origin is available. This may be due to a lack of resources or cargo."); + delay = true; return; } - - Celestial moonDestination = new(); - foreach (var possibleOrigin in closestCelestials) { - possibleResources = new(); - Celestial tempPossibleOrigin = possibleOrigin; - tempPossibleOrigin.Resources.Deuterium = (tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) > 0 ? tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave : 0; - if (tempPossibleOrigin.Resources.Metal < missingResources.Metal - resourcesTotalAvailable.Metal) - possibleResources.Metal = tempPossibleOrigin.Resources.Metal; - else - possibleResources.Metal = missingResources.Metal - resourcesTotalAvailable.Metal; - if (tempPossibleOrigin.Resources.Crystal < missingResources.Crystal - resourcesTotalAvailable.Crystal) - possibleResources.Crystal = tempPossibleOrigin.Resources.Crystal; - else - possibleResources.Crystal = missingResources.Crystal - resourcesTotalAvailable.Crystal; - if (tempPossibleOrigin.Resources.Deuterium < missingResources.Deuterium - resourcesTotalAvailable.Deuterium) - possibleResources.Deuterium = tempPossibleOrigin.Resources.Deuterium; - else - possibleResources.Deuterium = missingResources.Deuterium - resourcesTotalAvailable.Deuterium; - - idealShips = _calculationService.CalcShipNumberForPayload(possibleResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (idealShips > possibleOrigin.Ships.GetAmount(preferredShip) || - possibleResources.TotalResources <= (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend || - _calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)) - continue; - - resourcesTotalAvailable = resourcesTotalAvailable.Sum(possibleResources); - resultOrigins.Add(tempPossibleOrigin, possibleResources); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{tempPossibleOrigin.ToString()} add with {possibleResources.TotalResources} - ({resultOrigins.Count}) {_calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)}"); - if (resourcesTotalAvailable.IsEnoughFor(missingResources)) - break; - } - - if (resultOrigins.Count > MaxSlots) { + if (resultOrigins.Count() > MaxSlots) { DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {research.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); delay = true; return; } - - possibleResources = new(); - foreach (var (originMultiple, resourcesValue) in resultOrigins) { - possibleResources = possibleResources.Sum(resourcesValue); - } - if (!possibleResources.IsEnoughFor(missingResources)) { - possibleResources = possibleResources.Sum(celestial.Resources); - DoLog(LogLevel.Information, $"Not enough cargo available on all celestials to transport resources to build: {research.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {cost.TransportableResources} - Available: {possibleResources.TransportableResources}"); - return; - } Ships ships = new(); - var fleetID = 0; - foreach (var (originMultiple, resourcesValue) in resultOrigins) { + + foreach (var item in resultOrigins) { ships = new(); - ships.Add(preferredShip, _calculationService.CalcShipNumberForPayload(resourcesValue, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); - - fleetID = await _fleetScheduler.SendFleet(originMultiple, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, resourcesValue); + ships.Add((Buildables) transportsSettings.CargoType, _calculationService.CalcShipNumberForPayload(item.FirstOrDefault().Value, (Buildables) transportsSettings.CargoType, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(transportsSettings.CargoType), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); + if (item.FirstOrDefault().Key.Coordinate.IsSame(destination.Coordinate) && transportsSettings.SendToTheMoonIfPossible && destination.Coordinate.Type == Celestials.Moon) + fleetId= await _fleetScheduler.SendFleet(item.FirstOrDefault().Key, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, item.FirstOrDefault().Value); + else + fleetId= await _fleetScheduler.SendFleet(item.FirstOrDefault().Key, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, item.FirstOrDefault().Value); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; @@ -413,15 +353,18 @@ protected override async Task Execute() { } else { Celestial destination; if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { - destination = _tbotInstance.UserData.celestials + destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; + if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) + destination = celestial; + missingResources = missingResources.Difference(destination.Resources); } else { - destination = _tbotInstance.UserData.celestials + destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) @@ -429,14 +372,15 @@ protected override async Task Execute() { .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) .SingleOrDefault() ?? new() { ID = 0 }; } - origin = _tbotInstance.UserData.celestials + origin = allCelestials .Unique() .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, cost, Buildables.Null); if (fleetId == (int) SendFleetCode.AfterSleepTime) { + fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, missingResources, Buildables.Null); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } if (fleetId == (int) SendFleetCode.NotEnoughSlots) { @@ -446,20 +390,17 @@ protected override async Task Execute() { } } else { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); - fleetId = (_tbotInstance.UserData.fleets - .Where(f => f.Mission == Missions.Transport) + fleetId = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) .Where(f => f.Resources.TotalResources > 0) .Where(f => f.ReturnFlight == false) .Where(f => f.Destination.Galaxy == celestial.Coordinate.Galaxy) .Where(f => f.Destination.System == celestial.Coordinate.System) .Where(f => f.Destination.Position == celestial.Coordinate.Position) .Where(f => f.Destination.Type == celestial.Coordinate.Type) - .OrderByDescending(f => f.ArriveIn) - .FirstOrDefault() ?? new() { ID = 0 }) - .ID; + .First().ID; } } else { - if (_tbotInstance.InstanceSettings.Brain.SlotPriorityLevel > 0) { + if (_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain > 0) { if (_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots == 0) DoLog(LogLevel.Information, $"Transports.MaxSlots is set to 0, you should increase it."); else diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index c9e5eede..24a0e98c 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -184,134 +184,126 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { if ((bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Transports.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active) { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new(); - RankSlotsPriority BrainRank = new(Feature.BrainLifeformAutoMine, - (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && - (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && - ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); - RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); - RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); - RankSlotsPriority ColonizeRank = new(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); - RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); - RankSlotsPriority presentFeature = BrainRank; - rankSlotsPriority.Add(BrainRank); - rankSlotsPriority.Add(ExpeditionsRank); - rankSlotsPriority.Add(AutoFarmRank); - rankSlotsPriority.Add(ColonizeRank); - rankSlotsPriority.Add(AutoDiscoveryRank); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - string msg = ""; - int reservedSlots = 0; - int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; - int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && - fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && - fleet.Mission != Missions.Spy && - fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery) - ).Count(); - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); - foreach (RankSlotsPriority feature in rankSlotsPriority) { - if (feature == presentFeature) - continue; - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { - msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; - reservedSlots += feature.MaxSlots; - } else { - otherSlots += feature.SlotsUsed; - } - } - if (otherSlots > 0) - msg = $"{msg}, {otherSlots} are used for Other"; - int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; - tempsValue = tempsValue < 0 ? 0 : tempsValue; - DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); - if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); - MaxSlots = 0; - } else if (MaxSlots > tempsValue) { - MaxSlots = tempsValue; - DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); - } - + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainLifeformAutoMine, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + new RankSlotsPriority(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal), + new RankSlotsPriority(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + new RankSlotsPriority(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1), + new RankSlotsPriority(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + new RankSlotsPriority(Feature.Harvest, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.BrainLifeformAutoMine, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); + if (MaxSlots > 0) { if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { - Celestial origin; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { - origin = _tbotInstance.UserData.celestials - .Unique() - .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) - .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) - .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) - .Where(c => c.Coordinate.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + Celestial origin = new() { ID = 0 }; + List allCelestials = _tbotInstance.UserData.celestials; + for (int i = 0; i < allCelestials.Count(); i++) { + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.LFBonuses); + } + Resources missingResources = xCostBuildable.Difference(celestial.Resources); + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst) { + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(allCelestials, celestial)) { + origin = allCelestials.Unique() + .Where(c => c.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, xCostBuildable, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + if (origin.Resources.IsEnoughFor(missingResources) && origin.ID != 0) { + missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; + } + long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { + Ships ships = new(); + ships.Add((Buildables) preferredShip, shipsNeeded); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); + Ships ships = new(); + ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); + Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); + } + } else { + DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); } } if (fleetId <= 0) { if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active) { - var resultOrigins = new Dictionary(); - List allCelestials = _tbotInstance.UserData.celestials; + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) + .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) + .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) + .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) + .SingleOrDefault() ?? new() { ID = 0 }; List celestialsToExclude = _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Exclude, allCelestials); - for (int i = 0; i < allCelestials.Count(); i++) { - allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); - allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; } - List closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons ? - allCelestials - .Where(planet => !celestialsToExclude.Has(planet)) - .Where(planet => planet.Resources.TotalResources > 0) - .Where(planet => planet.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) - .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) - .ToList(): - allCelestials - .Where(c => !celestialsToExclude.Has(c)) - .Where(c => c.Resources.TotalResources > 0) - .Where(c => c.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) - .ToList(); - - closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity ? - closestCelestials.OrderBy(c => _calculationService.CalcDistance(c.Coordinate, celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList() : - closestCelestials.OrderByDescending(c => c.Resources.TotalResources).ToList(); - - Resources missingResources = xCostBuildable.Difference(celestial.Resources); - Resources resourcesTotalAvailable = new(); - Resources possibleResources = new(); - + TransportSettings transportsSettings = new((bool) _tbotInstance.InstanceSettings.Brain.Transports.Active, + preferredShip, + (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeaveOnMoons, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.RoundResources, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible, + origin, + (long) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition, + new MultipleOrigins((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons, + (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity, + celestialsToExclude) + ); + Celestial destination; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + if ((bool) transportsSettings.SendToTheMoonIfPossible && _calculationService.IsThereMoonHere(allCelestials, celestial)) { destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) @@ -319,94 +311,34 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; - missingResources = xCostBuildable.Difference(destination.Resources); + if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) + destination = celestial; } else { - destination = allCelestials - .Unique() - .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) - .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) - .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) - .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .SingleOrDefault() ?? new() { ID = 0 }; - } - closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); - if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { - DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); - return; - } - - Buildables preferredShip = Buildables.SmallCargo; - if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); - preferredShip = Buildables.SmallCargo; - } - long idealShips; - - foreach (var possibleOrigin in closestCelestials) { - //if (!celestialsToExclude.Has(possibleOrigin)) // if .Where(planet => !celestialsToExclude.Has(planet)) don't work - if (!_calculationService.IsThereTransportTowardsCelestial(possibleOrigin, _tbotInstance.UserData.fleets)) - possibleResources = possibleResources.Sum(possibleOrigin.Resources); - } - if (!possibleResources.IsEnoughFor(xCostBuildable)) { - possibleResources = possibleResources.Sum(celestial.Resources); - DoLog(LogLevel.Information, $"Not enough resources available on all celestials to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); - return; + destination = celestial; } - Celestial moonDestination = new(); - foreach (var possibleOrigin in closestCelestials) { - possibleResources = new(); - Celestial tempPossibleOrigin = possibleOrigin; - tempPossibleOrigin.Resources.Deuterium = (tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) > 0 ? tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave : 0; - if (tempPossibleOrigin.Resources.Metal < missingResources.Metal - resourcesTotalAvailable.Metal) - possibleResources.Metal = tempPossibleOrigin.Resources.Metal; - else - possibleResources.Metal = missingResources.Metal - resourcesTotalAvailable.Metal; - if (tempPossibleOrigin.Resources.Crystal < missingResources.Crystal - resourcesTotalAvailable.Crystal) - possibleResources.Crystal = tempPossibleOrigin.Resources.Crystal; - else - possibleResources.Crystal = missingResources.Crystal - resourcesTotalAvailable.Crystal; - if (tempPossibleOrigin.Resources.Deuterium < missingResources.Deuterium - resourcesTotalAvailable.Deuterium) - possibleResources.Deuterium = tempPossibleOrigin.Resources.Deuterium; - else - possibleResources.Deuterium = missingResources.Deuterium - resourcesTotalAvailable.Deuterium; - - idealShips = _calculationService.CalcShipNumberForPayload(possibleResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (idealShips > possibleOrigin.Ships.GetAmount(preferredShip) || - possibleResources.TotalResources <= (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend || - _calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)) - continue; - - resourcesTotalAvailable = resourcesTotalAvailable.Sum(possibleResources); - resultOrigins.Add(tempPossibleOrigin, possibleResources); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{tempPossibleOrigin.ToString()} add with {possibleResources.TotalResources} - ({resultOrigins.Count}) {_calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)}"); - if (resourcesTotalAvailable.IsEnoughFor(missingResources)) - break; - } + var resultOrigins = _calculationService.CalcMultipleOrigin(celestial, allCelestials, missingResources, transportsSettings, _tbotInstance.UserData.fleets, _tbotInstance.UserData); - if (resultOrigins.Count > MaxSlots) { - DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + if (resultOrigins.Count() == 0) { + DoLog(LogLevel.Information, $"No origin is available. This may be due to a lack of resources or cargo."); delay = true; return; } - - possibleResources = new(); - foreach (var (originMultiple, resourcesValue) in resultOrigins) { - possibleResources = possibleResources.Sum(resourcesValue); - } - if (!possibleResources.IsEnoughFor(missingResources)) { - possibleResources = possibleResources.Sum(celestial.Resources); - DoLog(LogLevel.Information, $"Not enough cargo available on all celestials to transport resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); + if (resultOrigins.Count() > MaxSlots) { + DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + delay = true; return; } Ships ships = new(); - var fleetID = 0; - foreach (var (originMultiple, resourcesValue) in resultOrigins) { + + foreach (var item in resultOrigins) { ships = new(); - ships.Add(preferredShip, _calculationService.CalcShipNumberForPayload(resourcesValue, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); - - fleetID = await _fleetScheduler.SendFleet(originMultiple, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, resourcesValue); + ships.Add((Buildables) transportsSettings.CargoType, _calculationService.CalcShipNumberForPayload(item.FirstOrDefault().Value, (Buildables) transportsSettings.CargoType, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(transportsSettings.CargoType), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); + if (item.FirstOrDefault().Key.Coordinate.IsSame(destination.Coordinate) && transportsSettings.SendToTheMoonIfPossible && destination.Coordinate.Type == Celestials.Moon) + fleetId= await _fleetScheduler.SendFleet(item.FirstOrDefault().Key, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, item.FirstOrDefault().Value); + else + fleetId= await _fleetScheduler.SendFleet(item.FirstOrDefault().Key, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, item.FirstOrDefault().Value); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; @@ -418,16 +350,19 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { } } else { Celestial destination; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { - destination = _tbotInstance.UserData.celestials + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { + destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; + if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) + destination = celestial; + missingResources = missingResources.Difference(destination.Resources); } else { - destination = _tbotInstance.UserData.celestials + destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) @@ -435,14 +370,14 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) .SingleOrDefault() ?? new() { ID = 0 }; } - origin = _tbotInstance.UserData.celestials + origin = allCelestials .Unique() .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, xCostBuildable, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); + fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, missingResources, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } @@ -463,7 +398,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .First().ID; } } else { - if (_tbotInstance.InstanceSettings.Brain.SlotPriorityLevel > 0) { + if (_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain > 0) { if (_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots == 0) DoLog(LogLevel.Information, $"Transports.MaxSlots is set to 0, you should increase it."); else diff --git a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs index a9ac434a..648ff526 100644 --- a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs @@ -87,6 +87,15 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { long delayTime = 0; long interval = 0; _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + List planets = new(); + foreach (var p in _tbotInstance.UserData.celestials) { + if (p.Coordinate.Type == Celestials.Planet) { + var newPlanet = await _tbotOgameBridge.UpdatePlanet(p, UpdateTypes.Facilities); + newPlanet = await _tbotOgameBridge.UpdatePlanet(p, UpdateTypes.Buildings); + newPlanet = await _tbotOgameBridge.UpdatePlanet(p, UpdateTypes.LFBonuses); + planets.Add(newPlanet); + } + } try { DoLog(LogLevel.Information, $"Running Lifeform AutoResearch on {celestial.ToString()}"); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Fast); @@ -185,134 +194,126 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { if ((bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Transports.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active) { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new(); - RankSlotsPriority BrainRank = new(Feature.BrainLifeformAutoResearch, - (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && - (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && - ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); - RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); - RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); - RankSlotsPriority ColonizeRank = new(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); - RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); - RankSlotsPriority presentFeature = BrainRank; - rankSlotsPriority.Add(BrainRank); - rankSlotsPriority.Add(ExpeditionsRank); - rankSlotsPriority.Add(AutoFarmRank); - rankSlotsPriority.Add(ColonizeRank); - rankSlotsPriority.Add(AutoDiscoveryRank); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - string msg = ""; - int reservedSlots = 0; - int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; - int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && - fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && - fleet.Mission != Missions.Spy && - fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery) - ).Count(); - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); - foreach (RankSlotsPriority feature in rankSlotsPriority) { - if (feature == presentFeature) - continue; - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { - msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; - reservedSlots += feature.MaxSlots; - } else { - otherSlots += feature.SlotsUsed; - } - } - if (otherSlots > 0) - msg = $"{msg}, {otherSlots} are used for Other"; - int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; - tempsValue = tempsValue < 0 ? 0 : tempsValue; - DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); - if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); - MaxSlots = 0; - } else if (MaxSlots > tempsValue) { - MaxSlots = tempsValue; - DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); - } - + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainLifeformAutoResearch, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + new RankSlotsPriority(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal), + new RankSlotsPriority(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + new RankSlotsPriority(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1), + new RankSlotsPriority(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + new RankSlotsPriority(Feature.Harvest, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.BrainLifeformAutoResearch, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); + if (MaxSlots > 0) { if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { - Celestial origin; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { - origin = _tbotInstance.UserData.celestials - .Unique() - .Where(c => c.Coordinate.Galaxy == (int) celestial.Coordinate.Galaxy) - .Where(c => c.Coordinate.System == (int) celestial.Coordinate.System) - .Where(c => c.Coordinate.Position == (int) celestial.Coordinate.Position) - .Where(c => c.Coordinate.Type == (celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet)) + Celestial origin = new() { ID = 0 }; + List allCelestials = _tbotInstance.UserData.celestials; + for (int i = 0; i < allCelestials.Count(); i++) { + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.LFBonuses); + } + Resources missingResources = xCostBuildable.Difference(celestial.Resources); + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst) { + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst && _calculationService.IsThereMoonHere(allCelestials, celestial)) { + origin = allCelestials.Unique() + .Where(c => c.Coordinate.Galaxy == celestial.Coordinate.Galaxy) + .Where(c => c.Coordinate.System == celestial.Coordinate.System) + .Where(c => c.Coordinate.Position == celestial.Coordinate.Position) + .Where(c => c.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, xCostBuildable, LFBuildables.None); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + if (origin.Resources.IsEnoughFor(missingResources) && origin.ID != 0) { + missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; + } + long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { + Ships ships = new(); + ships.Add((Buildables) preferredShip, shipsNeeded); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); + Ships ships = new(); + ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); + Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); + } + } else { + DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); } } if (fleetId <= 0) { if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active) { - var resultOrigins = new Dictionary(); - List allCelestials = _tbotInstance.UserData.celestials; + origin = _tbotInstance.UserData.celestials + .Unique() + .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) + .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) + .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) + .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) + .SingleOrDefault() ?? new() { ID = 0 }; List celestialsToExclude = _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Exclude, allCelestials); - for (int i = 0; i < allCelestials.Count(); i++) { - allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Resources); - allCelestials[i] = await _tbotOgameBridge.UpdatePlanet(allCelestials[i], UpdateTypes.Ships); + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; } - List closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons ? - allCelestials - .Where(planet => !celestialsToExclude.Has(planet)) - .Where(planet => planet.Resources.TotalResources > 0) - .Where(planet => planet.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) - .Where(planet => planet.Coordinate.Type == Celestials.Moon) - .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) - .ToList(): - allCelestials - .Where(c => !celestialsToExclude.Has(c)) - .Where(c => c.Resources.TotalResources > 0) - .Where(c => c.Resources.Deuterium > (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) - .ToList(); - - closestCelestials = (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity ? - closestCelestials.OrderBy(c => _calculationService.CalcDistance(c.Coordinate, celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList() : - closestCelestials.OrderByDescending(c => c.Resources.TotalResources).ToList(); - - Resources missingResources = xCostBuildable.Difference(celestial.Resources); - Resources resourcesTotalAvailable = new(); - Resources possibleResources = new(); - + TransportSettings transportsSettings = new((bool) _tbotInstance.InstanceSettings.Brain.Transports.Active, + preferredShip, + (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeaveOnMoons, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.RoundResources, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible, + origin, + (long) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.CheckMoonOrPlanetFirst, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition, + new MultipleOrigins((bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.Active, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.OnlyFromMoons, + (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend, + (bool) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.PriorityToProximityOverQuantity, + celestialsToExclude) + ); + Celestial destination; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(allCelestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { + if ((bool) transportsSettings.SendToTheMoonIfPossible && _calculationService.IsThereMoonHere(allCelestials, celestial)) { destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) @@ -320,94 +321,34 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; - missingResources = xCostBuildable.Difference(destination.Resources); + if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) + destination = celestial; } else { - destination = allCelestials - .Unique() - .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) - .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) - .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) - .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) - .SingleOrDefault() ?? new() { ID = 0 }; - } - closestCelestials = closestCelestials.Where(c => !c.Coordinate.IsSame(destination.Coordinate)).ToList(); - if (_calculationService.IsThereTransportTowardsCelestial(destination, _tbotInstance.UserData.fleets)) { - DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {destination.ToString()}"); - return; - } - - Buildables preferredShip = Buildables.SmallCargo; - if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); - preferredShip = Buildables.SmallCargo; - } - long idealShips; - - foreach (var possibleOrigin in closestCelestials) { - //if (!celestialsToExclude.Has(possibleOrigin)) // if .Where(planet => !celestialsToExclude.Has(planet)) don't work - if (!_calculationService.IsThereTransportTowardsCelestial(possibleOrigin, _tbotInstance.UserData.fleets)) - possibleResources = possibleResources.Sum(possibleOrigin.Resources); - } - if (!possibleResources.IsEnoughFor(xCostBuildable)) { - possibleResources = possibleResources.Sum(celestial.Resources); - DoLog(LogLevel.Information, $"Not enough resources available on all celestials to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); - return; + destination = celestial; } - Celestial moonDestination = new(); - foreach (var possibleOrigin in closestCelestials) { - possibleResources = new(); - Celestial tempPossibleOrigin = possibleOrigin; - tempPossibleOrigin.Resources.Deuterium = (tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave) > 0 ? tempPossibleOrigin.Resources.Deuterium - (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave : 0; - if (tempPossibleOrigin.Resources.Metal < missingResources.Metal - resourcesTotalAvailable.Metal) - possibleResources.Metal = tempPossibleOrigin.Resources.Metal; - else - possibleResources.Metal = missingResources.Metal - resourcesTotalAvailable.Metal; - if (tempPossibleOrigin.Resources.Crystal < missingResources.Crystal - resourcesTotalAvailable.Crystal) - possibleResources.Crystal = tempPossibleOrigin.Resources.Crystal; - else - possibleResources.Crystal = missingResources.Crystal - resourcesTotalAvailable.Crystal; - if (tempPossibleOrigin.Resources.Deuterium < missingResources.Deuterium - resourcesTotalAvailable.Deuterium) - possibleResources.Deuterium = tempPossibleOrigin.Resources.Deuterium; - else - possibleResources.Deuterium = missingResources.Deuterium - resourcesTotalAvailable.Deuterium; + var resultOrigins = _calculationService.CalcMultipleOrigin(celestial, allCelestials, missingResources, transportsSettings, _tbotInstance.UserData.fleets, _tbotInstance.UserData); - idealShips = _calculationService.CalcShipNumberForPayload(possibleResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (idealShips > possibleOrigin.Ships.GetAmount(preferredShip) || - possibleResources.TotalResources <= (long) _tbotInstance.InstanceSettings.Brain.Transports.MultipleOrigins.MinimumResourcesToSend || - _calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)) - continue; - - resourcesTotalAvailable = resourcesTotalAvailable.Sum(possibleResources); - resultOrigins.Add(tempPossibleOrigin, possibleResources); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{tempPossibleOrigin.ToString()} add with {possibleResources.TotalResources} - ({resultOrigins.Count}) {_calculationService.IsThereTransportTowardsCelestial(tempPossibleOrigin, _tbotInstance.UserData.fleets)}"); - if (resourcesTotalAvailable.IsEnoughFor(missingResources)) - break; - } - - if (resultOrigins.Count > MaxSlots) { - DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + if (resultOrigins.Count() == 0) { + DoLog(LogLevel.Information, $"No origin is available. This may be due to a lack of resources or cargo."); delay = true; return; } - - possibleResources = new(); - foreach (var (originMultiple, resourcesValue) in resultOrigins) { - possibleResources = possibleResources.Sum(resourcesValue); - } - if (!possibleResources.IsEnoughFor(missingResources)) { - possibleResources = possibleResources.Sum(celestial.Resources); - DoLog(LogLevel.Information, $"Not enough cargo available on all celestials to transport resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Needed: {xCostBuildable.TransportableResources} - Available: {possibleResources.TransportableResources}"); + if (resultOrigins.Count() > MaxSlots) { + DoLog(LogLevel.Information, $"Not enough slots available to send all resources to build: {buildable.ToString()} level {level.ToString()} on {celestial.ToString()}. Slots needed: {resultOrigins.Count().ToString()}/{MaxSlots}."); + delay = true; return; } Ships ships = new(); - var fleetID = 0; - foreach (var (originMultiple, resourcesValue) in resultOrigins) { + + foreach (var item in resultOrigins) { ships = new(); - ships.Add(preferredShip, _calculationService.CalcShipNumberForPayload(resourcesValue, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); - - fleetID = await _fleetScheduler.SendFleet(originMultiple, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, resourcesValue); + ships.Add((Buildables) transportsSettings.CargoType, _calculationService.CalcShipNumberForPayload(item.FirstOrDefault().Value, (Buildables) transportsSettings.CargoType, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, celestial.LFBonuses.GetShipCargoBonus(transportsSettings.CargoType), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)); + if (item.FirstOrDefault().Key.Coordinate.IsSame(destination.Coordinate) && transportsSettings.SendToTheMoonIfPossible && destination.Coordinate.Type == Celestials.Moon) + fleetId= await _fleetScheduler.SendFleet(item.FirstOrDefault().Key, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, item.FirstOrDefault().Value); + else + fleetId= await _fleetScheduler.SendFleet(item.FirstOrDefault().Key, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, item.FirstOrDefault().Value); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; @@ -419,16 +360,19 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { } } else { Celestial destination; - if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && celestial.Coordinate.Type == Celestials.Planet && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial) && (!celestial.Ships.IsEmpty() || celestial.Resources.TotalResources > 0)) { - destination = _tbotInstance.UserData.celestials + if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.SendToTheMoonIfPossible && _calculationService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { + destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) .Where(planet => planet.Coordinate.Position == celestial.Coordinate.Position) .Where(planet => planet.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; + if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) + destination = celestial; + missingResources = missingResources.Difference(destination.Resources); } else { - destination = _tbotInstance.UserData.celestials + destination = allCelestials .Unique() .Where(planet => planet.Coordinate.Galaxy == celestial.Coordinate.Galaxy) .Where(planet => planet.Coordinate.System == celestial.Coordinate.System) @@ -436,7 +380,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { .Where(planet => planet.Coordinate.Type == celestial.Coordinate.Type) .SingleOrDefault() ?? new() { ID = 0 }; } - origin = _tbotInstance.UserData.celestials + origin = allCelestials .Unique() .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Galaxy) .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.System) @@ -454,9 +398,17 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { } } else { DoLog(LogLevel.Information, $"Skipping transport: there is already a transport incoming in {celestial.ToString()}"); + fleetId = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) + .Where(f => f.Resources.TotalResources > 0) + .Where(f => f.ReturnFlight == false) + .Where(f => f.Destination.Galaxy == celestial.Coordinate.Galaxy) + .Where(f => f.Destination.System == celestial.Coordinate.System) + .Where(f => f.Destination.Position == celestial.Coordinate.Position) + .Where(f => f.Destination.Type == celestial.Coordinate.Type) + .First().ID; } } else { - if (_tbotInstance.InstanceSettings.Brain.SlotPriorityLevel > 0) { + if (_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain > 0) { if (_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots == 0) DoLog(LogLevel.Information, $"Transports.MaxSlots is set to 0, you should increase it."); else diff --git a/TBot/Workers/ColonizeWorker.cs b/TBot/Workers/ColonizeWorker.cs index 569b68df..12fe8668 100644 --- a/TBot/Workers/ColonizeWorker.cs +++ b/TBot/Workers/ColonizeWorker.cs @@ -100,80 +100,35 @@ protected override async Task Execute() { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new(); - RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, - (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && - (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && - ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); - RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); - RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); - RankSlotsPriority ColonizeRank = new(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); - RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); - RankSlotsPriority presentFeature = ColonizeRank; - rankSlotsPriority.Add(BrainRank); - rankSlotsPriority.Add(ExpeditionsRank); - rankSlotsPriority.Add(AutoFarmRank); - rankSlotsPriority.Add(ColonizeRank); - rankSlotsPriority.Add(AutoDiscoveryRank); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - string msg = ""; - int reservedSlots = 0; - int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; - int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && - fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && - fleet.Mission != Missions.Spy && - fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery) - ).Count(); - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); - foreach (RankSlotsPriority feature in rankSlotsPriority) { - if (feature == presentFeature) - continue; - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { - msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; - reservedSlots += feature.MaxSlots; - } else { - otherSlots += feature.SlotsUsed; - } - } - if (otherSlots > 0) - msg = $"{msg}, {otherSlots} are used for Other"; - int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; - tempsValue = tempsValue < 0 ? 0 : tempsValue; - DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); - if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); - MaxSlots = 0; - } else if (MaxSlots > tempsValue) { - MaxSlots = tempsValue; - DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); - } + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + new RankSlotsPriority(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal), + new RankSlotsPriority(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + new RankSlotsPriority(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1), + new RankSlotsPriority(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + new RankSlotsPriority(Feature.Harvest, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.Colonize, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); if ( (!(bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active && _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize && !f.ReturnFlight) >= maxPlanets - currentPlanets) diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index 22b2c7a9..35357aa3 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -75,80 +75,35 @@ protected override async Task Execute() { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); _tbotInstance.UserData.serverData = await _ogameService.GetServerData(); - List rankSlotsPriority = new(); - RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, - (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && - (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && - ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); - RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); - RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); - RankSlotsPriority ColonizeRank = new(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); - RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); - RankSlotsPriority presentFeature = ExpeditionsRank; - rankSlotsPriority.Add(BrainRank); - rankSlotsPriority.Add(ExpeditionsRank); - rankSlotsPriority.Add(AutoFarmRank); - rankSlotsPriority.Add(ColonizeRank); - rankSlotsPriority.Add(AutoDiscoveryRank); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - string msg = ""; - int reservedSlots = 0; - int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; - int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && - fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && - fleet.Mission != Missions.Spy && - fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery) - ).Count(); - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); - foreach (RankSlotsPriority feature in rankSlotsPriority) { - if (feature == presentFeature) - continue; - //_tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { - msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; - reservedSlots += feature.MaxSlots; - } else { - otherSlots += feature.SlotsUsed; - } - } - if (otherSlots > 0) - msg = $"{msg}, {otherSlots} are used for Other"; - int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; - tempsValue = tempsValue < 0 ? 0 : tempsValue; - DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); - if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); - MaxSlots = 0; - } else if (MaxSlots > tempsValue) { - MaxSlots = tempsValue; - DoLog(LogLevel.Information, $"Less slots available than {presentFeature.Feature.ToString()}, many slots are already used/reserved -> steping back to {MaxSlots} instead of {presentFeature.MaxSlots}"); - } + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + new RankSlotsPriority(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal), + new RankSlotsPriority(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + new RankSlotsPriority(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1), + new RankSlotsPriority(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + new RankSlotsPriority(Feature.Harvest, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.Expeditions, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); int expsToSend; if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForAllExpeditions") && (bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { diff --git a/TBot/Workers/HarvestWorker.cs b/TBot/Workers/HarvestWorker.cs index b4959336..2aa9ca69 100644 --- a/TBot/Workers/HarvestWorker.cs +++ b/TBot/Workers/HarvestWorker.cs @@ -143,79 +143,35 @@ protected override async Task Execute() { _tbotInstance.UserData.celestials = newCelestials; _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new(); - RankSlotsPriority BrainRank = new(Feature.BrainAutoMine, - (int) _tbotInstance.InstanceSettings.Brain.SlotPriorityLevel, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && - (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && - ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || - (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Transport).Count()); - RankSlotsPriority ExpeditionsRank = new(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.Expeditions.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count()); - RankSlotsPriority AutoFarmRank = new(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.AutoFarm.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Attack).Count()); - RankSlotsPriority ColonizeRank = new(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.AutoColonize.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count()); - RankSlotsPriority AutoDiscoveryRank = new(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.SlotPriorityLevel, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count()); - RankSlotsPriority presentFeature = new(Feature.Harvest); - rankSlotsPriority.Add(BrainRank); - rankSlotsPriority.Add(ExpeditionsRank); - rankSlotsPriority.Add(AutoFarmRank); - rankSlotsPriority.Add(ColonizeRank); - rankSlotsPriority.Add(AutoDiscoveryRank); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - string msg = ""; - int reservedSlots = 0; - int MaxSlots = presentFeature.MaxSlots - presentFeature.SlotsUsed; - int otherSlots = (int) _tbotInstance.UserData.fleets.Where(fleet => (fleet.Mission != Missions.Transport && - fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && - fleet.Mission != Missions.Spy && - fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery) - ).Count(); - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"Main -> {presentFeature.ToString()}"); - foreach (RankSlotsPriority feature in rankSlotsPriority) { - if (feature == presentFeature) - continue; - _tbotInstance.log(LogLevel.Warning, LogSender.Main, $"{feature.ToString()}"); - if (feature.Rank > 0 && ((feature.Active && feature.HasPriorityOn(presentFeature)) || presentFeature.Rank == 0)) { - msg = $"{msg}, {feature.MaxSlots} are reserved for {feature.Feature.ToString()}"; - reservedSlots += feature.MaxSlots; - } else { - otherSlots += feature.SlotsUsed; - } - } - if (otherSlots > 0) - msg = $"{msg}, {otherSlots} are used for Other"; - int tempsValue = _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree - reservedSlots - otherSlots - presentFeature.SlotsUsed; - tempsValue = tempsValue < 0 ? 0 : tempsValue; - DoLog(LogLevel.Information, $"{presentFeature.MaxSlots} slots are reserved for {presentFeature.Feature.ToString()}. Total slots: {_tbotInstance.UserData.slots.Total}. {_tbotInstance.InstanceSettings.General.SlotsToLeaveFree} must remain free{msg}, {tempsValue} are availables"); - if (reservedSlots + otherSlots > _tbotInstance.UserData.slots.Total - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"Unable to send fleet for {presentFeature.Feature.ToString()}, too many slots are already used/reserved"); - MaxSlots = 0; - } else { - MaxSlots = tempsValue; - } + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainAutoMine, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + new RankSlotsPriority(Feature.Expeditions, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool) _tbotInstance.InstanceSettings.Expeditions.Active, + (int) _tbotInstance.UserData.slots.ExpTotal), + new RankSlotsPriority(Feature.AutoFarm, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + new RankSlotsPriority(Feature.Colonize, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, + (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + 1), + new RankSlotsPriority(Feature.AutoDiscovery, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + new RankSlotsPriority(Feature.Harvest, + (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.Harvest, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); if (dic.Count() == 0) DoLog(LogLevel.Information, "Skipping harvest: there are no fields to harvest."); diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index e8f06863..d37a459c 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -36,7 +36,15 @@ }, "CaptchaAPIKey": "", "CustomTitle": "", - "SlotsToLeaveFree": 1 + "SlotsToLeaveFree": 1, + "SlotPriorityLevel": { + "Brain": 2, + "Expeditions": 1, + "AutoFarm": 3, + "AutoColonize": 4, + "AutoDiscovery": 10, + "AutoHarvest": 99 + } }, "SleepMode": { "Active": false, @@ -107,11 +115,10 @@ }, "Brain": { "Active": true, - "SlotPriorityLevel": 2, "Transports": { "Active": true, "CargoType": "SmallCargo", - "DeutToLeave": 1000000, + "DeutToLeaveOnMoons": 1000000, "RoundResources": true, "SendToTheMoonIfPossible": true, "Origin": { @@ -127,7 +134,7 @@ "Active": false, "OnlyFromMoons": true, "MinimumResourcesToSend": 10000000, - "PriorityToProximityOverQuantity": true, + "PriorityToProximityOverQuantity": false, "Exclude": [ { "Galaxy": 1, @@ -135,7 +142,7 @@ "Position": 1, "Type": "Planet" } - ] + ] } }, "AutoMine": { @@ -340,7 +347,6 @@ }, "Expeditions": { "Active": true, - "SlotPriorityLevel": 1, "IgnoreSleep": false, "MinWaitNextFleet": 5, "MaxWaitNextFleet": 15, @@ -387,7 +393,6 @@ }, "AutoFarm": { "Active": true, - "SlotPriorityLevel": 0, "ExcludeMoons": true, "ScanRange": [ { @@ -438,12 +443,12 @@ "HarvestDeepSpace": true, "MinimumResourcesOwnDF": 300, "MinimumResourcesDeepSpace": 50000, + "MaxSlots": 5, "CheckIntervalMin": 30, "CheckIntervalMax": 60 }, "AutoColonize": { "Active": true, - "SlotPriorityLevel": 0, "Origin": { "Galaxy": 5, "System": 64, @@ -481,13 +486,12 @@ "MaxPlanets": 2 } ], - "RandomPosition": true, - "CheckIntervalMin": 30, - "CheckIntervalMax": 60 + "RandomPosition": false, + "CheckIntervalMin": 900, + "CheckIntervalMax": 1200 }, "AutoDiscovery": { "Active": true, - "SlotPriorityLevel": 0, "Origin": { "Galaxy": 5, "System": 64, From c931f0a89072ef77bf1fc7db3200b8c8efa736eb Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 18 May 2025 19:53:07 +0200 Subject: [PATCH 042/117] * improve Defender - Colonize Mission will respect Astrophysics Level 4, 6 and 8 for Positions [3, 13], [2, 14] and [1, 15]. --- TBot/Workers/FleetScheduler.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 541bf866..8e9ec427 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -708,14 +708,23 @@ private async Task> GetFleetSaveDestination(List galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate); for (sys = origin.Coordinate.System - 5; sys <= origin.Coordinate.System + 5; sys++) { - int pos = 1; + int pos = 0; sys = GeneralHelper.ClampSystem(sys); galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); foreach (var planet in galaxyInfo.Planets) { + pos++; if (planet == null) { + if (_tbotInstance.UserData.researches.Astrophysics < 4 && (pos <= 3 || pos >= 13)){ + continue; + } + if (_tbotInstance.UserData.researches.Astrophysics < 6 && (pos <= 2 || pos >= 14)) { + continue; + } + if (_tbotInstance.UserData.researches.Astrophysics < 8 && (pos <= 1 || pos >= 15)) { + continue; + } possibleDestinations.Add(new(origin.Coordinate.Galaxy, sys, pos)); } - pos++; } } From 448ad3adaed2654e931549f0b4aafb0708d1c214 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 18 May 2025 19:53:22 +0200 Subject: [PATCH 043/117] * ITelegram Update Nuget --- TBot/Services/TelegramMessenger.cs | 15 ++++++++++----- TBot/TBot.csproj | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/TBot/Services/TelegramMessenger.cs b/TBot/Services/TelegramMessenger.cs index 05b4d8f4..05aa1e24 100644 --- a/TBot/Services/TelegramMessenger.cs +++ b/TBot/Services/TelegramMessenger.cs @@ -163,7 +163,8 @@ public async Task RemoveTBotInstance(TBotMain instance) { public async Task SendMessage(string message, ParseMode parseMode = ParseMode.Html, CancellationToken cancellationToken = default) { try { isTyping = false; - await Client.SendTextMessageAsync( + //await Client.SendTextMessageAsync( + await Client.SendMessage( chatId: Channel, text: message, parseMode: parseMode, @@ -178,7 +179,8 @@ public Task SendTyping(CancellationToken cancellationToken) { isTyping = true; Task.Run(async () => { while (isTyping) { - await Client.SendChatActionAsync( + //await Client.SendChatActionAsync( + await Client.SendChatAction( chatId: Channel, action: ChatAction.Typing,//ChatAction.Typing, cancellationToken: cancellationToken); @@ -191,7 +193,8 @@ await Client.SendChatActionAsync( public async Task SendReplyMarkup(string text, IEnumerable> buttons, CancellationToken ct) { isTyping = false; var inlineKeyboard = new InlineKeyboardMarkup(buttons); - await Client.SendTextMessageAsync( + //await Client.SendTextMessageAsync( + await Client.SendMessage( chatId: Channel, text: text, replyMarkup: inlineKeyboard, @@ -203,7 +206,8 @@ public async Task SendMessage(ITelegramBotClient client, Chat chat, string messa try { isTyping = false; //await client.SendTextMessageAsync(chat, message, parseMode); - await client.SendTextMessageAsync(chat, message, null, parseMode); + //await client.SendTextMessageAsync(chat, message, null, parseMode); + await client.SendMessage(chat, message, parseMode); } catch (Exception e) { _logger.WriteLog(LogLevel.Error, LogSender.Tbot, $"Could not send Telegram message: an exception has occurred: {e.Message}"); } @@ -1279,7 +1283,8 @@ await SendMessage(botClient, message.Chat, async Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken) { try { if (exception is ApiRequestException apiRequestException) { - await botClient.SendTextMessageAsync(Channel, apiRequestException.ToString()); + //await botClient.SendTextMessageAsync(Channel, apiRequestException.ToString()); + await botClient.SendMessage(Channel, apiRequestException.ToString()); } } catch { } } diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 8f5ddd59..7750e540 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -47,7 +47,7 @@ - + From ce7a4f2407676d617232868d514f86f461d34399 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 18 May 2025 19:56:38 +0200 Subject: [PATCH 044/117] Update nuget dependencies for security purpose. --- TBot.Common/TBot.Common.csproj | 8 ++++---- .../TBot.Ogame.Infrastructure.csproj | 2 +- TBot.WebUI/TBot.WebUI.csproj | 4 ++-- TBot/TBot.csproj | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/TBot.Common/TBot.Common.csproj b/TBot.Common/TBot.Common.csproj index 522fb7e0..8ed27095 100644 --- a/TBot.Common/TBot.Common.csproj +++ b/TBot.Common/TBot.Common.csproj @@ -7,12 +7,12 @@ - - + + - - + + diff --git a/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj b/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj index d8b49ffa..d530990e 100644 --- a/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj +++ b/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj @@ -7,7 +7,7 @@ - + diff --git a/TBot.WebUI/TBot.WebUI.csproj b/TBot.WebUI/TBot.WebUI.csproj index b7c9c3b2..efef6a73 100644 --- a/TBot.WebUI/TBot.WebUI.csproj +++ b/TBot.WebUI/TBot.WebUI.csproj @@ -36,8 +36,8 @@ - - + + diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 7750e540..c0f84e7f 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -42,11 +42,11 @@ - - + + - + From 4fcd6259b89adee34668972dac3601910306c5db Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 18 May 2025 19:58:02 +0200 Subject: [PATCH 045/117] update version 3.1.5 --- TBot/TBot.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index c0f84e7f..0d1e213f 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,14 +5,14 @@ net9.0 disable TBot - 3.1.4 + 3.1.5 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.1.4 + 3.1.5 3.1.4 OGame Bot False From 8336d7cc07e3a1daccdc77674279c4aaf6ab8c1d Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Fri, 23 May 2025 23:17:30 +0200 Subject: [PATCH 046/117] cleanup --- TBot.WebUI/Views/Shared/_Layout.cshtml | 1 - TBot/TBot.csproj | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/TBot.WebUI/Views/Shared/_Layout.cshtml b/TBot.WebUI/Views/Shared/_Layout.cshtml index c4c2a887..f12c42fd 100644 --- a/TBot.WebUI/Views/Shared/_Layout.cshtml +++ b/TBot.WebUI/Views/Shared/_Layout.cshtml @@ -20,7 +20,6 @@ T-Bot - diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 0d1e213f..b0a0ff97 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -13,7 +13,7 @@ https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot 3.1.5 - 3.1.4 + 3.1.5 OGame Bot False ELK-Lab.pfx From 8bf858f7c7095e79b5319cab745f730e6b3e95b5 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Tue, 27 May 2025 23:10:35 +0200 Subject: [PATCH 047/117] Fix some transports problems --- TBot/Includes/CalculationService.cs | 22 +++-- TBot/Includes/IFleetScheduler.cs | 4 +- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 83 ++++++++++--------- TBot/Workers/Brain/AutoResearchWorker.cs | 72 ++++++++-------- .../Brain/LifeformsAutoMineCelestialWorker.cs | 72 ++++++++-------- .../LifeformsAutoResearchCelestialWorker.cs | 72 ++++++++-------- TBot/Workers/FleetScheduler.cs | 44 ++++++---- TBot/instance_settings.json | 20 +++-- 8 files changed, 212 insertions(+), 177 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 376e1972..4b66e0b1 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4808,8 +4808,8 @@ public int CountPlanetsInRange(List planets, int galaxy, int minSyste } public bool IsThereMoonHere(List planets, Celestial celestial) { - Celestial moon = planets.Unique() - .Single(c => c.HasCoords(new( + Celestial moon = planets.SingleOrDefault( + c => c.HasCoords(new( (int) celestial.Coordinate.Galaxy, (int) celestial.Coordinate.System, (int) celestial.Coordinate.Position, @@ -4827,10 +4827,10 @@ public bool IsThereMoonHere(List planets, Celestial celestial) { public int CalcSlotsPriority(Feature feature, List rankSlotsPriority, Slots slots, List fleets, int slotsToLeaveFree = 0) { - RankSlotsPriority actualFeature = rankSlotsPriority.Where(f => (f.Feature == feature)).SingleOrDefault(); int slotsAvailable = 0; int reservedSlots = slotsToLeaveFree; int otherSlots = (int) fleets.Where(fleet => (fleet.Mission != Missions.Transport && fleet.Mission != Missions.Expedition && fleet.Mission != Missions.Attack && fleet.Mission != Missions.Spy && fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery)).Count(); + int usedSlots = 0; if (slots.Free - slotsToLeaveFree > 0) { rankSlotsPriority.Where(f => (f.Feature == Feature.BrainAutoMine || f.Feature == Feature.BrainAutoResearch || f.Feature == Feature.BrainLifeformAutoMine || f.Feature == Feature.BrainLifeformAutoResearch)).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Transport).Count(); rankSlotsPriority.Where(f => f.Feature == Feature.Expeditions).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count(); @@ -4838,19 +4838,24 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP rankSlotsPriority.Where(f => f.Feature == Feature.Colonize).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count(); rankSlotsPriority.Where(f => f.Feature == Feature.AutoDiscovery).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count(); rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); + RankSlotsPriority actualFeature = rankSlotsPriority.Where(f => (f.Feature == feature)).SingleOrDefault(); if (actualFeature.Rank > 0) { reservedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Where(f => f.Rank < actualFeature.Rank).Sum(f => f.MaxSlots); + usedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Where(f => f.Rank <= actualFeature.Rank).Sum(f => f.SlotsUsed); otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank >= actualFeature.Rank).Sum(f => f.SlotsUsed); otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed); slotsAvailable = slots.Total - reservedSlots - otherSlots; - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Total slots: {slots.Total}. {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other."); + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Total slots: {slots.Total}. {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other."); if (slotsAvailable > 0) { - if (slotsAvailable < actualFeature.MaxSlots) { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Less slots available. Steping back to {slotsAvailable} instead of {actualFeature.MaxSlots}"); + if ((actualFeature.MaxSlots - actualFeature.SlotsUsed) <= 0) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"All reserved slots for {feature.ToString()} are used ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots})."); + return 0; + } else if (slotsAvailable < (actualFeature.MaxSlots - actualFeature.SlotsUsed)) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Less slots available. Steping back to {slotsAvailable} instead of {actualFeature.MaxSlots - actualFeature.SlotsUsed} ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots} used)"); return slotsAvailable; } else { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"{slots.Free} are availables and {actualFeature.MaxSlots} can be used for {feature.ToString()}"); + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"{slots.Free} slots are Free. {slotsAvailable} are availables and {actualFeature.SlotsUsed}/{actualFeature.MaxSlots} used for {feature.ToString()}"); return actualFeature.MaxSlots; } } else { @@ -4859,11 +4864,12 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP } } else { reservedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Sum(f => f.MaxSlots); + usedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Sum(f => f.SlotsUsed); otherSlots += rankSlotsPriority.Where(f => !f.Active).Where(f => f.Rank > 0).Sum(f => f.SlotsUsed); otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed); slotsAvailable = slots.Total - reservedSlots - otherSlots; if (slotsAvailable > 0) { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Total slots: {slots.Total} and {slotsToLeaveFree} must remain free. {reservedSlots} slots are reserved and {otherSlots} are used for other. {slotsAvailable} are availables and can be used for {feature.ToString()}"); + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Total slots: {slots.Total} and {slotsToLeaveFree} must remain free. {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other. {slotsAvailable} are availables and can be used for {feature.ToString()}"); return actualFeature.MaxSlots; } else { _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"No slots available. Total slots: {slots.Total}, {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other."); diff --git a/TBot/Includes/IFleetScheduler.cs b/TBot/Includes/IFleetScheduler.cs index 1509e0a2..d4703d19 100644 --- a/TBot/Includes/IFleetScheduler.cs +++ b/TBot/Includes/IFleetScheduler.cs @@ -18,8 +18,8 @@ public interface IFleetScheduler { Task CancelFleet(Fleet fleet); Task> UpdateFleets(); void RetireFleet(object fleet); - Task HandleMinerTransport(Celestial origin, Celestial destination, Resources resources, Buildables buildable = Buildables.Null, Buildings maxBuildings = null, Facilities maxFacilities = null, Facilities maxLunarFacilities = null, AutoMinerSettings autoMinerSettings = null); - Task HandleMinerTransport(Celestial origin, Celestial destination, Resources resources, LFBuildables buildable = LFBuildables.None, LFBuildings maxLFBuildings = null, bool preventIfMoreExpensiveThanNextMine = false); + Task HandleMinerTransport(Celestial origin, Celestial destination, Celestial differentDestination, Resources resources, Buildables buildable = Buildables.Null, Buildings maxBuildings = null, Facilities maxFacilities = null, Facilities maxLunarFacilities = null, AutoMinerSettings autoMinerSettings = null); + Task HandleMinerTransport(Celestial origin, Celestial destination, Celestial differentDestination, Resources resources, LFBuildables buildable = LFBuildables.None, LFBuildings maxLFBuildings = null, bool preventIfMoreExpensiveThanNextMine = false); Task Collect(); Task CollectImpl(bool fromTelegram = false); Task CollectDeut(long minAmount = 0); diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index d666848e..c0f42c38 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -204,7 +204,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings DoLog(LogLevel.Debug, $"Days of investment return: {Math.Round(DOIR, 2).ToString()} days."); } - Resources xCostBuildable = _calculationService.CalcPrice(buildable, level); + Resources xCostBuildable = _calculationService.CalcPrice(buildable, level);//, celestial.LFBonuses); if (celestial is Moon) xCostBuildable.Deuterium += (long) autoMinerSettings.DeutToLeaveOnMoons; @@ -361,41 +361,45 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(c => c.Coordinate.Type == Celestials.Planet) .SingleOrDefault() ?? new() { ID = 0 }; } - if (origin.Resources.IsEnoughFor(missingResources) && origin.ID != 0) { - missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; - Buildables preferredShip = Buildables.SmallCargo; - if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); - preferredShip = Buildables.SmallCargo; - } - long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { - Ships ships = new(); - ships.Add((Buildables) preferredShip, shipsNeeded); - fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; - } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + if (origin.ID != 0) { + if (origin.Resources.IsEnoughFor(missingResources)) { + missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; } - } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { - DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); - Ships ships = new(); - ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); - Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); - fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; - } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { + Ships ships = new(); + ships.Add((Buildables) preferredShip, shipsNeeded); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); + Ships ships = new(); + ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); + Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); } } else { - DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); + DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); } } else { - DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); + DoLog(LogLevel.Warning, $"No Moon available on {celestial.ToString()}."); } } @@ -455,7 +459,6 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings if (resultOrigins.Count() == 0) { DoLog(LogLevel.Information, $"No origin is available. This may be due to a lack of resources or cargo."); - delay = true; return; } if (resultOrigins.Count() > MaxSlots) { @@ -479,6 +482,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings return; } if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; return; } } @@ -511,7 +515,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, missingResources, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, missingResources, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } @@ -538,7 +542,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings else DoLog(LogLevel.Information, $"0 slots available."); } - DoLog(LogLevel.Information, $"Not enough slots: Transports.MaxSlots"); + DoLog(LogLevel.Information, $"Not enough slots available for Transports.MaxSlots, delaying."); delay = true; } } @@ -585,6 +589,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings var time = await _tbotOgameBridge.GetDateTime(); string autoMineTimer = $"AutoMine-{celestial.ID.ToString()}"; DateTime newTime; + long interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMax); if (stop) { DoLog(LogLevel.Information, $"Stopping AutoMine check for {celestial.ToString()}."); await EndExecution(); @@ -593,7 +598,6 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Facilities); DoLog(LogLevel.Information, $"Delaying..."); time = await _tbotOgameBridge.GetDateTime(); - long interval; try { interval = _calculationService.CalcProductionTime((Buildables) celestial.Productions.First().ID, celestial.Productions.First().Nbr, _tbotInstance.UserData.serverData, celestial.Facilities) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds); } catch { @@ -606,9 +610,8 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings DoLog(LogLevel.Information, $"Delaying..."); time = await _tbotOgameBridge.GetDateTime(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - long interval; try { - interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + interval = (_tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport).OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } catch { interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMax); } @@ -616,7 +619,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings ChangeWorkerPeriod(interval); DoLog(LogLevel.Information, $"Next AutoMine check for {celestial.ToString()} at {newTime.ToString()}"); } else if (started) { - long interval = (long) celestial.Constructions.BuildingCountdown * (long) 1000 + (long) RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds); + interval = (long) celestial.Constructions.BuildingCountdown * (long) 1000 + (long) RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds); newTime = time.AddMilliseconds(interval); ChangeWorkerPeriod(interval); @@ -631,9 +634,9 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings DoLog(LogLevel.Information, $"Next AutoMine check for {celestial.ToString()} at {newTime.ToString()}"); } else { - long interval = await CalcAutoMineTimer(celestial, buildable, level, started, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); + interval = await CalcAutoMineTimer(celestial, buildable, level, started, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); if (fleetId > 0) { - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 660e3c7d..182bf232 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -235,41 +235,45 @@ protected override async Task Execute() { .Where(c => c.Coordinate.Type == Celestials.Planet) .SingleOrDefault() ?? new() { ID = 0 }; } - if (origin.Resources.IsEnoughFor(missingResources) && origin.ID != 0) { - missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; - Buildables preferredShip = Buildables.SmallCargo; - if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); - preferredShip = Buildables.SmallCargo; - } - long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { - Ships ships = new(); - ships.Add((Buildables) preferredShip, shipsNeeded); - fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; + if (origin.ID != 0) { + if (origin.Resources.IsEnoughFor(missingResources)) { + missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; - } - } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { - DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); - Ships ships = new(); - ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); - Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); - fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; - } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { + Ships ships = new(); + ships.Add((Buildables) preferredShip, shipsNeeded); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); + Ships ships = new(); + ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); + Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); } } else { - DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); + DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); } } else { - DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); + DoLog(LogLevel.Warning, $"No Moon available on {celestial.ToString()}."); } } @@ -323,7 +327,6 @@ protected override async Task Execute() { if (resultOrigins.Count() == 0) { DoLog(LogLevel.Information, $"No origin is available. This may be due to a lack of resources or cargo."); - delay = true; return; } if (resultOrigins.Count() > MaxSlots) { @@ -347,6 +350,7 @@ protected override async Task Execute() { return; } if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; return; } } @@ -379,7 +383,7 @@ protected override async Task Execute() { .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, missingResources, Buildables.Null); + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, missingResources, Buildables.Null); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } @@ -406,7 +410,7 @@ protected override async Task Execute() { else DoLog(LogLevel.Information, $"0 slots available."); } - DoLog(LogLevel.Information, $"Not enough slots: Transports.MaxSlots"); + DoLog(LogLevel.Information, $"Not enough slots available for Transports.MaxSlots, delaying."); delay = true; } } @@ -426,7 +430,7 @@ protected override async Task Execute() { _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); long interval; try { - interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + interval = (_tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport).OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } catch { interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoResearch.CheckIntervalMax); } diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 24a0e98c..773e329a 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -233,41 +233,45 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .Where(c => c.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; } - if (origin.Resources.IsEnoughFor(missingResources) && origin.ID != 0) { - missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; - Buildables preferredShip = Buildables.SmallCargo; - if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); - preferredShip = Buildables.SmallCargo; - } - long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { - Ships ships = new(); - ships.Add((Buildables) preferredShip, shipsNeeded); - fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; + if (origin.ID != 0) { + if (origin.Resources.IsEnoughFor(missingResources)) { + missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; - } - } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { - DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); - Ships ships = new(); - ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); - Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); - fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; - } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { + Ships ships = new(); + ships.Add((Buildables) preferredShip, shipsNeeded); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); + Ships ships = new(); + ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); + Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); } } else { - DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); + DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); } } else { - DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); + DoLog(LogLevel.Warning, $"No Moon available on {celestial.ToString()}."); } } @@ -321,7 +325,6 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { if (resultOrigins.Count() == 0) { DoLog(LogLevel.Information, $"No origin is available. This may be due to a lack of resources or cargo."); - delay = true; return; } if (resultOrigins.Count() > MaxSlots) { @@ -345,6 +348,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { return; } if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; return; } } @@ -377,7 +381,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, missingResources, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, missingResources, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } @@ -404,7 +408,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { else DoLog(LogLevel.Information, $"0 slots available."); } - DoLog(LogLevel.Information, $"Not enough slots: Transports.MaxSlots"); + DoLog(LogLevel.Information, $"Not enough slots available for Transports.MaxSlots, delaying."); delay = true; } } @@ -439,7 +443,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { DoLog(LogLevel.Information, $"Delaying..."); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); try { - interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + interval = (_tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport).OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } catch { interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMax); } diff --git a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs index 648ff526..78de9c11 100644 --- a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs @@ -243,41 +243,45 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { .Where(c => c.Coordinate.Type == Celestials.Moon) .SingleOrDefault() ?? new() { ID = 0 }; } - if (origin.Resources.IsEnoughFor(missingResources) && origin.ID != 0) { - missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; - Buildables preferredShip = Buildables.SmallCargo; - if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); - preferredShip = Buildables.SmallCargo; - } - long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { - Ships ships = new(); - ships.Add((Buildables) preferredShip, shipsNeeded); - fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; + if (origin.ID != 0) { + if (origin.Resources.IsEnoughFor(missingResources)) { + missingResources = _tbotInstance.InstanceSettings.Brain.Transports.RoundResources ? missingResources.Round() : missingResources; + Buildables preferredShip = Buildables.SmallCargo; + if (!Enum.TryParse((string) _tbotInstance.InstanceSettings.Brain.Transports.CargoType, true, out preferredShip)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to parse CargoType. Falling back to default SmallCargo"); + preferredShip = Buildables.SmallCargo; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; - } - } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { - DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); - Ships ships = new(); - ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); - Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); - fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { - stop = true; - } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + long shipsNeeded = _calculationService.CalcShipNumberForPayload(missingResources, preferredShip, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses.GetShipCargoBonus(preferredShip), _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (origin.Ships.GetAmount(preferredShip) >= shipsNeeded) { + Ships ships = new(); + ships.Add((Buildables) preferredShip, shipsNeeded); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else if (_tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Multiple transports will take place."); + Ships ships = new(); + ships.Add((Buildables) preferredShip, origin.Ships.GetAmount(preferredShip)); + Resources transportableResources = _calculationService.CalcMaxTransportableResources(ships, missingResources, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, 0, _tbotInstance.UserData.serverData.ProbeCargo); + fleetId = await _fleetScheduler.SendFleet(origin, ships, celestial.Coordinate, Missions.Transport, Speeds.HundredPercent, transportableResources); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { + stop = true; + } + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; + } + } else { + DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); } } else { - DoLog(LogLevel.Warning, $"Not enough Cargo available. Skipping CheckMoonOrPlanetFirst."); + DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); } } else { - DoLog(LogLevel.Warning, $"Not enough resources available on {origin.ToString()} only to send resources to {celestial.ToString()}."); + DoLog(LogLevel.Warning, $"No Moon available on {celestial.ToString()}."); } } @@ -331,7 +335,6 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { if (resultOrigins.Count() == 0) { DoLog(LogLevel.Information, $"No origin is available. This may be due to a lack of resources or cargo."); - delay = true; return; } if (resultOrigins.Count() > MaxSlots) { @@ -355,6 +358,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { return; } if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + delay = true; return; } } @@ -387,7 +391,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, destination, xCostBuildable, LFBuildables.None); + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, xCostBuildable, LFBuildables.None); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } @@ -414,7 +418,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { else DoLog(LogLevel.Information, $"0 slots available."); } - DoLog(LogLevel.Information, $"Not enough slots: Transports.MaxSlots"); + DoLog(LogLevel.Information, $"Not enough slots available for Transports.MaxSlots, delaying."); delay = true; } } @@ -441,7 +445,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { DoLog(LogLevel.Information, $"Delaying..."); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); try { - interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + interval = (_tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport).OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } catch { interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); } diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 8e9ec427..b4b1c00b 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -838,7 +838,7 @@ private async Task> GetFleetSaveDestination(List } } - public async Task HandleMinerTransport(Celestial origin, Celestial destination, Resources resources, Buildables buildable = Buildables.Null, Buildings maxBuildings = null, Facilities maxFacilities = null, Facilities maxLunarFacilities = null, AutoMinerSettings autoMinerSettings = null) { + public async Task HandleMinerTransport(Celestial origin, Celestial destination, Celestial differentDestination, Resources resources, Buildables buildable = Buildables.Null, Buildings maxBuildings = null, Facilities maxFacilities = null, Facilities maxLunarFacilities = null, AutoMinerSettings autoMinerSettings = null) { try { if (origin.ID == destination.ID) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Skipping transport: origin and destination are the same."); @@ -959,6 +959,8 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat resources.Crystal > destination.ResourcesProduction.Crystal.StorageCapacity || resources.Deuterium > destination.ResourcesProduction.Deuterium.StorageCapacity ) { + if (differentDestination != null && differentDestination.ID != 0) + destination = differentDestination; _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Sending {ships.ToString()} with {missingResources.TransportableResources} from {origin.ToString()} to {destination.ToString()}"); return await SendFleet(origin, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources, _tbotInstance.UserData.userInfo.Class); } else { @@ -966,6 +968,8 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat return 0; } } else { + if (differentDestination != null && differentDestination.ID != 0) + destination = differentDestination; _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Sending {ships.ToString()} with {missingResources.TransportableResources} from {origin.ToString()} to {destination.ToString()}"); return await SendFleet(origin, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources, _tbotInstance.UserData.userInfo.Class); } @@ -985,7 +989,7 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat } } - public async Task HandleMinerTransport(Celestial origin, Celestial destination, Resources resources, LFBuildables buildable = LFBuildables.None, LFBuildings maxLFBuildings = null, bool preventIfMoreExpensiveThanNextMine = false) { + public async Task HandleMinerTransport(Celestial origin, Celestial destination, Celestial differentDestination, Resources resources, LFBuildables buildable = LFBuildables.None, LFBuildings maxLFBuildings = null, bool preventIfMoreExpensiveThanNextMine = false) { try { if (origin.ID == destination.ID) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Skipping transport: origin and destination are the same."); @@ -1112,6 +1116,8 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat resources.Crystal > destination.ResourcesProduction.Crystal.StorageCapacity || resources.Deuterium > destination.ResourcesProduction.Deuterium.StorageCapacity ) { + if (differentDestination != null && differentDestination.ID != 0) + destination = differentDestination; _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Sending {ships.ToString()} with {missingResources.TransportableResources} from {origin.ToString()} to {destination.ToString()}"); return await SendFleet(origin, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources, _tbotInstance.UserData.userInfo.Class); } else { @@ -1119,6 +1125,8 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat return (int) SendFleetCode.QuickerToWaitForProduction; } } else { + if (differentDestination != null && differentDestination.ID != 0) + destination = differentDestination; _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Sending {ships.ToString()} with {missingResources.TransportableResources} from {origin.ToString()} to {destination.ToString()}"); return await SendFleet(origin, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources, _tbotInstance.UserData.userInfo.Class); } @@ -1232,28 +1240,30 @@ public async Task CollectImpl(bool fromTelegram) { if (fromTelegram) { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Telegram collect initated.."); } - if (_tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target) { + + List tempCelestials = new(); + if (_tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Length > 0) { + tempCelestials = _calcService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target, _tbotInstance.UserData.celestials); + } else { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Skipping autorepatriate: no custom destination"); + return RepatriateCode.Failure; + } + if (tempCelestials.Count() > 0) { _tbotInstance.UserData.fleets = await UpdateFleets(); long TotalMet = 0; long TotalCri = 0; long TotalDeut = 0; bool samePosition = (bool) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.TargetAssociateMoon; - Coordinate destinationCoordinate = new(); - if (!samePosition) { - destinationCoordinate = new( - (int) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Galaxy, - (int) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.System, - (int) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Position, - Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.Target.Type) - ); - } List newCelestials = _tbotInstance.UserData.celestials.ToList(); List celestialsToExclude = _calcService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.AutoRepatriate.Exclude, _tbotInstance.UserData.celestials); List celestialList = _tbotInstance.UserData.celestials.ToList(); - if (!samePosition) - celestialList = (bool) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.RandomOrder ? celestialList.Shuffle().ToList() : celestialList.OrderBy(c => _calcService.CalcDistance(c.Coordinate, destinationCoordinate, _tbotInstance.UserData.serverData)).ToList(); - + + celestialList = (bool) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.RandomOrder ? celestialList.Shuffle().ToList() : celestialList.ToList(); + foreach (Celestial celestial in celestialList) { + List closestCelestials = tempCelestials + .OrderBy(c => _calcService.CalcDistance(c.Coordinate, celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList(); + Coordinate destinationCoordinate = new(); if (samePosition) { if (celestial.Coordinate.Type == Celestials.Planet && !_calcService.IsThereMoonHere(_tbotInstance.UserData.celestials, celestial)) { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping {celestial.ToString()}: There is no moon."); @@ -1265,6 +1275,8 @@ public async Task CollectImpl(bool fromTelegram) { (int) celestial.Coordinate.Position, celestial.Coordinate.Type == Celestials.Planet ? Celestials.Moon : Celestials.Planet ); + } else { + destinationCoordinate = closestCelestials.First().Coordinate; } if (celestialsToExclude.Has(celestial)) { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping {celestial.ToString()}: celestial in exclude list."); @@ -1324,7 +1336,7 @@ public async Task CollectImpl(bool fromTelegram) { ships.Add(preferredShip, tempCelestial.Ships.GetAmount(preferredShip)); } payload = _calcService.CalcMaxTransportableResources(ships, payload, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.serverData, tempCelestial.LFBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - + if (payload.TotalResources > 0) { var fleetId = await SendFleet(tempCelestial, ships, destinationCoordinate, Missions.Transport, Speeds.HundredPercent, payload); if (fleetId == (int) SendFleetCode.AfterSleepTime) { diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index d37a459c..785c16cb 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -120,7 +120,7 @@ "CargoType": "SmallCargo", "DeutToLeaveOnMoons": 1000000, "RoundResources": true, - "SendToTheMoonIfPossible": true, + "SendToTheMoonIfPossible": false, "Origin": { "Galaxy": 3, "System": 333, @@ -128,8 +128,8 @@ "Type": "Moon" }, "MaxSlots": 10, - "CheckMoonOrPlanetFirst": true, - "DoMultipleTransportIsNotEnoughShipButSamePosition": true, + "CheckMoonOrPlanetFirst": false, + "DoMultipleTransportIsNotEnoughShipButSamePosition": false, "MultipleOrigins": { "Active": false, "OnlyFromMoons": true, @@ -318,12 +318,14 @@ "OnlyOnMoons": true, "DeutToLeave": 1000000 }, - "Target": { - "Galaxy": 5, - "System": 63, - "Position": 8, - "Type": "Moon" - }, + "Target": [ + { + "Galaxy": 5, + "System": 63, + "Position": 8, + "Type": "Moon" + } + ], "TargetAssociateMoon": false, "CargoType": "LargeCargo", "RandomOrder": true, From 44d9df79eaf4a799f737ae18f0b28d34f2b1b241 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 28 May 2025 10:41:17 +0200 Subject: [PATCH 048/117] Update Release 3.1.6 * Fix some transports problems * Fix a crash that can occur when a moon is missing using some settings * Fix a crash when using the default origin and some settings * Update the AutoMine Timer interval to avoid spamming * Add multiple Targets for AutoRepatriate --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index b0a0ff97..54725b6c 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.1.5 + 3.1.6 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.1.5 - 3.1.5 + 3.1.6 + 3.1.6 OGame Bot False ELK-Lab.pfx From 5349e1ba481903b49d683684532f390d7d8e7e9a Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 31 May 2025 13:39:16 +0200 Subject: [PATCH 049/117] * Logic error on Colonizer and FleetScheduler using Calculaction Service function CalcLimitAstro() --- TBot/Workers/ColonizeWorker.cs | 2 +- TBot/Workers/FleetScheduler.cs | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/TBot/Workers/ColonizeWorker.cs b/TBot/Workers/ColonizeWorker.cs index 12fe8668..294e44a5 100644 --- a/TBot/Workers/ColonizeWorker.cs +++ b/TBot/Workers/ColonizeWorker.cs @@ -172,7 +172,7 @@ protected override async Task Execute() { (int) ii, Celestials.Planet ); - if (_calculationService.CalcLimitAstro((int) targetCoords.Position, _tbotInstance.UserData.researches)) { + if (!_calculationService.CalcLimitAstro((int) targetCoords.Position, _tbotInstance.UserData.researches)) { targets.Add(targetCoords); } } diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index b4b1c00b..a526e08d 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -713,16 +713,7 @@ private async Task> GetFleetSaveDestination(List galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); foreach (var planet in galaxyInfo.Planets) { pos++; - if (planet == null) { - if (_tbotInstance.UserData.researches.Astrophysics < 4 && (pos <= 3 || pos >= 13)){ - continue; - } - if (_tbotInstance.UserData.researches.Astrophysics < 6 && (pos <= 2 || pos >= 14)) { - continue; - } - if (_tbotInstance.UserData.researches.Astrophysics < 8 && (pos <= 1 || pos >= 15)) { - continue; - } + if (!_calcService.CalcLimitAstro((int) pos, _tbotInstance.UserData.researches)) { possibleDestinations.Add(new(origin.Coordinate.Galaxy, sys, pos)); } } From f55367f7708872d9c964cd8ee3809565ed27b839 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 31 May 2025 13:40:52 +0200 Subject: [PATCH 050/117] v3.1.7 --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 54725b6c..fa4f1d93 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.1.6 + 3.1.7 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.1.6 - 3.1.6 + 3.1.7 + 3.1.7 OGame Bot False ELK-Lab.pfx From 03598fc9eeae6852e2dd83a34d9eea4a73ddbb2c Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 31 May 2025 15:34:42 +0200 Subject: [PATCH 051/117] * Function Naming from CalcLimitAstro to IsAstrophysicsPositionValid and refactoring --- TBot/Includes/CalculationService.cs | 14 ++++++++------ TBot/Includes/ICalculationService.cs | 2 +- TBot/Workers/ColonizeWorker.cs | 2 +- TBot/Workers/FleetScheduler.cs | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 4b66e0b1..b52602f5 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4740,11 +4740,13 @@ public int CalcMaxPlanets(Researches researches) { return researches == null ? 1 : CalcMaxPlanets(researches.Astrophysics); } - public bool CalcLimitAstro(int pos, Researches researches) { - return ((pos >= 4 && pos <= 13 && (int)researches.Astrophysics >= 4) || - (pos >= 2 && pos <= 14 && (int)researches.Astrophysics >= 6) || - (pos >= 1 && pos <= 15 && (int)researches.Astrophysics >= 8)); - } + public bool IsAstrophysicsPositionValid(int pos, int astrophysics) => astrophysics switch { + 8 => pos >= 1 && pos <= 15, + 7 or 6 => pos >= 2 && pos <= 14, + 5 or 4 => pos >= 3 && pos <= 13, + 3 or 2 or 1 => pos >= 4 && pos <= 14, + _ => true + }; public int CalcMaxCrawlers(Planet planet, CharacterClass userClass, bool hasGeologist) { if (userClass == CharacterClass.Collector && hasGeologist) { @@ -5013,4 +5015,4 @@ public List> CalcMultipleOrigin(Celestial celes } } } -} \ No newline at end of file +} diff --git a/TBot/Includes/ICalculationService.cs b/TBot/Includes/ICalculationService.cs index c0bc89ef..9457d78f 100644 --- a/TBot/Includes/ICalculationService.cs +++ b/TBot/Includes/ICalculationService.cs @@ -43,7 +43,7 @@ public interface ICalculationService { int CalcMaxExpeditions(Researches researches, CharacterClass playerClass, Staff staff); int CalcMaxPlanets(int astrophysics); int CalcMaxPlanets(Researches researches); - bool CalcLimitAstro(int pos, Researches researches); + bool IsAstrophysicsPositionValid(int pos, int astrophysics); Resources CalcMaxTransportableResources(Ships ships, Resources resources, int hyperspaceTech, ServerData serverData, LFBonuses lfBonuses = null, CharacterClass playerClass = CharacterClass.NoClass, long deutToLeave = 0, int probeCargo = 0); long CalcMetalProduction(Buildings buildings, int position, int speedFactor, float ratio = 1, Researches researches = null, LFBonuses lfBonuses = null, CharacterClass playerClass = CharacterClass.NoClass, bool hasGeologist = false, bool hasStaff = false, int crawlers = 0, float crawlerRatio = 1); long CalcMetalProduction(int level, int position, int speedFactor, float ratio = 1, int plasma = 0, float metalLFBonus = 0, CharacterClass playerClass = CharacterClass.NoClass, bool hasGeologist = false, bool hasStaff = false, int crawlers = 0, float crawlerRatio = 1); diff --git a/TBot/Workers/ColonizeWorker.cs b/TBot/Workers/ColonizeWorker.cs index 294e44a5..cc2d9514 100644 --- a/TBot/Workers/ColonizeWorker.cs +++ b/TBot/Workers/ColonizeWorker.cs @@ -172,7 +172,7 @@ protected override async Task Execute() { (int) ii, Celestials.Planet ); - if (!_calculationService.CalcLimitAstro((int) targetCoords.Position, _tbotInstance.UserData.researches)) { + if (_calculationService.IsAstrophysicsPositionValid((int) targetCoords.Position, (int) _tbotInstance.UserData.researches.Astrophysics)) { targets.Add(targetCoords); } } diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index a526e08d..381c1ebb 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -713,7 +713,7 @@ private async Task> GetFleetSaveDestination(List galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); foreach (var planet in galaxyInfo.Planets) { pos++; - if (!_calcService.CalcLimitAstro((int) pos, _tbotInstance.UserData.researches)) { + if (_calcService.IsAstrophysicsPositionValid((int) pos, (int)_tbotInstance.UserData.researches.Astrophysics)) { possibleDestinations.Add(new(origin.Coordinate.Galaxy, sys, pos)); } } From b9af7ed8ba135e9bba712779027e57613808ed04 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 31 May 2025 15:35:24 +0200 Subject: [PATCH 052/117] v3.1.8 --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index fa4f1d93..69a95e4d 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.1.7 + 3.1.8 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.1.7 - 3.1.7 + 3.1.8 + 3.1.8 OGame Bot False ELK-Lab.pfx From 495056043c0a2b4c812ad8b025fd787b9eb40c01 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 31 May 2025 16:24:40 +0200 Subject: [PATCH 053/117] * fix crash on jsonObj parsing EditSettings --- TBot/Services/TBotMain.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TBot/Services/TBotMain.cs b/TBot/Services/TBotMain.cs index 16ea5148..dcabd723 100644 --- a/TBot/Services/TBotMain.cs +++ b/TBot/Services/TBotMain.cs @@ -460,10 +460,10 @@ public async Task EditSettings(Celestial celestial = null, Feature feature } if (feature == Feature.BrainAutoRepatriate || feature == Feature.Null) { - jsonObj["Brain"]["AutoRepatriate"]["Target"]["Galaxy"] = (int) celestial.Coordinate.Galaxy; - jsonObj["Brain"]["AutoRepatriate"]["Target"]["System"] = (int) celestial.Coordinate.System; - jsonObj["Brain"]["AutoRepatriate"]["Target"]["Position"] = (int) celestial.Coordinate.Position; - jsonObj["Brain"]["AutoRepatriate"]["Target"]["Type"] = type; + jsonObj["Brain"]["AutoRepatriate"]["Target"][0]["Galaxy"] = (int) celestial.Coordinate.Galaxy; + jsonObj["Brain"]["AutoRepatriate"]["Target"][0]["System"] = (int) celestial.Coordinate.System; + jsonObj["Brain"]["AutoRepatriate"]["Target"][0]["Position"] = (int) celestial.Coordinate.Position; + jsonObj["Brain"]["AutoRepatriate"]["Target"][0]["Type"] = type; } if (feature == Feature.Expeditions || feature == Feature.Null) { From 7f2b6e4ffee0061ee841741b4d5f345819abad8f Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 31 May 2025 16:25:20 +0200 Subject: [PATCH 054/117] v3.1.9 --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 69a95e4d..2c9cd983 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.1.8 + 3.1.9 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.1.8 - 3.1.8 + 3.1.9 + 3.1.9 OGame Bot False ELK-Lab.pfx From fa47b595037cf842f0ba55a054eb91594d09ada6 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 31 May 2025 16:50:17 +0200 Subject: [PATCH 055/117] * cleanup --- TBot/Includes/CalculationService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index b52602f5..139951b2 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4744,7 +4744,7 @@ public int CalcMaxPlanets(Researches researches) { 8 => pos >= 1 && pos <= 15, 7 or 6 => pos >= 2 && pos <= 14, 5 or 4 => pos >= 3 && pos <= 13, - 3 or 2 or 1 => pos >= 4 && pos <= 14, + 3 or 2 or 1 => pos >= 4 && pos <= 12, _ => true }; From 15f67ee494e0c32cb69b44e4049d98b631c20e78 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Sat, 31 May 2025 18:59:32 +0200 Subject: [PATCH 056/117] Fix interval value --- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 2 +- TBot/Workers/Brain/AutoResearchWorker.cs | 2 +- TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index c0f42c38..82627db3 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -640,7 +640,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMax); } if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { if (_tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport).Count() > 0) { diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 182bf232..04e76052 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -478,7 +478,7 @@ protected override async Task Execute() { var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.AutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.CheckIntervalMax); } if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 773e329a..9c93f2e4 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -488,7 +488,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMax); } if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) From d10a3f08974f1351b87343716a64eb179c56e738 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 31 May 2025 20:04:33 +0200 Subject: [PATCH 057/117] * fix AutoMine Timers wrong variable. --- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 2 +- TBot/Workers/Brain/AutoResearchWorker.cs | 2 +- TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index c0f42c38..82627db3 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -640,7 +640,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.AutoMine.CheckIntervalMax); } if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { if (_tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport).Count() > 0) { diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 182bf232..04e76052 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -478,7 +478,7 @@ protected override async Task Execute() { var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.AutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.CheckIntervalMax); } if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 773e329a..9c93f2e4 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -488,7 +488,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.CheckIntervalMax); + interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMax); } if ((bool) _tbotInstance.InstanceSettings.Brain.Transports.DoMultipleTransportIsNotEnoughShipButSamePosition) { var transportfleet2 = _tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Transport) From 77851d32ed437cb8cf93502ff96474d1896a29fd Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 31 May 2025 20:05:25 +0200 Subject: [PATCH 058/117] v3.2.0 --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 2c9cd983..2846edd1 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.1.9 + 3.2.0 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.1.9 - 3.1.9 + 3.2.0 + 3.2.0 OGame Bot False ELK-Lab.pfx From fc8345321b0c5c5b208e4161c99efc2115bcd5ad Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 1 Jun 2025 16:04:07 +0200 Subject: [PATCH 059/117] v3.2.1 * fix Defender crash on nil pointer reference. --- TBot/TBot.csproj | 6 +++--- TBot/Workers/DefenderWorker.cs | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 2846edd1..5b9ba751 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.0 + 3.2.1 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.0 - 3.2.0 + 3.2.1 + 3.2.1 OGame Bot False ELK-Lab.pfx diff --git a/TBot/Workers/DefenderWorker.cs b/TBot/Workers/DefenderWorker.cs index eaca570c..2e167bff 100644 --- a/TBot/Workers/DefenderWorker.cs +++ b/TBot/Workers/DefenderWorker.cs @@ -228,14 +228,16 @@ private async void HandleAttack(AttackerFleet attack) { if ((bool) _tbotInstance.InstanceSettings.Defender.TelegramMessenger.Active) { await _tbotInstance.SendTelegramMessage($"Player {attack.AttackerName} ({attack.AttackerID}) is attacking your planet {attack.Destination.ToString()} arriving at {attack.ArrivalTime.ToString()}"); - if (attack.Ships != null) + if (attack.Ships != null) { await Task.Delay(1000, _ct); - await _tbotInstance.SendTelegramMessage($"The attack is composed by: {attack.Ships.ToString()}"); + await _tbotInstance.SendTelegramMessage($"The attack is composed by: {attack.Ships.ToString()}"); + } } DoLog(LogLevel.Warning, $"Player {attack.AttackerName} ({attack.AttackerID}) is attacking your planet {attackedCelestial.ToString()} arriving at {attack.ArrivalTime.ToString()}"); - if (attack.Ships != null) + if (attack.Ships != null) { await Task.Delay(1000, _ct); - DoLog(LogLevel.Warning, $"The attack is composed by: {attack.Ships.ToString()}"); + DoLog(LogLevel.Warning, $"The attack is composed by: {attack.Ships.ToString()}"); + } if ((bool) _tbotInstance.InstanceSettings.Defender.SpyAttacker.Active) { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); From 1aacd07677cdd174319e090cebce39a8f508d62c Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 4 Jun 2025 08:58:30 +0200 Subject: [PATCH 060/117] * fix AutoTransport --- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index 82627db3..4cd5bef8 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -515,6 +515,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; + missingResources = xCostBuildable; fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, missingResources, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; From f1690238929409178f8222a0bfae43732f2a0b19 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 4 Jun 2025 08:59:56 +0200 Subject: [PATCH 061/117] v3.2.2 --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 5b9ba751..d1990691 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.1 + 3.2.2 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.1 - 3.2.1 + 3.2.2 + 3.2.2 OGame Bot False ELK-Lab.pfx From 683ea161d937b7e131353422014c34acea704924 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Wed, 4 Jun 2025 18:04:38 +0200 Subject: [PATCH 062/117] fix Autotransport on non Multi-Origin for all brain feature --- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 5 ++--- TBot/Workers/Brain/AutoResearchWorker.cs | 4 ++-- TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs | 4 ++-- TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs | 2 +- TBot/Workers/FleetScheduler.cs | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index 4cd5bef8..e7e15184 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -498,7 +498,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .SingleOrDefault() ?? new() { ID = 0 }; if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) destination = celestial; - missingResources = missingResources.Difference(destination.Resources); + xCostBuildable = xCostBuildable.Difference(destination.Resources); } else { destination = allCelestials .Unique() @@ -515,8 +515,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - missingResources = xCostBuildable; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, missingResources, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, xCostBuildable, buildable, maxBuildings, maxFacilities, maxLunarFacilities, autoMinerSettings); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 04e76052..8a5f1e74 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -366,7 +366,7 @@ protected override async Task Execute() { .SingleOrDefault() ?? new() { ID = 0 }; if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) destination = celestial; - missingResources = missingResources.Difference(destination.Resources); + cost = cost.Difference(destination.Resources); } else { destination = allCelestials .Unique() @@ -383,7 +383,7 @@ protected override async Task Execute() { .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, missingResources, Buildables.Null); + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, cost, Buildables.Null); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 9c93f2e4..678cece4 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -364,7 +364,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .SingleOrDefault() ?? new() { ID = 0 }; if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) destination = celestial; - missingResources = missingResources.Difference(destination.Resources); + xCostBuildable = xCostBuildable.Difference(destination.Resources); } else { destination = allCelestials .Unique() @@ -381,7 +381,7 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Position) .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.Brain.Transports.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, missingResources, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); + fleetId = await _fleetScheduler.HandleMinerTransport(origin, celestial, destination, xCostBuildable, buildable, maxLFBuildings, preventIfMoreExpensiveThanNextMine); if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; } diff --git a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs index 78de9c11..8a7ac865 100644 --- a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs @@ -374,7 +374,7 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { .SingleOrDefault() ?? new() { ID = 0 }; if (destination.Ships.IsEmpty() || celestial.Resources.TotalResources == 0) destination = celestial; - missingResources = missingResources.Difference(destination.Resources); + xCostBuildable = xCostBuildable.Difference(destination.Resources); } else { destination = allCelestials .Unique() diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 381c1ebb..f4ea29d1 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -956,7 +956,7 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat return await SendFleet(origin, ships, destination.Coordinate, Missions.Transport, Speeds.HundredPercent, missingResources, _tbotInstance.UserData.userInfo.Class); } else { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, "Skipping transport: it is quicker to wait for production."); - return 0; + return (int) SendFleetCode.QuickerToWaitForProduction; } } else { if (differentDestination != null && differentDestination.ID != 0) From 34f773a295d54bcb3253dcff8385fb7d3166706d Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 4 Jun 2025 19:44:32 +0200 Subject: [PATCH 063/117] v3.2.3 * extended AutoTransport fix --- TBot.Ogame.Infrastructure/Models/GalaxyInfo.cs | 2 ++ TBot/TBot.csproj | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/TBot.Ogame.Infrastructure/Models/GalaxyInfo.cs b/TBot.Ogame.Infrastructure/Models/GalaxyInfo.cs index 148062cc..f55ac372 100644 --- a/TBot.Ogame.Infrastructure/Models/GalaxyInfo.cs +++ b/TBot.Ogame.Infrastructure/Models/GalaxyInfo.cs @@ -3,12 +3,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using TBot.Ogame.Infrastructure.Enums; namespace TBot.Ogame.Infrastructure.Models { public class GalaxyInfo { public int Galaxy { get; set; } public int System { get; set; } public List Planets { get; set; } + public List AvailableMissions { get; set; } public ExpeditionDebris ExpeditionDebris { get; set; } } } diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index d1990691..453345cf 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.2 + 3.2.3 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.2 - 3.2.2 + 3.2.3 + 3.2.3 OGame Bot False ELK-Lab.pfx From 9a2a5a01c2f6689a6471e6fb385b21c703ca55db Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Wed, 4 Jun 2025 22:30:16 +0200 Subject: [PATCH 064/117] Few fixes for the bot --- TBot/Includes/CalculationService.cs | 6 ++++-- TBot/Includes/ICalculationService.cs | 2 +- TBot/Workers/Brain/AutoResearchWorker.cs | 6 +++--- TBot/Workers/FleetScheduler.cs | 2 +- TBot/instance_settings.json | 1 + 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 139951b2..251c6ed0 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4408,9 +4408,11 @@ public bool ShouldResearchEnergyTech(List planets, Researches researches return ShouldResearchEnergyTech(planets, researches.EnergyTechnology, maxEnergyTech, playerClass, hasEngineer, hasStaff); } - public Buildables GetNextResearchToBuild(Planet celestial, Researches researches, bool prioritizeRobotsAndNanitesOnNewPlanets = false, Slots slots = null, int maxEnergyTechnology = 20, int maxLaserTechnology = 12, int maxIonTechnology = 5, int maxHyperspaceTechnology = 20, int maxPlasmaTechnology = 20, int maxCombustionDrive = 19, int maxImpulseDrive = 17, int maxHyperspaceDrive = 15, int maxEspionageTechnology = 8, int maxComputerTechnology = 20, int maxAstrophysics = 23, int maxIntergalacticResearchNetwork = 12, int maxWeaponsTechnology = 25, int maxShieldingTechnology = 25, int maxArmourTechnology = 25, bool optimizeForStart = true, bool ensureExpoSlots = true, CharacterClass playerClass = CharacterClass.NoClass, bool hasGeologist = false, bool hasAdmiral = false) { - if (ShouldBuildResearchLab(celestial, 12, researches)) + public Buildables GetNextResearchToBuild(Planet celestial, Researches researches, bool prioritizeRobotsAndNanitesOnNewPlanets = false, Slots slots = null, int maxEnergyTechnology = 20, int maxLaserTechnology = 12, int maxIonTechnology = 5, int maxHyperspaceTechnology = 20, int maxPlasmaTechnology = 20, int maxCombustionDrive = 19, int maxImpulseDrive = 17, int maxHyperspaceDrive = 15, int maxEspionageTechnology = 8, int maxComputerTechnology = 20, int maxAstrophysics = 23, int maxIntergalacticResearchNetwork = 12, int maxWeaponsTechnology = 25, int maxShieldingTechnology = 25, int maxArmourTechnology = 25, bool optimizeForStart = true, bool ensureExpoSlots = true, bool ForceResearchWhateverTheLabLevel = false, CharacterClass playerClass = CharacterClass.NoClass, bool hasGeologist = false, bool hasAdmiral = false) { + if (ShouldBuildResearchLab(celestial, 12, researches) && !ForceResearchWhateverTheLabLevel) { + _logger.WriteLog(LogLevel.Information, LogSender.Tbot, $"Skipping AutoResearch: Can't build any research, Research Lab need to be upgraded first (actually cheaper than the next mine)."); return Buildables.Null; + } if (optimizeForStart) { if (researches.EnergyTechnology == 0 && celestial.Facilities.ResearchLab > 0 && researches.EnergyTechnology < maxEnergyTechnology) diff --git a/TBot/Includes/ICalculationService.cs b/TBot/Includes/ICalculationService.cs index 9457d78f..070294e8 100644 --- a/TBot/Includes/ICalculationService.cs +++ b/TBot/Includes/ICalculationService.cs @@ -125,7 +125,7 @@ public interface ICalculationService { Buildables GetNextMineToBuild(Planet planet, int maxMetalMine = 100, int maxCrystalMine = 100, int maxDeuteriumSynthetizer = 100, bool optimizeForStart = true); Buildables GetNextMineToBuild(Planet planet, Researches researches = null, int speedFactor = 1, int maxMetalMine = 100, int maxCrystalMine = 100, int maxDeuteriumSynthetizer = 100, float ratio = 1, CharacterClass playerClass = CharacterClass.NoClass, bool hasGeologist = false, bool hasStaff = false, bool optimizeForStart = true, float maxDaysOfInvestmentReturn = 36500); Buildables GetNextMineToBuild(Planet planet, Researches researches, Buildings maxBuildings, Facilities maxFacilities, CharacterClass playerClass, Staff staff, ServerData serverData, AutoMinerSettings settings, float ratio = 1); - Buildables GetNextResearchToBuild(Planet celestial, Researches researches, bool prioritizeRobotsAndNanitesOnNewPlanets = false, Slots slots = null, int maxEnergyTechnology = 20, int maxLaserTechnology = 12, int maxIonTechnology = 5, int maxHyperspaceTechnology = 20, int maxPlasmaTechnology = 20, int maxCombustionDrive = 19, int maxImpulseDrive = 17, int maxHyperspaceDrive = 15, int maxEspionageTechnology = 8, int maxComputerTechnology = 20, int maxAstrophysics = 23, int maxIntergalacticResearchNetwork = 12, int maxWeaponsTechnology = 25, int maxShieldingTechnology = 25, int maxArmourTechnology = 25, bool optimizeForStart = true, bool ensureExpoSlots = true, CharacterClass playerClass = CharacterClass.NoClass, bool hasGeologist = false, bool hasAdmiral = false); + Buildables GetNextResearchToBuild(Planet celestial, Researches researches, bool prioritizeRobotsAndNanitesOnNewPlanets = false, Slots slots = null, int maxEnergyTechnology = 20, int maxLaserTechnology = 12, int maxIonTechnology = 5, int maxHyperspaceTechnology = 20, int maxPlasmaTechnology = 20, int maxCombustionDrive = 19, int maxImpulseDrive = 17, int maxHyperspaceDrive = 15, int maxEspionageTechnology = 8, int maxComputerTechnology = 20, int maxAstrophysics = 23, int maxIntergalacticResearchNetwork = 12, int maxWeaponsTechnology = 25, int maxShieldingTechnology = 25, int maxArmourTechnology = 25, bool optimizeForStart = true, bool ensureExpoSlots = true, bool ForceResearchWhateverTheLabLevel = false, CharacterClass playerClass = CharacterClass.NoClass, bool hasGeologist = false, bool hasAdmiral = false); long GetProductionEnergyDelta(Buildables buildable, int level, int energyTechnology = 0, float ratio = 1, CharacterClass userClass = CharacterClass.NoClass, bool hasEngineer = false, bool hasStaff = false); long GetRequiredEnergyDelta(Buildables buildable, int level); int GetSolarSatelliteOutput(Planet planet, bool isCollector = false, bool hasEngineer = false, bool hasFullStaff = false); diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 8a5f1e74..3e1129d4 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -137,10 +137,10 @@ protected override async Task Execute() { ) { research = Buildables.Astrophysics; } else { - research = _calculationService.GetNextResearchToBuild(celestial as Planet, _tbotInstance.UserData.researches, (bool) _tbotInstance.InstanceSettings.Brain.AutoMine.PrioritizeRobotsAndNanites, _tbotInstance.UserData.slots, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxEnergyTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxLaserTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxIonTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxHyperspaceTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxPlasmaTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxCombustionDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxImpulseDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxHyperspaceDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxEspionageTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxComputerTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxAstrophysics, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxIntergalacticResearchNetwork, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxWeaponsTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxShieldingTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxArmourTechnology, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.OptimizeForStart, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.EnsureExpoSlots, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.Admiral); + research = _calculationService.GetNextResearchToBuild(celestial as Planet, _tbotInstance.UserData.researches, (bool) _tbotInstance.InstanceSettings.Brain.AutoMine.PrioritizeRobotsAndNanites, _tbotInstance.UserData.slots, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxEnergyTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxLaserTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxIonTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxHyperspaceTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxPlasmaTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxCombustionDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxImpulseDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxHyperspaceDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxEspionageTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxComputerTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxAstrophysics, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxIntergalacticResearchNetwork, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxWeaponsTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxShieldingTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxArmourTechnology, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.OptimizeForStart, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.EnsureExpoSlots, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.ForceResearchWhateverTheLabLevel, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.Admiral); } } else { - research = _calculationService.GetNextResearchToBuild(celestial as Planet, _tbotInstance.UserData.researches, (bool) _tbotInstance.InstanceSettings.Brain.AutoMine.PrioritizeRobotsAndNanites, _tbotInstance.UserData.slots, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxEnergyTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxLaserTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxIonTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxHyperspaceTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxPlasmaTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxCombustionDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxImpulseDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxHyperspaceDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxEspionageTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxComputerTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxAstrophysics, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxIntergalacticResearchNetwork, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxWeaponsTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxShieldingTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxArmourTechnology, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.OptimizeForStart, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.EnsureExpoSlots, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.Admiral); + research = _calculationService.GetNextResearchToBuild(celestial as Planet, _tbotInstance.UserData.researches, (bool) _tbotInstance.InstanceSettings.Brain.AutoMine.PrioritizeRobotsAndNanites, _tbotInstance.UserData.slots, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxEnergyTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxLaserTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxIonTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxHyperspaceTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxPlasmaTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxCombustionDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxImpulseDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxHyperspaceDrive, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxEspionageTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxComputerTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxAstrophysics, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxIntergalacticResearchNetwork, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxWeaponsTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxShieldingTechnology, (int) _tbotInstance.InstanceSettings.Brain.AutoResearch.MaxArmourTechnology, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.OptimizeForStart, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.EnsureExpoSlots, (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.ForceResearchWhateverTheLabLevel, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.staff.Geologist, _tbotInstance.UserData.staff.Admiral); } if ( @@ -474,7 +474,7 @@ protected override async Task Execute() { interval = (((fleet.Mission == Missions.Transport || fleet.Mission == Missions.Deploy) ? (long) fleet.ArriveIn : (long) fleet.BackIn) * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { if (fleetId > 0) { - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); var transportfleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId && f.Mission == Missions.Transport); interval = (transportfleet.ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } else { diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index f4ea29d1..a0759210 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -713,7 +713,7 @@ private async Task> GetFleetSaveDestination(List galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); foreach (var planet in galaxyInfo.Planets) { pos++; - if (_calcService.IsAstrophysicsPositionValid((int) pos, (int)_tbotInstance.UserData.researches.Astrophysics)) { + if (_calcService.IsAstrophysicsPositionValid((int) pos, (int)_tbotInstance.UserData.researches.Astrophysics) && planet != null) { possibleDestinations.Add(new(origin.Coordinate.Galaxy, sys, pos)); } } diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index 785c16cb..9b3beec4 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -287,6 +287,7 @@ "PrioritizePlasmaTechnology": true, "PrioritizeEnergyTechnology": true, "PrioritizeIntergalacticResearchNetwork": true, + "ForceResearchWhateverTheLabLevel": false, "CheckIntervalMin": 10, "CheckIntervalMax": 20 }, From e50e51f04402862d2c8fcd5fa146e828c7cfe84f Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Thu, 12 Jun 2025 18:46:31 +0200 Subject: [PATCH 065/117] Fix slots distribution & better CalcMultipleOrigin --- TBot/Includes/CalculationService.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 251c6ed0..702830b8 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4860,7 +4860,7 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP return slotsAvailable; } else { _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"{slots.Free} slots are Free. {slotsAvailable} are availables and {actualFeature.SlotsUsed}/{actualFeature.MaxSlots} used for {feature.ToString()}"); - return actualFeature.MaxSlots; + return actualFeature.MaxSlots - actualFeature.SlotsUsed; } } else { _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"No slots available."); @@ -4874,7 +4874,7 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP slotsAvailable = slots.Total - reservedSlots - otherSlots; if (slotsAvailable > 0) { _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Total slots: {slots.Total} and {slotsToLeaveFree} must remain free. {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other. {slotsAvailable} are availables and can be used for {feature.ToString()}"); - return actualFeature.MaxSlots; + return slotsAvailable; } else { _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"No slots available. Total slots: {slots.Total}, {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other."); return 0; @@ -4887,6 +4887,10 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP } public List> CalcMultipleOrigin(Celestial celestialToBuild, List allCelestials, Resources missingResources, TransportSettings transportSettings, List fleets, UserData userData) { + if (missingResources.TotalResources < transportSettings.MultipleOrigin.MinimumResourcesToSend) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Skipping transport: missing resources {missingResources.TransportableResources} is less than minimum {transportSettings.MultipleOrigin.MinimumResourcesToSend}"); + return new(); + } List> result = new(); bool roundRes = transportSettings.RoundResources; Resources resources = new(); @@ -4978,8 +4982,10 @@ public List> CalcMultipleOrigin(Celestial celes celResources.Difference(celResources.Difference(missingResources.Difference(resources))).Round(): celResources.Difference(celResources.Difference(missingResources.Difference(resources))); } - if (celResources.TotalResources < transportSettings.MultipleOrigin.MinimumResourcesToSend || celResources.TotalResources == 0) + if (celResources.TotalResources < transportSettings.MultipleOrigin.MinimumResourcesToSend || celResources.TotalResources == 0) { + _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Skipping transport from {cel.ToString()}: resources under minimum threshold ({celResources.TotalResources} < {transportSettings.MultipleOrigin.MinimumResourcesToSend})"); continue; + } if (cel.Ships.GetAmount(transportSettings.CargoType) >= CalcShipNumberForPayload(celResources, transportSettings.CargoType, userData.researches.HyperspaceTechnology, userData.serverData, cel.LFBonuses.GetShipCargoBonus(transportSettings.CargoType), userData.userInfo.Class, userData.serverData.ProbeCargo)) { resources = resources.Sum(celResources); result.Add(new Dictionary { { cel, celResources } } ); From 0b9947b73b23761fa80f5ec5e411445cc60e9f4f Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Thu, 12 Jun 2025 19:25:36 +0200 Subject: [PATCH 066/117] Improve CalcMultipleOrigin's resources calculation --- TBot/Includes/CalculationService.cs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 702830b8..b7044cad 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4906,7 +4906,7 @@ public List> CalcMultipleOrigin(Celestial celes .Where(c => c.Resources.TotalResources > 0) .ToList(); - Resources TotalResources = allCelestials.Aggregate(new Resources(), (total, celestial) => total.Sum(celestial.Resources)); + Resources TotalResources = closestCelestials.Aggregate(new Resources(), (total, celestial) => total.Sum(celestial.Resources.Difference(new Resources(0, 0, transportSettings.DeutToLeave))) ); if (!TotalResources.IsEnoughFor(missingResources)) { _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Not enough resources available on all celestials: Needed: {missingResources.TransportableResources} - Available: {TotalResources.TransportableResources}"); return new(); @@ -4958,8 +4958,10 @@ public List> CalcMultipleOrigin(Celestial celes return new(); } TotalResources = closestCelestials.Aggregate(new Resources(), (total, celestial) => { - if (celestial.Ships.GetAmount(transportSettings.CargoType) >= CalcShipNumberForPayload(celestial.Resources, transportSettings.CargoType, userData.researches.HyperspaceTechnology, userData.serverData, celestial.LFBonuses.GetShipCargoBonus(transportSettings.CargoType), userData.userInfo.Class, userData.serverData.ProbeCargo)) { - return total.Sum(celestial.Resources); + if (celestial.Resources.TotalResources < transportSettings.MultipleOrigin.MinimumResourcesToSend || celestial.Resources.TotalResources == 0) + return total; + if (celestial.Ships.GetAmount(transportSettings.CargoType) >= CalcShipNumberForPayload(celestial.Resources.Difference(new Resources(0, 0, transportSettings.DeutToLeave)), transportSettings.CargoType, userData.researches.HyperspaceTechnology, userData.serverData, celestial.LFBonuses.GetShipCargoBonus(transportSettings.CargoType), userData.userInfo.Class, userData.serverData.ProbeCargo)) { + return total.Sum(celestial.Resources.Difference(new Resources(0, 0, transportSettings.DeutToLeave))); } else { Ships ships = new(); ships.Add(transportSettings.CargoType, celestial.Ships.GetAmount(transportSettings.CargoType)); @@ -4994,16 +4996,11 @@ public List> CalcMultipleOrigin(Celestial celes Ships ships = new(); ships.Add(transportSettings.CargoType, cel.Ships.GetAmount(transportSettings.CargoType)); Resources res = CalcMaxTransportableResources(ships, celResources, userData.researches.HyperspaceTechnology, userData.serverData, cel.LFBonuses, userData.userInfo.Class, 0, userData.serverData.ProbeCargo); - if (resources.Sum(res).IsEnoughFor(missingResources)) { - resources = resources.Sum(res); - celResources = res; - if (celResources.TotalResources == 0) - continue; - result.Add(new Dictionary { { cel, celResources } } ); - } else { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Not enough resources transportable"); - return new(); - } + resources = resources.Sum(res); + celResources = res; + if (celResources.TotalResources == 0) + continue; + result.Add(new Dictionary { { cel, celResources } } ); } else { _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Not enough resources transportable"); return new(); @@ -5011,6 +5008,7 @@ public List> CalcMultipleOrigin(Celestial celes } _logger.WriteLog(LogLevel.Information, LogSender.Tbot, $"Sending resources from: {cel.Coordinate.ToString()} to {destination.Coordinate.ToString()} - Resources: {celResources.TransportableResources}"); if (resources.IsEnoughFor(missingResources)) { + _logger.WriteLog(LogLevel.Information, LogSender.Tbot, $"{result.Count()} transports will be send to {destination.ToString()}"); return result; } } From a150276e402122d2899da461c1432ba377f452bf Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Tue, 17 Jun 2025 21:06:54 +0200 Subject: [PATCH 067/117] add new telegram command --- TBot/Services/TBotMain.cs | 11 +++++++++++ TBot/Services/TelegramMessenger.cs | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/TBot/Services/TBotMain.cs b/TBot/Services/TBotMain.cs index dcabd723..2abb6ec7 100644 --- a/TBot/Services/TBotMain.cs +++ b/TBot/Services/TBotMain.cs @@ -1444,6 +1444,17 @@ public async Task TelegramRetireFleet(int fleetId) { } _fleetScheduler.RetireFleet(ToRecallFleet); } + public async Task TelegramRetireFleetM(Missions mission) { + userData.fleets = await _fleetScheduler.UpdateFleets(); + List ToRecallFleet = userData.fleets.Where(f => f.Mission == mission).ToList(); + if (ToRecallFleet.Count == 0) { + await SendTelegramMessage($"Unable to recall fleet ! No mission ?"); + return; + } + foreach (var fleet in ToRecallFleet) { + _fleetScheduler.RetireFleet(fleet); + } + } public async Task TelegramMesgAttacker(string message) { userData.attacks = await _ogameService.GetAttacks(); diff --git a/TBot/Services/TelegramMessenger.cs b/TBot/Services/TelegramMessenger.cs index 05aa1e24..de9330dc 100644 --- a/TBot/Services/TelegramMessenger.cs +++ b/TBot/Services/TelegramMessenger.cs @@ -258,6 +258,7 @@ public async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, "/getinfo", "/celestial", "/cancel", + "/cancelmission", "/cancelghostsleep", "/editsettings", "/spycrash", @@ -430,6 +431,7 @@ await SendMessage(botClient, message.Chat, "/sleep - Stop bot for the specified amount of hours. Format: /sleep 4h3m or 3m50s\n" + "/wakeup - Wakeup bot\n" + "/cancel - Cancel fleet with specified ID. Format: /cancel 65656\n" + + "/cancelmission - Cancel all fleets with specified mission. Format: /cancel Deploy or other mission\n" + "/getcelestials - Return the list of your celestials\n" + "/attacked - check if you're (still) under attack\n" + "/celestial - Update program current celestial target. Format: /celestial 2:45:8 Moon/Planet\n" + @@ -794,6 +796,18 @@ await SendMessage(botClient, message.Chat, return; + case "/cancelmission": + if (message.Text.Split(' ').Length != 2) { + await SendMessage(botClient, message.Chat, "Mission argument required!"); + return; + } + arg = message.Text.Split(' ')[1]; + Missions.TryParse(arg, out mission); + + await currInstance.TelegramRetireFleetM(mission); + return; + + case "/cancelghostsleep": if (message.Text.Split(' ').Length != 1) { await SendMessage(botClient, message.Chat, "No argument accepted with this command!"); From efe48b279bfb466060053b9d6c63468deae59170 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Wed, 18 Jun 2025 19:29:16 +0200 Subject: [PATCH 068/117] improve optimizeForStart --- TBot/Includes/CalculationService.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index b7044cad..16b177cc 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4415,6 +4415,8 @@ public Buildables GetNextResearchToBuild(Planet celestial, Researches researches } if (optimizeForStart) { + if (researches.ComputerTechnology < 6 && celestial.Facilities.ResearchLab >= 1 && researches.Astrophysics > 1 && researches.ComputerTechnology < maxComputerTechnology) + return Buildables.ComputerTechnology; if (researches.EnergyTechnology == 0 && celestial.Facilities.ResearchLab > 0 && researches.EnergyTechnology < maxEnergyTechnology) return Buildables.EnergyTechnology; if (researches.CombustionDrive < 2 && celestial.Facilities.ResearchLab > 0 && researches.EnergyTechnology >= 1 && researches.CombustionDrive < maxCombustionDrive) From 179eb335a65ea5996ff322929041a8887ce0d226 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Sun, 22 Jun 2025 18:54:42 +0200 Subject: [PATCH 069/117] update RankSlotsPriority builder --- TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs b/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs index 1be10a91..abc9ce97 100644 --- a/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs +++ b/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs @@ -9,7 +9,7 @@ namespace TBot.Ogame.Infrastructure.Models { public class RankSlotsPriority { public RankSlotsPriority(Feature feature = Feature.Null, int rank = int.MaxValue, bool active = false, int maxSlots = 0, int slotsUsed = 0) { - Rank = rank < 1 ? int.MaxValue : rank; + Rank = rank; Active = active; MaxSlots = maxSlots; SlotsUsed = slotsUsed; From 559a571bd3b7e1de430c2dea13e421824f77e908 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Mon, 23 Jun 2025 12:12:45 +0200 Subject: [PATCH 070/117] reduce autoColonize IntensiveReasearch check interval --- TBot/Workers/ColonizeWorker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TBot/Workers/ColonizeWorker.cs b/TBot/Workers/ColonizeWorker.cs index cc2d9514..65cceab5 100644 --- a/TBot/Workers/ColonizeWorker.cs +++ b/TBot/Workers/ColonizeWorker.cs @@ -138,7 +138,7 @@ protected override async Task Execute() { interval = (_tbotInstance.UserData.fleets .OrderBy(f => f.ArriveIn) .First(f => !f.ReturnFlight) - .ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds); + .ArriveIn * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.LessThanFiveSeconds); } else { Coordinate originCoords = new( (int) _tbotInstance.InstanceSettings.AutoColonize.Origin.Galaxy, From c31eb7676b9ab884988266c3f387ef535088b482 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Mon, 23 Jun 2025 12:27:52 +0200 Subject: [PATCH 071/117] fix visual feature match in log --- TBot/Includes/CalculationService.cs | 49 ++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 16b177cc..1fab3001 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4837,6 +4837,39 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP int reservedSlots = slotsToLeaveFree; int otherSlots = (int) fleets.Where(fleet => (fleet.Mission != Missions.Transport && fleet.Mission != Missions.Expedition && fleet.Mission != Missions.Attack && fleet.Mission != Missions.Spy && fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery)).Count(); int usedSlots = 0; + LogSender logsender; + switch (feature) { + case Feature.BrainAutoMine: + logsender = LogSender.AutoMine; + break; + case Feature.BrainAutoResearch: + logsender = LogSender.AutoResearch; + break; + case Feature.BrainLifeformAutoMine: + logsender = LogSender.LifeformsAutoMine; + break; + case Feature.BrainLifeformAutoResearch: + logsender = LogSender.LifeformsAutoResearch; + break; + case Feature.Expeditions: + logsender = LogSender.Expeditions; + break; + case Feature.AutoFarm: + logsender = LogSender.AutoFarm; + break; + case Feature.Colonize: + logsender = LogSender.Colonize; + break; + case Feature.AutoDiscovery: + logsender = LogSender.AutoDiscovery; + break; + case Feature.Harvest: + logsender = LogSender.Harvest; + break; + default: + logsender = LogSender.FleetScheduler; + break; + } if (slots.Free - slotsToLeaveFree > 0) { rankSlotsPriority.Where(f => (f.Feature == Feature.BrainAutoMine || f.Feature == Feature.BrainAutoResearch || f.Feature == Feature.BrainLifeformAutoMine || f.Feature == Feature.BrainLifeformAutoResearch)).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Transport).Count(); rankSlotsPriority.Where(f => f.Feature == Feature.Expeditions).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count(); @@ -4852,20 +4885,20 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank >= actualFeature.Rank).Sum(f => f.SlotsUsed); otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed); slotsAvailable = slots.Total - reservedSlots - otherSlots; - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Total slots: {slots.Total}. {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other."); + _logger.WriteLog(LogLevel.Information, logsender, $"Total slots: {slots.Total}. {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other."); if (slotsAvailable > 0) { if ((actualFeature.MaxSlots - actualFeature.SlotsUsed) <= 0) { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"All reserved slots for {feature.ToString()} are used ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots})."); + _logger.WriteLog(LogLevel.Information, logsender, $"All reserved slots for {feature.ToString()} are used ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots})."); return 0; } else if (slotsAvailable < (actualFeature.MaxSlots - actualFeature.SlotsUsed)) { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Less slots available. Steping back to {slotsAvailable} instead of {actualFeature.MaxSlots - actualFeature.SlotsUsed} ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots} used)"); + _logger.WriteLog(LogLevel.Information, logsender, $"Less slots available. Steping back to {slotsAvailable} instead of {actualFeature.MaxSlots - actualFeature.SlotsUsed} ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots} used)"); return slotsAvailable; } else { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"{slots.Free} slots are Free. {slotsAvailable} are availables and {actualFeature.SlotsUsed}/{actualFeature.MaxSlots} used for {feature.ToString()}"); + _logger.WriteLog(LogLevel.Information, logsender, $"{slots.Free} slots are Free. {slotsAvailable} are availables and {actualFeature.SlotsUsed}/{actualFeature.MaxSlots} used for {feature.ToString()}"); return actualFeature.MaxSlots - actualFeature.SlotsUsed; } } else { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"No slots available."); + _logger.WriteLog(LogLevel.Information, logsender, $"No slots available."); return 0; } } else { @@ -4875,15 +4908,15 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed); slotsAvailable = slots.Total - reservedSlots - otherSlots; if (slotsAvailable > 0) { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"Total slots: {slots.Total} and {slotsToLeaveFree} must remain free. {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other. {slotsAvailable} are availables and can be used for {feature.ToString()}"); + _logger.WriteLog(LogLevel.Information, logsender, $"Total slots: {slots.Total} and {slotsToLeaveFree} must remain free. {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other. {slotsAvailable} are availables and can be used for {feature.ToString()}"); return slotsAvailable; } else { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, $"No slots available. Total slots: {slots.Total}, {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other."); + _logger.WriteLog(LogLevel.Information, logsender, $"No slots available. Total slots: {slots.Total}, {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other."); return 0; } } } else { - _logger.WriteLog(LogLevel.Information, LogSender.Brain, "No slots left, delaying"); + _logger.WriteLog(LogLevel.Information, logsender, "No slots left, delaying"); return 0; } } From cbe6946e8f1926ad25f1eacfde248254a4bebae7 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 26 Jun 2025 07:07:40 +0200 Subject: [PATCH 072/117] updade ogame module --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index c3e8ddcc..58de3448 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "ogame"] path = ogame url = https://github.com/0xE232FE/ogame.mod.git - branch = develop_v11.15.5-tbot + branch = develop-ogamed-tbot From f950c68e241c2f613c225c6f71efbe8cd4cda98a Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 26 Jun 2025 07:09:09 +0200 Subject: [PATCH 073/117] update ogame module --- ogame | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ogame b/ogame index 3f648fad..32a8ab7b 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit 3f648fad63acfc703b48c225e1a58fc70ccdf411 +Subproject commit 32a8ab7bec123b30b5f89ff83a4d4b1200b1a09d From e955ec272a3a90c20b7550cd913ce87d0596f31f Mon Sep 17 00:00:00 2001 From: 0xE232FE Date: Thu, 26 Jun 2025 07:11:09 +0200 Subject: [PATCH 074/117] Update release.yml --- .github/workflows/release.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 45b686f7..7e00c838 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,10 +33,10 @@ jobs: run: dotnet publish TBot -c Release -r win-x64 -o publish/win64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed win64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=windows GOARCH=amd64 go build -o ogamed.exe cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed.exe ${{ github.workspace }}/publish/win64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed.exe ${{ github.workspace }}/publish/win64/ cp ${{ github.workspace }}/README.md ${{ github.workspace }}/publish/win64/ - name: Package win64 uses: montudor/action-zip@v1 @@ -47,10 +47,10 @@ jobs: run: dotnet publish TBot -c Release -r win-x86 -o publish/win32/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed win32 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=windows GOARCH=386 go build -o ogamed.exe cd ${{ github.workspace }}/ - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed.exe ${{ github.workspace }}/publish/win32/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed.exe ${{ github.workspace }}/publish/win32/ cp ${{ github.workspace }}/README.md ${{ github.workspace }}/publish/win32/ - name: Package win32 uses: montudor/action-zip@v1 @@ -61,10 +61,10 @@ jobs: run: dotnet publish TBot -c Release -r linux-x64 -o publish/linux64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linux64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=linux GOARCH=amd64 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/linux64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/linux64/ chmod +x ${{ github.workspace }}/publish/linux64/TBot chmod +x ${{ github.workspace }}/publish/linux64/ogamed cp ${{ github.workspace }}/README.md ${{ github.workspace }}/publish/linux64/ @@ -77,10 +77,10 @@ jobs: run: dotnet publish TBot -c Release -r linux-arm -o publish/linuxarm/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linuxarm run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=linux GOARCH=arm GOARM=7 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/linuxarm/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/linuxarm/ chmod +x ${{ github.workspace }}/publish/linuxarm/TBot chmod +x ${{ github.workspace }}/publish/linuxarm/ogamed cp ${{ github.workspace }}/README.md ${{ github.workspace }}/publish/linuxarm/ @@ -93,10 +93,10 @@ jobs: run: dotnet publish TBot -c Release -r linux-arm64 -o publish/linuxarm64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linuxarm64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=linux GOARCH=arm64 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/linuxarm64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/linuxarm64/ chmod +x ${{ github.workspace }}/publish/linuxarm64/TBot chmod +x ${{ github.workspace }}/publish/linuxarm64/ogamed cp ${{ github.workspace }}/README.md ${{ github.workspace }}/publish/linuxarm64/ @@ -109,10 +109,10 @@ jobs: run: dotnet publish TBot -c Release -r osx-x64 -o publish/osx64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed osx64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=darwin GOARCH=amd64 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/osx64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/osx64/ chmod +x ${{ github.workspace }}/publish/osx64/TBot chmod +x ${{ github.workspace }}/publish/osx64/ogamed cp ${{ github.workspace }}/README.md ${{ github.workspace }}/publish/osx64/ @@ -125,10 +125,10 @@ jobs: run: dotnet publish TBot -c Release -r osx-arm64 -o publish/osx-arm64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed osx-arm64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=darwin GOARCH=arm64 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/osx-arm64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/osx-arm64/ chmod +x ${{ github.workspace }}/publish/osx-arm64/TBot chmod +x ${{ github.workspace }}/publish/osx-arm64/ogamed cp ${{ github.workspace }}/README.md ${{ github.workspace }}/publish/osx-arm64/ From aaa1d2623a6dd5ee26a8d508c5262325d5211975 Mon Sep 17 00:00:00 2001 From: 0xE232FE Date: Thu, 26 Jun 2025 07:11:33 +0200 Subject: [PATCH 075/117] Update snapshot.yml --- .github/workflows/snapshot.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 94c1d93d..914340f4 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -34,10 +34,10 @@ jobs: run: dotnet publish TBot -c Release -r win-x64 -o publish/win64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed win64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=windows GOARCH=amd64 go build -o ogamed.exe cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed.exe ${{ github.workspace }}/publish/win64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed.exe ${{ github.workspace }}/publish/win64/ - name: Package win64 uses: montudor/action-zip@v1 with: @@ -52,10 +52,10 @@ jobs: run: dotnet publish TBot -c Release -r win-x86 -o publish/win32/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed win32 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=windows GOARCH=386 go build -o ogamed.exe cd ${{ github.workspace }}/ - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed.exe ${{ github.workspace }}/publish/win32/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed.exe ${{ github.workspace }}/publish/win32/ - name: Package win32 uses: montudor/action-zip@v1 with: @@ -70,10 +70,10 @@ jobs: run: dotnet publish TBot -c Release -r linux-x64 -o publish/linux64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linux64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=linux GOARCH=amd64 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/linux64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/linux64/ chmod +x ${{ github.workspace }}/publish/linux64/TBot chmod +x ${{ github.workspace }}/publish/linux64/ogamed - name: Package linux64 @@ -90,10 +90,10 @@ jobs: run: dotnet publish TBot -c Release -r linux-arm -o publish/linuxarm/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linuxarm run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=linux GOARCH=arm GOARM=7 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/linuxarm/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/linuxarm/ chmod +x ${{ github.workspace }}/publish/linuxarm/TBot chmod +x ${{ github.workspace }}/publish/linuxarm/ogamed - name: Package linuxarm @@ -110,10 +110,10 @@ jobs: run: dotnet publish TBot -c Release -r linux-arm64 -o publish/linuxarm64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed linuxarm64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=linux GOARCH=arm64 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/linuxarm64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/linuxarm64/ chmod +x ${{ github.workspace }}/publish/linuxarm64/TBot chmod +x ${{ github.workspace }}/publish/linuxarm64/ogamed - name: Package linuxarm64 @@ -130,10 +130,10 @@ jobs: run: dotnet publish TBot -c Release -r osx-x64 -o publish/osx64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed osx64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=darwin GOARCH=amd64 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/osx64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/osx64/ chmod +x ${{ github.workspace }}/publish/osx64/TBot chmod +x ${{ github.workspace }}/publish/osx64/ogamed - name: Package osx64 @@ -150,10 +150,10 @@ jobs: run: dotnet publish TBot -c Release -r osx-arm64 -o publish/osx-arm64/ -p:PublishSingleFile=true --self-contained true - name: Build ogamed osx-arm64 run: | - cd ${{ github.workspace }}/ogame/cmd/ogamed + cd ${{ github.workspace }}/ogame/cmd/ogamed-tbot env GOOS=darwin GOARCH=arm64 go build -o ogamed cd ${{ github.workspace }} - mv ${{ github.workspace }}/ogame/cmd/ogamed/ogamed ${{ github.workspace }}/publish/osx-arm64/ + mv ${{ github.workspace }}/ogame/cmd/ogamed-tbot/ogamed ${{ github.workspace }}/publish/osx-arm64/ chmod +x ${{ github.workspace }}/publish/osx-arm64/TBot chmod +x ${{ github.workspace }}/publish/osx-arm64/ogamed - name: Package osx-arm64 From 6321772870caf83d782c858c53fdc79defacb74e Mon Sep 17 00:00:00 2001 From: 0xE232FE Date: Thu, 26 Jun 2025 07:15:19 +0200 Subject: [PATCH 076/117] Update snapshot.yml --- .github/workflows/snapshot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 914340f4..afc88037 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -28,7 +28,7 @@ jobs: - name: Setup GO uses: actions/setup-go@v2 with: - go-version: '~1.18.0' + go-version: '~1.23.0' - name: Build TBot win64 run: dotnet publish TBot -c Release -r win-x64 -o publish/win64/ -p:PublishSingleFile=true --self-contained true From b1d204736f9b0cb53fdadc27e82de271e4e1aeae Mon Sep 17 00:00:00 2001 From: 0xE232FE Date: Thu, 26 Jun 2025 07:15:30 +0200 Subject: [PATCH 077/117] Update release.yml --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7e00c838..e80e4875 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,7 +27,7 @@ jobs: - name: Setup GO uses: actions/setup-go@v2 with: - go-version: '~1.18.0' + go-version: '~1.23.0' - name: Build TBot win64 run: dotnet publish TBot -c Release -r win-x64 -o publish/win64/ -p:PublishSingleFile=true --self-contained true From 4a676adb27a6c436696b07a65467682de04d1281 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 26 Jun 2025 07:35:46 +0200 Subject: [PATCH 078/117] v3.2.5 * Few fixes for the bot * Fix slots distribution & better CalcMultipleOrigin * Improve CalcMultipleOrigin's resources calculation * add new telegram command * improve optimizeForStart * update RankSlotsPriority builder * reduce autoColonize IntensiveReasearch check interval * fix visual feature match in log --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 453345cf..21f74fc7 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.3 + 3.2.5 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.3 - 3.2.3 + 3.2.5 + 3.2.5 OGame Bot False ELK-Lab.pfx From 40ca005e45f43d627257b06fb3c54631947df420 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 26 Jun 2025 21:20:46 +0200 Subject: [PATCH 079/117] * fix Automine LFTechs --- TBot.Ogame.Infrastructure/Models/LFTechs.cs | 152 ++++++++++---------- TBot/Includes/CalculationService.cs | 84 +++++++---- 2 files changed, 138 insertions(+), 98 deletions(-) diff --git a/TBot.Ogame.Infrastructure/Models/LFTechs.cs b/TBot.Ogame.Infrastructure/Models/LFTechs.cs index 1adbf90e..7fa22278 100644 --- a/TBot.Ogame.Infrastructure/Models/LFTechs.cs +++ b/TBot.Ogame.Infrastructure/Models/LFTechs.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Text; @@ -9,96 +10,99 @@ namespace TBot.Ogame.Infrastructure.Models { public class LFTechs { //Humans - public int IntergalacticEnvoys { get; set; } - public int HighPerformanceExtractors { get; set; } - public int FusionDrives { get; set; } - public int StealthFieldGenerator { get; set; } - public int OrbitalDen { get; set; } - public int ResearchAI { get; set; } - public int HighPerformanceTerraformer { get; set; } - public int EnhancedProductionTechnologies { get; set; } - public int LightFighterMkII { get; set; } - public int CruiserMkII { get; set; } - public int ImprovedLabTechnology { get; set; } - public int PlasmaTerraformer { get; set; } - public int LowTemperatureDrives { get; set; } - public int BomberMkII { get; set; } - public int DestroyerMkII { get; set; } - public int BattlecruiserMkII { get; set; } - public int RobotAssistants { get; set; } - public int Supercomputer { get; set; } + public int? IntergalacticEnvoys { get; set; } + public int? HighPerformanceExtractors { get; set; } + public int? FusionDrives { get; set; } + public int? StealthFieldGenerator { get; set; } + public int? OrbitalDen { get; set; } + public int? ResearchAI { get; set; } + public int? HighPerformanceTerraformer { get; set; } + public int? EnhancedProductionTechnologies { get; set; } + public int? LightFighterMkII { get; set; } + public int? CruiserMkII { get; set; } + public int? ImprovedLabTechnology { get; set; } + public int? PlasmaTerraformer { get; set; } + public int? LowTemperatureDrives { get; set; } + public int? BomberMkII { get; set; } + public int? DestroyerMkII { get; set; } + public int? BattlecruiserMkII { get; set; } + public int? RobotAssistants { get; set; } + public int? Supercomputer { get; set; } //Rocktal - public int VolcanicBatteries { get; set; } - public int AcousticScanning { get; set; } - public int HighEnergyPumpSystems { get; set; } - public int CargoHoldExpansionCivilianShips { get; set; } - public int MagmaPoweredProduction { get; set; } - public int GeothermalPowerPlants { get; set; } - public int DepthSounding { get; set; } - public int IonCrystalEnhancementHeavyFighter { get; set; } - public int ImprovedStellarator { get; set; } - public int HardenedDiamondDrillHeads { get; set; } - public int SeismicMiningTechnology { get; set; } - public int MagmaPoweredPumpSystems { get; set; } - public int IonCrystalModules { get; set; } - public int OptimisedSiloConstructionMethod { get; set; } - public int DiamondEnergyTransmitter { get; set; } - public int ObsidianShieldReinforcement { get; set; } - public int RuneShields { get; set; } - public int RocktalCollectorEnhancement { get; set; } + public int? VolcanicBatteries { get; set; } + public int? AcousticScanning { get; set; } + public int? HighEnergyPumpSystems { get; set; } + public int? CargoHoldExpansionCivilianShips { get; set; } + public int? MagmaPoweredProduction { get; set; } + public int? GeothermalPowerPlants { get; set; } + public int? DepthSounding { get; set; } + public int? IonCrystalEnhancementHeavyFighter { get; set; } + public int? ImprovedStellarator { get; set; } + public int? HardenedDiamondDrillHeads { get; set; } + public int? SeismicMiningTechnology { get; set; } + public int? MagmaPoweredPumpSystems { get; set; } + public int? IonCrystalModules { get; set; } + public int? OptimisedSiloConstructionMethod { get; set; } + public int? DiamondEnergyTransmitter { get; set; } + public int? ObsidianShieldReinforcement { get; set; } + public int? RuneShields { get; set; } + public int? RocktalCollectorEnhancement { get; set; } //Mechas - public int CatalyserTechnology { get; set; } - public int PlasmaDrive { get; set; } - public int EfficiencyModule { get; set; } - public int DepotAI { get; set; } - public int GeneralOverhaulLightFighter { get; set; } - public int AutomatedTransportLines { get; set; } - public int ImprovedDroneAI { get; set; } - public int ExperimentalRecyclingTechnology { get; set; } - public int GeneralOverhaulCruiser { get; set; } - public int SlingshotAutopilot { get; set; } - public int HighTemperatureSuperconductors { get; set; } - public int GeneralOverhaulBattleship { get; set; } - public int ArtificialSwarmIntelligence { get; set; } - public int GeneralOverhaulBattlecruiser { get; set; } - public int GeneralOverhaulBomber { get; set; } - public int GeneralOverhaulDestroyer { get; set; } - public int ExperimentalWeaponsTechnology { get; set; } - public int MechanGeneralEnhancement { get; set; } + public int? CatalyserTechnology { get; set; } + public int? PlasmaDrive { get; set; } + public int? EfficiencyModule { get; set; } + public int? DepotAI { get; set; } + public int? GeneralOverhaulLightFighter { get; set; } + public int? AutomatedTransportLines { get; set; } + public int? ImprovedDroneAI { get; set; } + public int? ExperimentalRecyclingTechnology { get; set; } + public int? GeneralOverhaulCruiser { get; set; } + public int? SlingshotAutopilot { get; set; } + public int? HighTemperatureSuperconductors { get; set; } + public int? GeneralOverhaulBattleship { get; set; } + public int? ArtificialSwarmIntelligence { get; set; } + public int? GeneralOverhaulBattlecruiser { get; set; } + public int? GeneralOverhaulBomber { get; set; } + public int? GeneralOverhaulDestroyer { get; set; } + public int? ExperimentalWeaponsTechnology { get; set; } + public int? MechanGeneralEnhancement { get; set; } //Kaelesh - public int HeatRecovery { get; set; } - public int SulphideProcess { get; set; } - public int PsionicNetwork { get; set; } - public int TelekineticTractorBeam { get; set; } - public int EnhancedSensorTechnology { get; set; } - public int NeuromodalCompressor { get; set; } - public int NeuroInterface { get; set; } - public int InterplanetaryAnalysisNetwork { get; set; } - public int OverclockingHeavyFighter { get; set; } - public int TelekineticDrive { get; set; } - public int SixthSense { get; set; } - public int Psychoharmoniser { get; set; } - public int EfficientSwarmIntelligence { get; set; } - public int OverclockingLargeCargo { get; set; } - public int GravitationSensors { get; set; } - public int OverclockingBattleship { get; set; } - public int PsionicShieldMatrix { get; set; } - public int KaeleshDiscovererEnhancement { get; set; } + public int? HeatRecovery { get; set; } + public int? SulphideProcess { get; set; } + public int? PsionicNetwork { get; set; } + public int? TelekineticTractorBeam { get; set; } + public int? EnhancedSensorTechnology { get; set; } + public int? NeuromodalCompressor { get; set; } + public int? NeuroInterface { get; set; } + public int? InterplanetaryAnalysisNetwork { get; set; } + public int? OverclockingHeavyFighter { get; set; } + public int? TelekineticDrive { get; set; } + public int? SixthSense { get; set; } + public int? Psychoharmoniser { get; set; } + public int? EfficientSwarmIntelligence { get; set; } + public int? OverclockingLargeCargo { get; set; } + public int? GravitationSensors { get; set; } + public int? OverclockingBattleship { get; set; } + public int? PsionicShieldMatrix { get; set; } + public int? KaeleshDiscovererEnhancement { get; set; } public int GetLevel(LFTechno building) { int output = 0; foreach (PropertyInfo prop in GetType().GetProperties()) { if (prop.Name == building.ToString()) { - output = (int) prop.GetValue(this); + object value = prop.GetValue(this, null); + if (value is not null) { + output = (int) prop.GetValue(this, null); + } } } return output; } - public LFTechs SetLevel(LFTechno buildable, int level) { + public LFTechs SetLevel(LFTechno buildable, int? level) { foreach (PropertyInfo prop in this.GetType().GetProperties()) { if (prop.Name == buildable.ToString()) { prop.SetValue(this, level); diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 1fab3001..43dd09dc 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis.Operations; using System.Reflection.Emit; using System.Data; +using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Tbot.Includes { @@ -3100,12 +3101,19 @@ public int GetNextLevel(Celestial planet, LFBuildables buildable) { public int GetNextLevel(Celestial planet, LFTechno buildable) { int output = 0; - if (planet is Planet) { - foreach (PropertyInfo prop in planet.LFTechs.GetType().GetProperties()) { - if (prop.Name == buildable.ToString()) { - output = (int) prop.GetValue(planet.LFTechs) + 1; - } + //if (planet is Planet) { + // foreach (PropertyInfo prop in planet.LFTechs.GetType().GetProperties()) { + // if (prop.Name == buildable.ToString()) { + // output = (int) prop.GetValue(planet.LFTechs) + 1; + // } + // } + //} + if (planet is Celestial) { + int? level = planet.LFTechs.GetLevel(buildable); + if (level is null) { + return output; } + output = planet.LFTechs.GetLevel(buildable) + 1; } return output; } @@ -4041,36 +4049,64 @@ public LFTechno GetNextLFTechToBuild(Celestial celestial, LFTechs MaxReasearchLe //TODO //As planets can have any lifeform techs, its complicated to find which techs are existing on a planet if the techs are not at least level 1 //Therefore, for the moment, up only techs that are minimum level 1, its a way to also allows player to chose which research to up - foreach (PropertyInfo prop in celestial.LFTechs.GetType().GetProperties()) { - foreach (LFTechno nextLFTech in Enum.GetValues()) { - if ((int) prop.GetValue(celestial.LFTechs) > 0 && GetNextLevel(celestial, nextLFTech) <= MaxReasearchLevel.GetLevel(nextLFTech) && prop.Name == nextLFTech.ToString()) { - //Console.WriteLine($"-----------------------------> {nextLFTech}: {GetNextLevel(celestial, nextLFTech)} / {MaxReasearchLevel.GetLevel(nextLFTech)}"); - return nextLFTech; - } + //foreach (PropertyInfo prop in celestial.LFTechs.GetType().GetProperties()) { + // foreach (LFTechno nextLFTech in Enum.GetValues()) { + // if ((int) prop.GetValue(celestial.LFTechs) > 0 && GetNextLevel(celestial, nextLFTech) <= MaxReasearchLevel.GetLevel(nextLFTech) && prop.Name == nextLFTech.ToString()) { + // //Console.WriteLine($"-----------------------------> {nextLFTech}: {GetNextLevel(celestial, nextLFTech)} / {MaxReasearchLevel.GetLevel(nextLFTech)}"); + // return nextLFTech; + // } + // } + //} + + + foreach (LFTechno nextLFTech in Enum.GetValues()) { + int? level = celestial.LFTechs.GetLevel(nextLFTech); + if (level is null) { + continue; } + if (level > 0 && GetNextLevel(celestial, nextLFTech) <= MaxReasearchLevel.GetLevel(nextLFTech)) { + //Console.WriteLine($"-----------------------------> {nextLFTech}: {GetNextLevel(celestial, nextLFTech)} / {MaxReasearchLevel.GetLevel(nextLFTech)}"); + return nextLFTech; + } } - return LFTechno.None; + + return LFTechno.None; } public LFTechno GetLessExpensiveLFTechToBuild(Celestial celestial, Resources currentcost, LFTechs MaxReasearchLevel, double costReduction = 0) { LFTechno nextLFtech = LFTechno.None; Resource nextLFtechcost = new(); - foreach (PropertyInfo prop in celestial.LFTechs.GetType().GetProperties()) { - foreach (LFTechno next in Enum.GetValues()) { - if ((int) prop.GetValue(celestial.LFTechs) > 0 && GetNextLevel(celestial, next) <= MaxReasearchLevel.GetLevel(next) && prop.Name == next.ToString()) { - //Console.WriteLine($"-----------------------------> {next}: {GetNextLevel(celestial, next)} / {MaxReasearchLevel.GetLevel(next)}"); - var nextLFtechlvl = GetNextLevel(celestial, next); - Resources newcost = CalcPrice(next, nextLFtechlvl, costReduction); - if (newcost.ConvertedDeuterium < currentcost.ConvertedDeuterium) { - currentcost = newcost; - nextLFtech = next; - } - } - + //foreach (PropertyInfo prop in celestial.LFTechs.GetType().GetProperties()) { + // foreach (LFTechno next in Enum.GetValues()) { + // if ((int) prop.GetValue(celestial.LFTechs) > 0 && GetNextLevel(celestial, next) <= MaxReasearchLevel.GetLevel(next) && prop.Name == next.ToString()) { + // //Console.WriteLine($"-----------------------------> {next}: {GetNextLevel(celestial, next)} / {MaxReasearchLevel.GetLevel(next)}"); + // var nextLFtechlvl = GetNextLevel(celestial, next); + // Resources newcost = CalcPrice(next, nextLFtechlvl, costReduction); + // if (newcost.ConvertedDeuterium < currentcost.ConvertedDeuterium) { + // currentcost = newcost; + // nextLFtech = next; + // } + // } + // } + //} + + foreach (LFTechno next in Enum.GetValues()) { + int? level = celestial.LFTechs.GetLevel(next); + if (level is null) { + continue; } + if (level > 0 && GetNextLevel(celestial, next) <= MaxReasearchLevel.GetLevel(next)) { + //Console.WriteLine($"-----------------------------> {next}: {GetNextLevel(celestial, next)} / {MaxReasearchLevel.GetLevel(next)}"); + var nextLFtechlvl = GetNextLevel(celestial, next); + Resources newcost = CalcPrice(next, nextLFtechlvl, costReduction); + if (newcost.ConvertedDeuterium < currentcost.ConvertedDeuterium) { + currentcost = newcost; + nextLFtech = next; + } + } } return nextLFtech; } From da6002e56d7eadb7bec09510f38739f82cec1f39 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 26 Jun 2025 21:34:34 +0200 Subject: [PATCH 080/117] fix AutoMine LFTechs --- TBot/Includes/CalculationService.cs | 41 +---- TBot/instance_settings.json | 254 ++++++++++++++-------------- 2 files changed, 135 insertions(+), 160 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 43dd09dc..48880fe9 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -3101,13 +3101,9 @@ public int GetNextLevel(Celestial planet, LFBuildables buildable) { public int GetNextLevel(Celestial planet, LFTechno buildable) { int output = 0; - //if (planet is Planet) { - // foreach (PropertyInfo prop in planet.LFTechs.GetType().GetProperties()) { - // if (prop.Name == buildable.ToString()) { - // output = (int) prop.GetValue(planet.LFTechs) + 1; - // } - // } - //} + if (buildable is LFTechno.None) { + return output; + } if (planet is Celestial) { int? level = planet.LFTechs.GetLevel(buildable); if (level is null) { @@ -4049,17 +4045,6 @@ public LFTechno GetNextLFTechToBuild(Celestial celestial, LFTechs MaxReasearchLe //TODO //As planets can have any lifeform techs, its complicated to find which techs are existing on a planet if the techs are not at least level 1 //Therefore, for the moment, up only techs that are minimum level 1, its a way to also allows player to chose which research to up - //foreach (PropertyInfo prop in celestial.LFTechs.GetType().GetProperties()) { - // foreach (LFTechno nextLFTech in Enum.GetValues()) { - // if ((int) prop.GetValue(celestial.LFTechs) > 0 && GetNextLevel(celestial, nextLFTech) <= MaxReasearchLevel.GetLevel(nextLFTech) && prop.Name == nextLFTech.ToString()) { - // //Console.WriteLine($"-----------------------------> {nextLFTech}: {GetNextLevel(celestial, nextLFTech)} / {MaxReasearchLevel.GetLevel(nextLFTech)}"); - // return nextLFTech; - // } - - // } - //} - - foreach (LFTechno nextLFTech in Enum.GetValues()) { int? level = celestial.LFTechs.GetLevel(nextLFTech); if (level is null) { @@ -4071,28 +4056,16 @@ public LFTechno GetNextLFTechToBuild(Celestial celestial, LFTechs MaxReasearchLe return nextLFTech; } } - - return LFTechno.None; + return LFTechno.None; } public LFTechno GetLessExpensiveLFTechToBuild(Celestial celestial, Resources currentcost, LFTechs MaxReasearchLevel, double costReduction = 0) { LFTechno nextLFtech = LFTechno.None; Resource nextLFtechcost = new(); - //foreach (PropertyInfo prop in celestial.LFTechs.GetType().GetProperties()) { - // foreach (LFTechno next in Enum.GetValues()) { - // if ((int) prop.GetValue(celestial.LFTechs) > 0 && GetNextLevel(celestial, next) <= MaxReasearchLevel.GetLevel(next) && prop.Name == next.ToString()) { - // //Console.WriteLine($"-----------------------------> {next}: {GetNextLevel(celestial, next)} / {MaxReasearchLevel.GetLevel(next)}"); - // var nextLFtechlvl = GetNextLevel(celestial, next); - // Resources newcost = CalcPrice(next, nextLFtechlvl, costReduction); - // if (newcost.ConvertedDeuterium < currentcost.ConvertedDeuterium) { - // currentcost = newcost; - // nextLFtech = next; - // } - // } - // } - //} - foreach (LFTechno next in Enum.GetValues()) { + if (next is LFTechno.None) { + continue; + } int? level = celestial.LFTechs.GetLevel(next); if (level is null) { continue; diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index 9b3beec4..4c105de7 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -1,34 +1,34 @@ { "Credentials": { - "Universe": "", - "Email": "", - "Password": "", - "Language": "", - "LobbyPioneers": false, + "Universe": "Bermuda", + "Email": "reporter@netterchef.de", + "Password": "jIOj28rJFAIUOJFaw", + "Language": "en", + "LobbyPioneers": true, "BasicAuth": { "Username": "", "Password": "" }, "DeviceConf": { - "Name": "Device-name", + "Name": "reporter@netterchef.de.dev", "System": "Windows", "Browser": "Chrome", "UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", - "Memory": 8, - "Concurrency": 16, + "Memory": 16, + "Concurrency": 24, "Color": 24, "Width": 1920, "Height": 1080, "Timezone": "Europe/London", "Lang": "en" - } + } }, "General": { - "Host": "localhost", + "Host": "192.168.2.115", "Port": "8080", "Proxy": { "Enabled": false, - "Address": "", + "Address": "127.0.0.1:5789", "Type": "socks5", "Username": "", "Password": "", @@ -48,23 +48,23 @@ }, "SleepMode": { "Active": false, - "GoToSleep": "23:15", - "WakeUp": "07:05", + "GoToSleep": "08:30", + "WakeUp": "14:00", "PreventIfThereAreFleets": true, "TelegramMessenger": { "Active": false }, "AutoFleetSave": { "Active": true, - "OnlyMoons": true, - "DeutToLeave": 200000, + "OnlyMoons": false, + "DeutToLeave": 100, "Recall": true, "DefaultMission": "Deploy" } }, "Defender": { "Active": true, - "CheckIntervalMin": 1, + "CheckIntervalMin": 9, "CheckIntervalMax": 22, "IgnoreProbes": true, "DefendFromMissiles": true, @@ -77,13 +77,13 @@ }, "RandomActivity": true, "Home": { - "Galaxy": 1, - "System": 1, - "Position": 1, + "Galaxy": 5, + "System": 313, + "Position": 8, "Type": "Planet" }, "Autofleet": { - "Active": true, + "Active": false, "TelegramMessenger": { "Active": false } @@ -95,7 +95,7 @@ 100004 ], "SpyAttacker": { - "Active": true, + "Active": false, "Probes": 20 }, "MessageAttacker": { @@ -117,15 +117,15 @@ "Active": true, "Transports": { "Active": true, - "CargoType": "SmallCargo", + "CargoType": "LargeCargo", "DeutToLeaveOnMoons": 1000000, - "RoundResources": true, + "RoundResources": false, "SendToTheMoonIfPossible": false, "Origin": { - "Galaxy": 3, - "System": 333, + "Galaxy": 5, + "System": 313, "Position": 8, - "Type": "Moon" + "Type": "Planet" }, "MaxSlots": 10, "CheckMoonOrPlanetFirst": false, @@ -146,7 +146,7 @@ } }, "AutoMine": { - "Active": true, + "Active": false, "Transports": { "Active": true }, @@ -154,7 +154,7 @@ "MaxCrystalMine": 35, "MaxDeuteriumSynthetizer": 37, "MaxSolarPlant": 20, - "MaxFusionReactor": 20, + "MaxFusionReactor": 0, "MaxMetalStorage": 13, "MaxCrystalStorage": 12, "MaxDeuteriumTank": 11, @@ -162,7 +162,7 @@ "MaxShipyard": 12, "MaxResearchLab": 12, "MaxMissileSilo": 0, - "MaxNaniteFactory": 7, + "MaxNaniteFactory": 3, "MaxTerraformer": 8, "MaxSpaceDock": 7, "MaxLunarBase": 8, @@ -173,41 +173,41 @@ "RandomOrder": true, "Exclude": [ { - "Galaxy": 3, - "System": 333, - "Position": 15, + "Galaxy": 5, + "System": 119, + "Position": 6, "Type": "Planet" } ], - "OptimizeForStart": true, - "PrioritizeRobotsAndNanites": false, + "OptimizeForStart": false, + "PrioritizeRobotsAndNanites": true, "BuildDepositIfFull": false, "BuildSolarSatellites": true, - "BuildCrawlers": true, - "DepositHours": 6, - "MaxDaysOfInvestmentReturn": 7, + "BuildCrawlers": false, + "DepositHours": 24, + "MaxDaysOfInvestmentReturn": 14, "DeutToLeaveOnMoons": 1000000, "CheckIntervalMin": 10, "CheckIntervalMax": 20 }, "LifeformAutoMine": { - "Active": true, + "Active": false, "Transports": { - "Active": true + "Active": false }, - "StartFromCrystalMineLvl": 20, - "MaxBasePopulationBuilding": 60, - "MaxBaseFoodBuilding": 62, - "MaxBaseTechBuilding": 6, - "MaxT2Building": 10, - "MaxT3Building": 8, - "MaxBuilding6": 5, - "MaxBuilding7": 5, - "MaxBuilding8": 5, - "MaxBuilding9": 5, - "MaxBuilding10": 5, - "MaxBuilding11": 5, - "MaxBuilding12": 5, + "StartFromCrystalMineLvl": 15, + "MaxBasePopulationBuilding": 30, + "MaxBaseFoodBuilding": 31, + "MaxBaseTechBuilding": 1, + "MaxT2Building": 0, + "MaxT3Building": 0, + "MaxBuilding6": 0, + "MaxBuilding7": 0, + "MaxBuilding8": 0, + "MaxBuilding9": 0, + "MaxBuilding10": 0, + "MaxBuilding11": 0, + "MaxBuilding12": 0, "Exclude": [ { "Galaxy": 3, @@ -256,29 +256,29 @@ "CheckIntervalMax": 60 }, "AutoResearch": { - "Active": true, + "Active": false, "Transports": { - "Active": true + "Active": false }, - "MaxEnergyTechnology": 20, + "MaxEnergyTechnology": 10, "MaxLaserTechnology": 12, "MaxIonTechnology": 5, - "MaxHyperspaceTechnology": 20, - "MaxPlasmaTechnology": 20, - "MaxCombustionDrive": 19, - "MaxImpulseDrive": 17, - "MaxHyperspaceDrive": 15, + "MaxHyperspaceTechnology": 8, + "MaxPlasmaTechnology": 7, + "MaxCombustionDrive": 6, + "MaxImpulseDrive": 8, + "MaxHyperspaceDrive": 8, "MaxEspionageTechnology": 8, - "MaxComputerTechnology": 20, - "MaxAstrophysics": 23, - "MaxIntergalacticResearchNetwork": 12, - "MaxWeaponsTechnology": 25, - "MaxShieldingTechnology": 25, - "MaxArmourTechnology": 25, + "MaxComputerTechnology": 10, + "MaxAstrophysics": 9, + "MaxIntergalacticResearchNetwork": 4, + "MaxWeaponsTechnology": 10, + "MaxShieldingTechnology": 10, + "MaxArmourTechnology": 15, "Target": { - "Galaxy": 3, - "System": 333, - "Position": 8, + "Galaxy": 5, + "System": 119, + "Position": 6, "Type": "Planet" }, "OptimizeForStart": true, @@ -292,7 +292,7 @@ "CheckIntervalMax": 20 }, "AutoCargo": { - "Active": true, + "Active": false, "ExcludeMoons": true, "CargoType": "LargeCargo", "RandomOrder": true, @@ -312,19 +312,19 @@ "CheckIntervalMax": 240 }, "AutoRepatriate": { - "Active": true, + "Active": false, "ExcludeMoons": false, - "MinimumResources": 1000000, + "MinimumResources": 1000, "LeaveDeut": { "OnlyOnMoons": true, - "DeutToLeave": 1000000 + "DeutToLeave": 1000 }, "Target": [ { "Galaxy": 5, - "System": 63, - "Position": 8, - "Type": "Moon" + "System": 119, + "Position": 6, + "Type": "Planet" } ], "TargetAssociateMoon": false, @@ -349,16 +349,16 @@ } }, "Expeditions": { - "Active": true, + "Active": false, "IgnoreSleep": false, "MinWaitNextFleet": 5, "MaxWaitNextFleet": 15, - "PrimaryShip": "LargeCargo", - "MinPrimaryToSend": 1000, - "PrimaryToKeep": 10000, - "SecondaryShip": "Null", + "PrimaryShip": "SmallCargo", + "MinPrimaryToSend": 1, + "PrimaryToKeep": 300, + "SecondaryShip": "LargeCargo", "MinSecondaryToSend": 0, - "SecondaryToPrimaryRatio": 2, + "SecondaryToPrimaryRatio": 100, "ManualShips": { "Active": false, "Ships": { @@ -369,7 +369,7 @@ "EspionageProbe": 1 } }, - "WaitForAllExpeditions": false, + "WaitForAllExpeditions": true, "WaitForMajorityOfExpeditions": false, "MinWaitNextRound": 30, "MaxWaitNextRound": 300, @@ -378,51 +378,45 @@ "Range": 1 }, "RandomizeOrder": true, - "FuelToCarry": 20000, + "FuelToCarry": 100, "Origin": [ { "Galaxy": 5, - "System": 63, + "System": 313, "Position": 8, - "Type": "Moon" - }, - { - "Galaxy": 5, - "System": 64, - "Position": 8, - "Type": "Moon" + "Type": "Planet" } ] }, "AutoFarm": { - "Active": true, + "Active": false, "ExcludeMoons": true, "ScanRange": [ { - "Galaxy": 2, - "StartSystem": 360, - "EndSystem": 420 + "Galaxy": 5, + "StartSystem": 199, + "EndSystem": 499 } ], "Exclude": [ { - "Galaxy": 3, - "System": 3, - "Planet": 3 + "Galaxy": 1, + "System": 1, + "Planet": 1 } ], - "KeepReportFor": 180, - "NumProbes": 10, + "KeepReportFor": 1440, + "NumProbes": 52, "Origin": [ { - "Galaxy": 2, - "System": 396, - "Position": 4, + "Galaxy": 5, + "System": 313, + "Position": 8, "Type": "Planet" } ], "TargetsProbedBeforeAttack": 30, - "CargoType": "LargeCargo", + "CargoType": "SmallCargo", "FleetSpeed": 100, "MinCargosToKeep": 0, "MinCargosToSend": 25, @@ -430,12 +424,12 @@ "BuildCargos": false, "BuildProbes": false, "MinimumResources": 1000000, - "MinimumPlayerRank": 500, + "MinimumPlayerRank": 9999, "MaxFlightTime": 7200, "MaxWaitTime": 7200, "MinLootFuelRatio": 0.5, - "PreferedResource": "", - "MaxSlots": 18, + "PreferedResource": "Crystal", + "MaxSlots": 6, "SlotsToLeaveFree": 1, "CheckIntervalMin": 30, "CheckIntervalMax": 60 @@ -451,21 +445,21 @@ "CheckIntervalMax": 60 }, "AutoColonize": { - "Active": true, + "Active": false, "Origin": { "Galaxy": 5, - "System": 64, + "System": 313, "Position": 8, "Type": "Planet" }, "SlotsToLeaveFree": 0, "Abandon": { "Active": true, - "MinFields": 280, + "MinFields": 300, "MinTemperatureAcceptable": -130, "MaxTemperatureAcceptable": 260 }, - "IntensiveResearch" : { + "IntensiveResearch": { "Active": false, "MaxSlots": 10, "MinWaitNextFleet": 25, @@ -473,19 +467,27 @@ }, "Targets": [ { - "Galaxy": 1, - "StartSystem": 123, - "EndSystem": 123, - "StartPosition": 7, - "EndPosition": 9, - "MaxPlanets": 1 + "Galaxy": 5, + "StartSystem": 1, + "EndSystem": 499, + "StartPosition": 8, + "EndPosition": 8, + "MaxPlanets": 3 + }, + { + "Galaxy": 6, + "StartSystem": 1, + "EndSystem": 499, + "StartPosition": 8, + "EndPosition": 8, + "MaxPlanets": 2 }, { - "Galaxy": 3, - "StartSystem": 150, - "EndSystem": 350, - "StartPosition": 15, - "EndPosition": 15, + "Galaxy": 4, + "StartSystem": 1, + "EndSystem": 499, + "StartPosition": 8, + "EndPosition": 8, "MaxPlanets": 2 } ], @@ -494,10 +496,10 @@ "CheckIntervalMax": 1200 }, "AutoDiscovery": { - "Active": true, + "Active": false, "Origin": { "Galaxy": 5, - "System": 64, + "System": 313, "Position": 8, "Type": "Planet" }, @@ -506,4 +508,4 @@ "CheckIntervalMin": 30, "CheckIntervalMax": 60 } -} \ No newline at end of file +} From 479c782eab909815de666bbe95dff7a205bd09e0 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 26 Jun 2025 21:38:00 +0200 Subject: [PATCH 081/117] v3.2.6 * fix AutoMine LFTechs --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 21f74fc7..38f466c5 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.5 + 3.2.6 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.5 - 3.2.5 + 3.2.6 + 3.2.6 OGame Bot False ELK-Lab.pfx From 3c76a86e5045f391cf4a5adf5e4c387bb9692df8 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Thu, 26 Jun 2025 22:12:33 +0200 Subject: [PATCH 082/117] fix SlotPriorityLevel --- .../Models/RankSlotsPriority.cs | 2 +- TBot/instance_settings.json | 314 +++++++++--------- 2 files changed, 156 insertions(+), 160 deletions(-) diff --git a/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs b/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs index abc9ce97..1be10a91 100644 --- a/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs +++ b/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs @@ -9,7 +9,7 @@ namespace TBot.Ogame.Infrastructure.Models { public class RankSlotsPriority { public RankSlotsPriority(Feature feature = Feature.Null, int rank = int.MaxValue, bool active = false, int maxSlots = 0, int slotsUsed = 0) { - Rank = rank; + Rank = rank < 1 ? int.MaxValue : rank; Active = active; MaxSlots = maxSlots; SlotsUsed = slotsUsed; diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index 4c105de7..f508926c 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -1,34 +1,34 @@ { "Credentials": { - "Universe": "Bermuda", - "Email": "reporter@netterchef.de", - "Password": "jIOj28rJFAIUOJFaw", - "Language": "en", - "LobbyPioneers": true, + "Universe": "", + "Email": "", + "Password": "", + "Language": "", + "LobbyPioneers": false, "BasicAuth": { "Username": "", "Password": "" }, "DeviceConf": { - "Name": "reporter@netterchef.de.dev", + "Name": "Device-name", "System": "Windows", "Browser": "Chrome", "UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", - "Memory": 16, - "Concurrency": 24, + "Memory": 8, + "Concurrency": 16, "Color": 24, "Width": 1920, "Height": 1080, "Timezone": "Europe/London", "Lang": "en" - } + } }, "General": { - "Host": "192.168.2.115", + "Host": "localhost", "Port": "8080", "Proxy": { "Enabled": false, - "Address": "127.0.0.1:5789", + "Address": "", "Type": "socks5", "Username": "", "Password": "", @@ -48,23 +48,23 @@ }, "SleepMode": { "Active": false, - "GoToSleep": "08:30", - "WakeUp": "14:00", + "GoToSleep": "23:15", + "WakeUp": "07:05", "PreventIfThereAreFleets": true, "TelegramMessenger": { "Active": false }, "AutoFleetSave": { "Active": true, - "OnlyMoons": false, - "DeutToLeave": 100, + "OnlyMoons": true, + "DeutToLeave": 200000, "Recall": true, "DefaultMission": "Deploy" } }, "Defender": { "Active": true, - "CheckIntervalMin": 9, + "CheckIntervalMin": 1, "CheckIntervalMax": 22, "IgnoreProbes": true, "DefendFromMissiles": true, @@ -77,13 +77,13 @@ }, "RandomActivity": true, "Home": { - "Galaxy": 5, - "System": 313, - "Position": 8, + "Galaxy": 1, + "System": 1, + "Position": 1, "Type": "Planet" }, "Autofleet": { - "Active": false, + "Active": true, "TelegramMessenger": { "Active": false } @@ -95,7 +95,7 @@ 100004 ], "SpyAttacker": { - "Active": false, + "Active": true, "Probes": 20 }, "MessageAttacker": { @@ -117,15 +117,15 @@ "Active": true, "Transports": { "Active": true, - "CargoType": "LargeCargo", + "CargoType": "SmallCargo", "DeutToLeaveOnMoons": 1000000, - "RoundResources": false, + "RoundResources": true, "SendToTheMoonIfPossible": false, "Origin": { - "Galaxy": 5, - "System": 313, + "Galaxy": 3, + "System": 333, "Position": 8, - "Type": "Planet" + "Type": "Moon" }, "MaxSlots": 10, "CheckMoonOrPlanetFirst": false, @@ -146,7 +146,7 @@ } }, "AutoMine": { - "Active": false, + "Active": true, "Transports": { "Active": true }, @@ -154,7 +154,7 @@ "MaxCrystalMine": 35, "MaxDeuteriumSynthetizer": 37, "MaxSolarPlant": 20, - "MaxFusionReactor": 0, + "MaxFusionReactor": 20, "MaxMetalStorage": 13, "MaxCrystalStorage": 12, "MaxDeuteriumTank": 11, @@ -162,7 +162,7 @@ "MaxShipyard": 12, "MaxResearchLab": 12, "MaxMissileSilo": 0, - "MaxNaniteFactory": 3, + "MaxNaniteFactory": 7, "MaxTerraformer": 8, "MaxSpaceDock": 7, "MaxLunarBase": 8, @@ -173,41 +173,41 @@ "RandomOrder": true, "Exclude": [ { - "Galaxy": 5, - "System": 119, - "Position": 6, + "Galaxy": 3, + "System": 333, + "Position": 15, "Type": "Planet" } ], - "OptimizeForStart": false, - "PrioritizeRobotsAndNanites": true, + "OptimizeForStart": true, + "PrioritizeRobotsAndNanites": false, "BuildDepositIfFull": false, "BuildSolarSatellites": true, - "BuildCrawlers": false, - "DepositHours": 24, - "MaxDaysOfInvestmentReturn": 14, + "BuildCrawlers": true, + "DepositHours": 6, + "MaxDaysOfInvestmentReturn": 7, "DeutToLeaveOnMoons": 1000000, "CheckIntervalMin": 10, "CheckIntervalMax": 20 }, "LifeformAutoMine": { - "Active": false, + "Active": true, "Transports": { - "Active": false + "Active": true }, - "StartFromCrystalMineLvl": 15, - "MaxBasePopulationBuilding": 30, - "MaxBaseFoodBuilding": 31, - "MaxBaseTechBuilding": 1, - "MaxT2Building": 0, - "MaxT3Building": 0, - "MaxBuilding6": 0, - "MaxBuilding7": 0, - "MaxBuilding8": 0, - "MaxBuilding9": 0, - "MaxBuilding10": 0, - "MaxBuilding11": 0, - "MaxBuilding12": 0, + "StartFromCrystalMineLvl": 20, + "MaxBasePopulationBuilding": 60, + "MaxBaseFoodBuilding": 62, + "MaxBaseTechBuilding": 6, + "MaxT2Building": 10, + "MaxT3Building": 8, + "MaxBuilding6": 5, + "MaxBuilding7": 5, + "MaxBuilding8": 5, + "MaxBuilding9": 5, + "MaxBuilding10": 5, + "MaxBuilding11": 5, + "MaxBuilding12": 5, "Exclude": [ { "Galaxy": 3, @@ -221,64 +221,57 @@ "CheckIntervalMax": 60 }, "LifeformAutoResearch": { + "Active": false, + "Transports": { + "Active": true + }, + "MaxResearchLevel": 15, + "MaxTechs11": 15, + "MaxTechs12": 13, + "MaxTechs13": 12, + "MaxTechs14": 12, + "MaxTechs15": 15, + "MaxTechs16": 9, + "MaxTechs21": 9, + "MaxTechs22": 9, + "MaxTechs23": 5, + "MaxTechs24": 8, + "MaxTechs25": 14, + "MaxTechs26": 9, + "MaxTechs31": 0, + "MaxTechs32": 0, + "MaxTechs33": 0, + "MaxTechs34": 0, + "MaxTechs35": 0, + "MaxTechs36": 0, + "Exclude": [], + "CheckIntervalMin": 60, + "CheckIntervalMax": 120 + }, + "AutoResearch": { "Active": true, "Transports": { "Active": true }, - "MaxResearchLevel": 6, - "MaxTechs11": 6, - "MaxTechs12": 6, - "MaxTechs13": 6, - "MaxTechs14": 6, - "MaxTechs15": 6, - "MaxTechs16": 6, - "MaxTechs21": 6, - "MaxTechs22": 6, - "MaxTechs23": 6, - "MaxTechs24": 6, - "MaxTechs25": 6, - "MaxTechs26": 6, - "MaxTechs31": 6, - "MaxTechs32": 6, - "MaxTechs33": 6, - "MaxTechs34": 6, - "MaxTechs35": 6, - "MaxTechs36": 6, - "Exclude": [ - { - "Galaxy": 3, - "System": 333, - "Position": 15, - "Type": "Planet" - } - ], - "CheckIntervalMin": 30, - "CheckIntervalMax": 60 - }, - "AutoResearch": { - "Active": false, - "Transports": { - "Active": false - }, - "MaxEnergyTechnology": 10, + "MaxEnergyTechnology": 20, "MaxLaserTechnology": 12, "MaxIonTechnology": 5, - "MaxHyperspaceTechnology": 8, - "MaxPlasmaTechnology": 7, - "MaxCombustionDrive": 6, - "MaxImpulseDrive": 8, - "MaxHyperspaceDrive": 8, + "MaxHyperspaceTechnology": 20, + "MaxPlasmaTechnology": 20, + "MaxCombustionDrive": 19, + "MaxImpulseDrive": 17, + "MaxHyperspaceDrive": 15, "MaxEspionageTechnology": 8, - "MaxComputerTechnology": 10, - "MaxAstrophysics": 9, - "MaxIntergalacticResearchNetwork": 4, - "MaxWeaponsTechnology": 10, - "MaxShieldingTechnology": 10, - "MaxArmourTechnology": 15, + "MaxComputerTechnology": 20, + "MaxAstrophysics": 23, + "MaxIntergalacticResearchNetwork": 12, + "MaxWeaponsTechnology": 25, + "MaxShieldingTechnology": 25, + "MaxArmourTechnology": 25, "Target": { - "Galaxy": 5, - "System": 119, - "Position": 6, + "Galaxy": 3, + "System": 333, + "Position": 8, "Type": "Planet" }, "OptimizeForStart": true, @@ -292,7 +285,7 @@ "CheckIntervalMax": 20 }, "AutoCargo": { - "Active": false, + "Active": true, "ExcludeMoons": true, "CargoType": "LargeCargo", "RandomOrder": true, @@ -312,19 +305,19 @@ "CheckIntervalMax": 240 }, "AutoRepatriate": { - "Active": false, + "Active": true, "ExcludeMoons": false, - "MinimumResources": 1000, + "MinimumResources": 1000000, "LeaveDeut": { "OnlyOnMoons": true, - "DeutToLeave": 1000 + "DeutToLeave": 1000000 }, "Target": [ { "Galaxy": 5, - "System": 119, - "Position": 6, - "Type": "Planet" + "System": 63, + "Position": 8, + "Type": "Moon" } ], "TargetAssociateMoon": false, @@ -334,31 +327,36 @@ "Exclude": [ { "Galaxy": 3, - "System": 333, - "Position": 15, + "System": 482, + "Position": 7, "Type": "Planet" } ], - "CheckIntervalMin": 30, - "CheckIntervalMax": 60 - }, - "BuyOfferOfTheDay": { - "Active": true, - "CheckIntervalMin": 240, - "CheckIntervalMax": 360 - } - }, + "TargetAssociateMoon": true, + "CargoType": "SmallCargo", + "RandomOrder": false, + "SkipIfIncomingTransport": true, + "Exclude": [], + "CheckIntervalMin": 3000, + "CheckIntervalMax": 6000 + }, + "BuyOfferOfTheDay": { + "Active": false, + "CheckIntervalMin": 240, + "CheckIntervalMax": 360 + } + }, "Expeditions": { - "Active": false, + "Active": true, "IgnoreSleep": false, "MinWaitNextFleet": 5, "MaxWaitNextFleet": 15, - "PrimaryShip": "SmallCargo", - "MinPrimaryToSend": 1, - "PrimaryToKeep": 300, - "SecondaryShip": "LargeCargo", + "PrimaryShip": "LargeCargo", + "MinPrimaryToSend": 1000, + "PrimaryToKeep": 10000, + "SecondaryShip": "Null", "MinSecondaryToSend": 0, - "SecondaryToPrimaryRatio": 100, + "SecondaryToPrimaryRatio": 2, "ManualShips": { "Active": false, "Ships": { @@ -369,7 +367,7 @@ "EspionageProbe": 1 } }, - "WaitForAllExpeditions": true, + "WaitForAllExpeditions": false, "WaitForMajorityOfExpeditions": false, "MinWaitNextRound": 30, "MaxWaitNextRound": 300, @@ -378,13 +376,19 @@ "Range": 1 }, "RandomizeOrder": true, - "FuelToCarry": 100, + "FuelToCarry": 20000, "Origin": [ { "Galaxy": 5, - "System": 313, + "System": 63, "Position": 8, - "Type": "Planet" + "Type": "Moon" + }, + { + "Galaxy": 5, + "System": 64, + "Position": 8, + "Type": "Moon" } ] }, @@ -416,7 +420,7 @@ } ], "TargetsProbedBeforeAttack": 30, - "CargoType": "SmallCargo", + "CargoType": "LargeCargo", "FleetSpeed": 100, "MinCargosToKeep": 0, "MinCargosToSend": 25, @@ -424,12 +428,12 @@ "BuildCargos": false, "BuildProbes": false, "MinimumResources": 1000000, - "MinimumPlayerRank": 9999, + "MinimumPlayerRank": 500, "MaxFlightTime": 7200, "MaxWaitTime": 7200, "MinLootFuelRatio": 0.5, - "PreferedResource": "Crystal", - "MaxSlots": 6, + "PreferedResource": "", + "MaxSlots": 18, "SlotsToLeaveFree": 1, "CheckIntervalMin": 30, "CheckIntervalMax": 60 @@ -437,7 +441,7 @@ "AutoHarvest": { "Active": false, "HarvestOwnDF": true, - "HarvestDeepSpace": true, + "HarvestDeepSpace": false, "MinimumResourcesOwnDF": 300, "MinimumResourcesDeepSpace": 50000, "MaxSlots": 5, @@ -445,21 +449,21 @@ "CheckIntervalMax": 60 }, "AutoColonize": { - "Active": false, + "Active": true, "Origin": { "Galaxy": 5, - "System": 313, + "System": 64, "Position": 8, "Type": "Planet" }, "SlotsToLeaveFree": 0, "Abandon": { "Active": true, - "MinFields": 300, + "MinFields": 280, "MinTemperatureAcceptable": -130, "MaxTemperatureAcceptable": 260 }, - "IntensiveResearch": { + "IntensiveResearch" : { "Active": false, "MaxSlots": 10, "MinWaitNextFleet": 25, @@ -467,27 +471,19 @@ }, "Targets": [ { - "Galaxy": 5, - "StartSystem": 1, - "EndSystem": 499, - "StartPosition": 8, - "EndPosition": 8, - "MaxPlanets": 3 - }, - { - "Galaxy": 6, - "StartSystem": 1, - "EndSystem": 499, - "StartPosition": 8, - "EndPosition": 8, - "MaxPlanets": 2 + "Galaxy": 1, + "StartSystem": 123, + "EndSystem": 123, + "StartPosition": 7, + "EndPosition": 9, + "MaxPlanets": 1 }, { - "Galaxy": 4, - "StartSystem": 1, - "EndSystem": 499, - "StartPosition": 8, - "EndPosition": 8, + "Galaxy": 3, + "StartSystem": 150, + "EndSystem": 350, + "StartPosition": 15, + "EndPosition": 15, "MaxPlanets": 2 } ], @@ -499,7 +495,7 @@ "Active": false, "Origin": { "Galaxy": 5, - "System": 313, + "System": 64, "Position": 8, "Type": "Planet" }, From 6e74180f6befc00b1be31d10661429c7170f916a Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 26 Jun 2025 22:15:04 +0200 Subject: [PATCH 083/117] v3.2.6 * fix AutoMine LFTechs --- TBot.Ogame.Infrastructure/Models/LFTechs.cs | 152 ++++++++++---------- TBot/Includes/CalculationService.cs | 57 ++++---- TBot/TBot.csproj | 6 +- 3 files changed, 114 insertions(+), 101 deletions(-) diff --git a/TBot.Ogame.Infrastructure/Models/LFTechs.cs b/TBot.Ogame.Infrastructure/Models/LFTechs.cs index 1adbf90e..7fa22278 100644 --- a/TBot.Ogame.Infrastructure/Models/LFTechs.cs +++ b/TBot.Ogame.Infrastructure/Models/LFTechs.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Text; @@ -9,96 +10,99 @@ namespace TBot.Ogame.Infrastructure.Models { public class LFTechs { //Humans - public int IntergalacticEnvoys { get; set; } - public int HighPerformanceExtractors { get; set; } - public int FusionDrives { get; set; } - public int StealthFieldGenerator { get; set; } - public int OrbitalDen { get; set; } - public int ResearchAI { get; set; } - public int HighPerformanceTerraformer { get; set; } - public int EnhancedProductionTechnologies { get; set; } - public int LightFighterMkII { get; set; } - public int CruiserMkII { get; set; } - public int ImprovedLabTechnology { get; set; } - public int PlasmaTerraformer { get; set; } - public int LowTemperatureDrives { get; set; } - public int BomberMkII { get; set; } - public int DestroyerMkII { get; set; } - public int BattlecruiserMkII { get; set; } - public int RobotAssistants { get; set; } - public int Supercomputer { get; set; } + public int? IntergalacticEnvoys { get; set; } + public int? HighPerformanceExtractors { get; set; } + public int? FusionDrives { get; set; } + public int? StealthFieldGenerator { get; set; } + public int? OrbitalDen { get; set; } + public int? ResearchAI { get; set; } + public int? HighPerformanceTerraformer { get; set; } + public int? EnhancedProductionTechnologies { get; set; } + public int? LightFighterMkII { get; set; } + public int? CruiserMkII { get; set; } + public int? ImprovedLabTechnology { get; set; } + public int? PlasmaTerraformer { get; set; } + public int? LowTemperatureDrives { get; set; } + public int? BomberMkII { get; set; } + public int? DestroyerMkII { get; set; } + public int? BattlecruiserMkII { get; set; } + public int? RobotAssistants { get; set; } + public int? Supercomputer { get; set; } //Rocktal - public int VolcanicBatteries { get; set; } - public int AcousticScanning { get; set; } - public int HighEnergyPumpSystems { get; set; } - public int CargoHoldExpansionCivilianShips { get; set; } - public int MagmaPoweredProduction { get; set; } - public int GeothermalPowerPlants { get; set; } - public int DepthSounding { get; set; } - public int IonCrystalEnhancementHeavyFighter { get; set; } - public int ImprovedStellarator { get; set; } - public int HardenedDiamondDrillHeads { get; set; } - public int SeismicMiningTechnology { get; set; } - public int MagmaPoweredPumpSystems { get; set; } - public int IonCrystalModules { get; set; } - public int OptimisedSiloConstructionMethod { get; set; } - public int DiamondEnergyTransmitter { get; set; } - public int ObsidianShieldReinforcement { get; set; } - public int RuneShields { get; set; } - public int RocktalCollectorEnhancement { get; set; } + public int? VolcanicBatteries { get; set; } + public int? AcousticScanning { get; set; } + public int? HighEnergyPumpSystems { get; set; } + public int? CargoHoldExpansionCivilianShips { get; set; } + public int? MagmaPoweredProduction { get; set; } + public int? GeothermalPowerPlants { get; set; } + public int? DepthSounding { get; set; } + public int? IonCrystalEnhancementHeavyFighter { get; set; } + public int? ImprovedStellarator { get; set; } + public int? HardenedDiamondDrillHeads { get; set; } + public int? SeismicMiningTechnology { get; set; } + public int? MagmaPoweredPumpSystems { get; set; } + public int? IonCrystalModules { get; set; } + public int? OptimisedSiloConstructionMethod { get; set; } + public int? DiamondEnergyTransmitter { get; set; } + public int? ObsidianShieldReinforcement { get; set; } + public int? RuneShields { get; set; } + public int? RocktalCollectorEnhancement { get; set; } //Mechas - public int CatalyserTechnology { get; set; } - public int PlasmaDrive { get; set; } - public int EfficiencyModule { get; set; } - public int DepotAI { get; set; } - public int GeneralOverhaulLightFighter { get; set; } - public int AutomatedTransportLines { get; set; } - public int ImprovedDroneAI { get; set; } - public int ExperimentalRecyclingTechnology { get; set; } - public int GeneralOverhaulCruiser { get; set; } - public int SlingshotAutopilot { get; set; } - public int HighTemperatureSuperconductors { get; set; } - public int GeneralOverhaulBattleship { get; set; } - public int ArtificialSwarmIntelligence { get; set; } - public int GeneralOverhaulBattlecruiser { get; set; } - public int GeneralOverhaulBomber { get; set; } - public int GeneralOverhaulDestroyer { get; set; } - public int ExperimentalWeaponsTechnology { get; set; } - public int MechanGeneralEnhancement { get; set; } + public int? CatalyserTechnology { get; set; } + public int? PlasmaDrive { get; set; } + public int? EfficiencyModule { get; set; } + public int? DepotAI { get; set; } + public int? GeneralOverhaulLightFighter { get; set; } + public int? AutomatedTransportLines { get; set; } + public int? ImprovedDroneAI { get; set; } + public int? ExperimentalRecyclingTechnology { get; set; } + public int? GeneralOverhaulCruiser { get; set; } + public int? SlingshotAutopilot { get; set; } + public int? HighTemperatureSuperconductors { get; set; } + public int? GeneralOverhaulBattleship { get; set; } + public int? ArtificialSwarmIntelligence { get; set; } + public int? GeneralOverhaulBattlecruiser { get; set; } + public int? GeneralOverhaulBomber { get; set; } + public int? GeneralOverhaulDestroyer { get; set; } + public int? ExperimentalWeaponsTechnology { get; set; } + public int? MechanGeneralEnhancement { get; set; } //Kaelesh - public int HeatRecovery { get; set; } - public int SulphideProcess { get; set; } - public int PsionicNetwork { get; set; } - public int TelekineticTractorBeam { get; set; } - public int EnhancedSensorTechnology { get; set; } - public int NeuromodalCompressor { get; set; } - public int NeuroInterface { get; set; } - public int InterplanetaryAnalysisNetwork { get; set; } - public int OverclockingHeavyFighter { get; set; } - public int TelekineticDrive { get; set; } - public int SixthSense { get; set; } - public int Psychoharmoniser { get; set; } - public int EfficientSwarmIntelligence { get; set; } - public int OverclockingLargeCargo { get; set; } - public int GravitationSensors { get; set; } - public int OverclockingBattleship { get; set; } - public int PsionicShieldMatrix { get; set; } - public int KaeleshDiscovererEnhancement { get; set; } + public int? HeatRecovery { get; set; } + public int? SulphideProcess { get; set; } + public int? PsionicNetwork { get; set; } + public int? TelekineticTractorBeam { get; set; } + public int? EnhancedSensorTechnology { get; set; } + public int? NeuromodalCompressor { get; set; } + public int? NeuroInterface { get; set; } + public int? InterplanetaryAnalysisNetwork { get; set; } + public int? OverclockingHeavyFighter { get; set; } + public int? TelekineticDrive { get; set; } + public int? SixthSense { get; set; } + public int? Psychoharmoniser { get; set; } + public int? EfficientSwarmIntelligence { get; set; } + public int? OverclockingLargeCargo { get; set; } + public int? GravitationSensors { get; set; } + public int? OverclockingBattleship { get; set; } + public int? PsionicShieldMatrix { get; set; } + public int? KaeleshDiscovererEnhancement { get; set; } public int GetLevel(LFTechno building) { int output = 0; foreach (PropertyInfo prop in GetType().GetProperties()) { if (prop.Name == building.ToString()) { - output = (int) prop.GetValue(this); + object value = prop.GetValue(this, null); + if (value is not null) { + output = (int) prop.GetValue(this, null); + } } } return output; } - public LFTechs SetLevel(LFTechno buildable, int level) { + public LFTechs SetLevel(LFTechno buildable, int? level) { foreach (PropertyInfo prop in this.GetType().GetProperties()) { if (prop.Name == buildable.ToString()) { prop.SetValue(this, level); diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 1fab3001..48880fe9 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis.Operations; using System.Reflection.Emit; using System.Data; +using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Tbot.Includes { @@ -3100,12 +3101,15 @@ public int GetNextLevel(Celestial planet, LFBuildables buildable) { public int GetNextLevel(Celestial planet, LFTechno buildable) { int output = 0; - if (planet is Planet) { - foreach (PropertyInfo prop in planet.LFTechs.GetType().GetProperties()) { - if (prop.Name == buildable.ToString()) { - output = (int) prop.GetValue(planet.LFTechs) + 1; - } + if (buildable is LFTechno.None) { + return output; + } + if (planet is Celestial) { + int? level = planet.LFTechs.GetLevel(buildable); + if (level is null) { + return output; } + output = planet.LFTechs.GetLevel(buildable) + 1; } return output; } @@ -4041,15 +4045,16 @@ public LFTechno GetNextLFTechToBuild(Celestial celestial, LFTechs MaxReasearchLe //TODO //As planets can have any lifeform techs, its complicated to find which techs are existing on a planet if the techs are not at least level 1 //Therefore, for the moment, up only techs that are minimum level 1, its a way to also allows player to chose which research to up - foreach (PropertyInfo prop in celestial.LFTechs.GetType().GetProperties()) { - foreach (LFTechno nextLFTech in Enum.GetValues()) { - if ((int) prop.GetValue(celestial.LFTechs) > 0 && GetNextLevel(celestial, nextLFTech) <= MaxReasearchLevel.GetLevel(nextLFTech) && prop.Name == nextLFTech.ToString()) { - //Console.WriteLine($"-----------------------------> {nextLFTech}: {GetNextLevel(celestial, nextLFTech)} / {MaxReasearchLevel.GetLevel(nextLFTech)}"); - return nextLFTech; - } - + foreach (LFTechno nextLFTech in Enum.GetValues()) { + int? level = celestial.LFTechs.GetLevel(nextLFTech); + if (level is null) { + continue; } + if (level > 0 && GetNextLevel(celestial, nextLFTech) <= MaxReasearchLevel.GetLevel(nextLFTech)) { + //Console.WriteLine($"-----------------------------> {nextLFTech}: {GetNextLevel(celestial, nextLFTech)} / {MaxReasearchLevel.GetLevel(nextLFTech)}"); + return nextLFTech; + } } return LFTechno.None; } @@ -4057,20 +4062,24 @@ public LFTechno GetNextLFTechToBuild(Celestial celestial, LFTechs MaxReasearchLe public LFTechno GetLessExpensiveLFTechToBuild(Celestial celestial, Resources currentcost, LFTechs MaxReasearchLevel, double costReduction = 0) { LFTechno nextLFtech = LFTechno.None; Resource nextLFtechcost = new(); - foreach (PropertyInfo prop in celestial.LFTechs.GetType().GetProperties()) { - foreach (LFTechno next in Enum.GetValues()) { - if ((int) prop.GetValue(celestial.LFTechs) > 0 && GetNextLevel(celestial, next) <= MaxReasearchLevel.GetLevel(next) && prop.Name == next.ToString()) { - //Console.WriteLine($"-----------------------------> {next}: {GetNextLevel(celestial, next)} / {MaxReasearchLevel.GetLevel(next)}"); - var nextLFtechlvl = GetNextLevel(celestial, next); - Resources newcost = CalcPrice(next, nextLFtechlvl, costReduction); - if (newcost.ConvertedDeuterium < currentcost.ConvertedDeuterium) { - currentcost = newcost; - nextLFtech = next; - } - } - + foreach (LFTechno next in Enum.GetValues()) { + if (next is LFTechno.None) { + continue; + } + int? level = celestial.LFTechs.GetLevel(next); + if (level is null) { + continue; } + if (level > 0 && GetNextLevel(celestial, next) <= MaxReasearchLevel.GetLevel(next)) { + //Console.WriteLine($"-----------------------------> {next}: {GetNextLevel(celestial, next)} / {MaxReasearchLevel.GetLevel(next)}"); + var nextLFtechlvl = GetNextLevel(celestial, next); + Resources newcost = CalcPrice(next, nextLFtechlvl, costReduction); + if (newcost.ConvertedDeuterium < currentcost.ConvertedDeuterium) { + currentcost = newcost; + nextLFtech = next; + } + } } return nextLFtech; } diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 21f74fc7..38f466c5 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.5 + 3.2.6 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.5 - 3.2.5 + 3.2.6 + 3.2.6 OGame Bot False ELK-Lab.pfx From 42e50687c5403d7441d95f20ec7816b865ec6921 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Tue, 1 Jul 2025 21:01:44 +0200 Subject: [PATCH 084/117] update DeutToLeaveOnMoons and SlotsPriority repartition --- TBot/Includes/CalculationService.cs | 22 ++++++++++++---------- TBot/Workers/FleetScheduler.cs | 8 ++++---- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 48880fe9..62bfdf07 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4843,7 +4843,7 @@ public bool IsThereMoonHere(List planets, Celestial celestial) { public int CalcSlotsPriority(Feature feature, List rankSlotsPriority, Slots slots, List fleets, int slotsToLeaveFree = 0) { int slotsAvailable = 0; - int reservedSlots = slotsToLeaveFree; + int reservedSlots = 0; int otherSlots = (int) fleets.Where(fleet => (fleet.Mission != Missions.Transport && fleet.Mission != Missions.Expedition && fleet.Mission != Missions.Attack && fleet.Mission != Missions.Spy && fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery)).Count(); int usedSlots = 0; LogSender logsender; @@ -4890,11 +4890,12 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP if (actualFeature.Rank > 0) { reservedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Where(f => f.Rank < actualFeature.Rank).Sum(f => f.MaxSlots); - usedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Where(f => f.Rank <= actualFeature.Rank).Sum(f => f.SlotsUsed); - otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank >= actualFeature.Rank).Sum(f => f.SlotsUsed); - otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed); - slotsAvailable = slots.Total - reservedSlots - otherSlots; - _logger.WriteLog(LogLevel.Information, logsender, $"Total slots: {slots.Total}. {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other."); + usedSlots += rankSlotsPriority.Where(f => f.Active).Sum(f => f.SlotsUsed); + otherSlots += rankSlotsPriority.Where(f => !f.Active).Sum(f => f.SlotsUsed); + /*otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank > actualFeature.Rank).Sum(f => f.SlotsUsed); + otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed);*/ + slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots; + _logger.WriteLog(LogLevel.Information, logsender, $"Total slots: {slots.Total}. {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other. {slotsAvailable} are availables."); if (slotsAvailable > 0) { if ((actualFeature.MaxSlots - actualFeature.SlotsUsed) <= 0) { _logger.WriteLog(LogLevel.Information, logsender, $"All reserved slots for {feature.ToString()} are used ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots})."); @@ -4912,10 +4913,11 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP } } else { reservedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Sum(f => f.MaxSlots); - usedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Sum(f => f.SlotsUsed); - otherSlots += rankSlotsPriority.Where(f => !f.Active).Where(f => f.Rank > 0).Sum(f => f.SlotsUsed); - otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed); - slotsAvailable = slots.Total - reservedSlots - otherSlots; + usedSlots += rankSlotsPriority.Where(f => f.Active).Sum(f => f.SlotsUsed); + otherSlots += rankSlotsPriority.Where(f => !f.Active).Sum(f => f.SlotsUsed); + /*otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank > actualFeature.Rank).Sum(f => f.SlotsUsed); + otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed);*/ + slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots; if (slotsAvailable > 0) { _logger.WriteLog(LogLevel.Information, logsender, $"Total slots: {slots.Total} and {slotsToLeaveFree} must remain free. {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other. {slotsAvailable} are availables and can be used for {feature.ToString()}"); return slotsAvailable; diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index a0759210..980daf56 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -840,8 +840,8 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat } else { var missingResources = resources.Difference(destination.Resources); Resources resToLeave = new(0, 0, 0); - if ((long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave > 0) - resToLeave.Deuterium = (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave; + if ((long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeaveOnMoons > 0) + resToLeave.Deuterium = (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeaveOnMoons; origin = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Resources); if (origin.Resources.IsEnoughFor(missingResources, resToLeave)) { @@ -991,8 +991,8 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat } else { var missingResources = resources.Difference(destination.Resources); Resources resToLeave = new(0, 0, 0); - if ((long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave > 0) - resToLeave.Deuterium = (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeave; + if ((long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeaveOnMoons > 0) + resToLeave.Deuterium = (long) _tbotInstance.InstanceSettings.Brain.Transports.DeutToLeaveOnMoons; origin = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Resources); if (origin.Resources.IsEnoughFor(missingResources, resToLeave)) { From b2069c3c9a56c28eb5b48f11636c52adece12595 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 5 Jul 2025 18:06:50 +0200 Subject: [PATCH 085/117] v3.2.7 * fix login issues * fix delete messages * update deps ogamed --- TBot.Ogame.Infrastructure/Models/AuctionResourcesValue.cs | 2 +- TBot/TBot.csproj | 6 +++--- ogame | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/TBot.Ogame.Infrastructure/Models/AuctionResourcesValue.cs b/TBot.Ogame.Infrastructure/Models/AuctionResourcesValue.cs index 7046124c..6f01d3ab 100644 --- a/TBot.Ogame.Infrastructure/Models/AuctionResourcesValue.cs +++ b/TBot.Ogame.Infrastructure/Models/AuctionResourcesValue.cs @@ -15,7 +15,7 @@ public class AuctionResourcesValue { [JsonProperty("name")] public string Name { get; set; } - public int otherPlanetId { get; set; } = 0; + public int? otherPlanetId { get; set; } = 0; public override string ToString() { string outStr = "["; diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 38f466c5..398cfe14 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.6 + 3.2.7 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.6 - 3.2.6 + 3.2.7 + 3.2.7 OGame Bot False ELK-Lab.pfx diff --git a/ogame b/ogame index 32a8ab7b..ef9f3735 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit 32a8ab7bec123b30b5f89ff83a4d4b1200b1a09d +Subproject commit ef9f37356d1ddcf90b72b35b25cd0c500594b167 From 72e2caf49398b2bf65068c69dea83caf2f0d864a Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 10 Jul 2025 17:30:03 +0200 Subject: [PATCH 086/117] * update deps --- ogame | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ogame b/ogame index ef9f3735..f1d908f0 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit ef9f37356d1ddcf90b72b35b25cd0c500594b167 +Subproject commit f1d908f0c2a8d89e814884eb95211d87c6a80b11 From ae5ee3b34313b023a04a81367f4af125521673b1 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 10 Jul 2025 17:31:10 +0200 Subject: [PATCH 087/117] v3.2.8 * update ogamed --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 398cfe14..4f140295 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.7 + 3.2.8 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.7 - 3.2.7 + 3.2.8 + 3.2.8 OGame Bot False ELK-Lab.pfx From 6decac1899c551dc63c2d41b3963a53a9973142f Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 13 Jul 2025 18:08:56 +0200 Subject: [PATCH 088/117] v3.2.9 fix Expedition Fleet preparation using Math.Floor instead of Math.Round function. --- TBot/Includes/CalculationService.cs | 3 ++- TBot/TBot.csproj | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 62bfdf07..0c44aaa5 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -663,7 +663,8 @@ public Ships CalcExpeditionShips(Ships fleet, Buildables primaryShip, int expedi long availableVal = (long) prop.GetValue(fleet); long idealVal = (long) prop.GetValue(ideal); if (availableVal < idealVal * expeditionsNumber) { - long realVal = (long) Math.Round(((float) availableVal / (float) expeditionsNumber), MidpointRounding.AwayFromZero); + //long realVal = (long) Math.Round(((float) availableVal / (float) expeditionsNumber), MidpointRounding.AwayFromZero); + long realVal = (long) Math.Floor(((float) availableVal / (float) expeditionsNumber)); prop.SetValue(ideal, realVal); } } diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 4f140295..330ac721 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.8 + 3.2.9 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.8 - 3.2.8 + 3.2.9 + 3.2.9 OGame Bot False ELK-Lab.pfx From b7203ef72768276257f0c87e1cf2cb2926149e49 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 23 Jul 2025 11:38:00 +0200 Subject: [PATCH 089/117] fix slot calculation issue where usedSlots counted twice. --- TBot/Includes/CalculationService.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index 0c44aaa5..d73a6183 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4895,7 +4895,8 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP otherSlots += rankSlotsPriority.Where(f => !f.Active).Sum(f => f.SlotsUsed); /*otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank > actualFeature.Rank).Sum(f => f.SlotsUsed); otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed);*/ - slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots; + //slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots; // usedSlots is alread measured in reservedSlots variable + slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - otherSlots; _logger.WriteLog(LogLevel.Information, logsender, $"Total slots: {slots.Total}. {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other. {slotsAvailable} are availables."); if (slotsAvailable > 0) { if ((actualFeature.MaxSlots - actualFeature.SlotsUsed) <= 0) { @@ -4918,7 +4919,8 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP otherSlots += rankSlotsPriority.Where(f => !f.Active).Sum(f => f.SlotsUsed); /*otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank > actualFeature.Rank).Sum(f => f.SlotsUsed); otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed);*/ - slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots; + //slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots; // usedSlots is alread measured in reservedSlots variable + slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - otherSlots; if (slotsAvailable > 0) { _logger.WriteLog(LogLevel.Information, logsender, $"Total slots: {slots.Total} and {slotsToLeaveFree} must remain free. {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other. {slotsAvailable} are availables and can be used for {feature.ToString()}"); return slotsAvailable; From 2992b02505d4fb357235eaf0dd1a7378f145df1d Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 23 Jul 2025 11:38:43 +0200 Subject: [PATCH 090/117] v3.3.0 * fix Slot calculation service --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 330ac721..2001b84d 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.2.9 + 3.3.0 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.2.9 - 3.2.9 + 3.3.0 + 3.3.0 OGame Bot False ELK-Lab.pfx From ab5c3a26811433089c7d521b12274ad320bdf353 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 26 Jul 2025 08:20:02 +0200 Subject: [PATCH 091/117] * refactoring discovery @zeus * refactoring slot logic and CalculationService @zeus --- TBot.Ogame.Infrastructure/IOgameService.cs | 4 +- TBot.Ogame.Infrastructure/OgameService.cs | 66 ++++--- TBot/Includes/CalculationService.cs | 161 +++++++-------- TBot/Workers/AutoDiscoveryWorker.cs | 216 +++++++++++---------- TBot/Workers/ColonizeWorker.cs | 27 +-- TBot/Workers/FleetScheduler.cs | 12 +- 6 files changed, 249 insertions(+), 237 deletions(-) diff --git a/TBot.Ogame.Infrastructure/IOgameService.cs b/TBot.Ogame.Infrastructure/IOgameService.cs index 1c52da84..230e9811 100644 --- a/TBot.Ogame.Infrastructure/IOgameService.cs +++ b/TBot.Ogame.Infrastructure/IOgameService.cs @@ -95,6 +95,8 @@ void Initialize(Credentials credentials, Task SendMessage(int playerID, string message); Task SetUserAgent(string userAgent); Task SolveCaptcha(string challengeID, int answer); - Task AbandonCelestial(Celestial celestial); + Task AbandonCelestial(Celestial celestial); + Task> GetPositionsAvailableForDiscoveryFleet(Celestial celestial, Coordinate coordinate); + Task GetAvailableDiscoveries(Celestial celestial); } } diff --git a/TBot.Ogame.Infrastructure/OgameService.cs b/TBot.Ogame.Infrastructure/OgameService.cs index 5edb9e08..b44dddc4 100644 --- a/TBot.Ogame.Infrastructure/OgameService.cs +++ b/TBot.Ogame.Infrastructure/OgameService.cs @@ -562,34 +562,38 @@ public async Task CancelResearch(Celestial celestial) { } public async Task SendFleet(Celestial origin, Ships ships, Coordinate destination, Missions mission, decimal speed, Resources payload) { - List> parameters = new List>(); - parameters.Add(new KeyValuePair("galaxy", destination.Galaxy.ToString())); - parameters.Add(new KeyValuePair("system", destination.System.ToString())); - parameters.Add(new KeyValuePair("position", destination.Position.ToString())); - parameters.Add(new KeyValuePair("type", ((int) destination.Type).ToString())); - - var request = new RestRequest { - Resource = $"/bot/planets/{origin.ID}/send-fleet", - Method = Method.Post, - }; - foreach (PropertyInfo prop in ships.GetType().GetProperties()) { - long qty = (long) prop.GetValue(ships, null); - if (qty == 0) - continue; - if (Enum.TryParse(prop.Name, out Buildables buildable)) { - parameters.Add(new KeyValuePair("ships", (int) buildable + "," + prop.GetValue(ships, null))); + try { + List> parameters = new List>(); + parameters.Add(new KeyValuePair("galaxy", destination.Galaxy.ToString())); + parameters.Add(new KeyValuePair("system", destination.System.ToString())); + parameters.Add(new KeyValuePair("position", destination.Position.ToString())); + parameters.Add(new KeyValuePair("type", ((int)destination.Type).ToString())); + + var request = new RestRequest { + Resource = $"/bot/planets/{origin.ID}/send-fleet", + Method = Method.Post, + }; + foreach (PropertyInfo prop in ships.GetType().GetProperties()) { + long qty = (long) prop.GetValue(ships, null); + if (qty == 0) + continue; + if (Enum.TryParse(prop.Name, out Buildables buildable)) { + parameters.Add(new KeyValuePair("ships", (int) buildable + "," + prop.GetValue(ships, null))); + } } - } - parameters.Add(new KeyValuePair("mission", ((int) mission).ToString())); + parameters.Add(new KeyValuePair("mission", ((int) mission).ToString())); - parameters.Add(new KeyValuePair("speed", speed.ToString())); - parameters.Add(new KeyValuePair("metal", payload.Metal.ToString())); - parameters.Add(new KeyValuePair("crystal", payload.Crystal.ToString())); - parameters.Add(new KeyValuePair("deuterium", payload.Deuterium.ToString())); - parameters.Add(new KeyValuePair("food", payload.Food.ToString())); + parameters.Add(new KeyValuePair("speed", speed.ToString())); + parameters.Add(new KeyValuePair("metal", payload.Metal.ToString())); + parameters.Add(new KeyValuePair("crystal", payload.Crystal.ToString())); + parameters.Add(new KeyValuePair("deuterium", payload.Deuterium.ToString())); + parameters.Add(new KeyValuePair("food", payload.Food.ToString())); - return await PostAsync($"/bot/planets/{origin.ID}/send-fleet", parameters.ToArray()); + return await PostAsync($"/bot/planets/{origin.ID}/send-fleet", parameters.ToArray()); + } catch (OgamedException e) when (e.Message.Contains("no ships to send")) { + return null; + } } public async Task CancelFleet(Fleet fleet) { @@ -728,7 +732,19 @@ public async Task SendDiscovery(Celestial origin, Coordinate coords) { return success; } - public async Task AbandonCelestial(Celestial celestial) { + public async Task> GetPositionsAvailableForDiscoveryFleet(Celestial celestial, Coordinate coordinate) { + List> parameters = new List>(); + parameters.Add(new KeyValuePair("galaxy", coordinate.Galaxy.ToString())); + parameters.Add(new KeyValuePair("system", coordinate.System.ToString())); + parameters.Add(new KeyValuePair("position", coordinate.Position.ToString())); + return await PostAsync>($"/bot/planets/{celestial.ID}/get-system-available-discovery", parameters.ToArray()); + } + + public async Task GetAvailableDiscoveries(Celestial celestial) { + return await GetAsync($"/bot/planets/{celestial.ID}/get-available-discoveries"); + } + + public async Task AbandonCelestial(Celestial celestial) { bool success = false; try { Abandon result = await GetAsync($"/bot/celestials/{celestial.ID}/abandon"); diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index d73a6183..eb5f1b43 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -4841,98 +4841,83 @@ public bool IsThereMoonHere(List planets, Celestial celestial) { return moon.ID == 0 ? false: true; } - public int CalcSlotsPriority(Feature feature, List rankSlotsPriority, Slots slots, List fleets, int slotsToLeaveFree = 0) { - - int slotsAvailable = 0; - int reservedSlots = 0; - int otherSlots = (int) fleets.Where(fleet => (fleet.Mission != Missions.Transport && fleet.Mission != Missions.Expedition && fleet.Mission != Missions.Attack && fleet.Mission != Missions.Spy && fleet.Mission != Missions.Colonize && fleet.Mission != Missions.Discovery)).Count(); - int usedSlots = 0; + public int CalcSlotsPriority(Feature feature, List rankSlotsPriority, Slots slots, List fleets, int slotsToLeaveFree = 0) + { LogSender logsender; - switch (feature) { - case Feature.BrainAutoMine: - logsender = LogSender.AutoMine; - break; - case Feature.BrainAutoResearch: - logsender = LogSender.AutoResearch; - break; - case Feature.BrainLifeformAutoMine: - logsender = LogSender.LifeformsAutoMine; - break; - case Feature.BrainLifeformAutoResearch: - logsender = LogSender.LifeformsAutoResearch; - break; - case Feature.Expeditions: - logsender = LogSender.Expeditions; - break; - case Feature.AutoFarm: - logsender = LogSender.AutoFarm; - break; - case Feature.Colonize: - logsender = LogSender.Colonize; - break; - case Feature.AutoDiscovery: - logsender = LogSender.AutoDiscovery; - break; - case Feature.Harvest: - logsender = LogSender.Harvest; - break; - default: - logsender = LogSender.FleetScheduler; - break; + switch (feature) + { + case Feature.BrainAutoMine: logsender = LogSender.AutoMine; break; + case Feature.BrainAutoResearch: logsender = LogSender.AutoResearch; break; + case Feature.BrainLifeformAutoMine: logsender = LogSender.LifeformsAutoMine; break; + case Feature.BrainLifeformAutoResearch: logsender = LogSender.LifeformsAutoResearch; break; + case Feature.Expeditions: logsender = LogSender.Expeditions; break; + case Feature.AutoFarm: logsender = LogSender.AutoFarm; break; + case Feature.Colonize: logsender = LogSender.Colonize; break; + case Feature.AutoDiscovery: logsender = LogSender.AutoDiscovery; break; + case Feature.Harvest: logsender = LogSender.Harvest; break; + default: logsender = LogSender.FleetScheduler; break; } - if (slots.Free - slotsToLeaveFree > 0) { - rankSlotsPriority.Where(f => (f.Feature == Feature.BrainAutoMine || f.Feature == Feature.BrainAutoResearch || f.Feature == Feature.BrainLifeformAutoMine || f.Feature == Feature.BrainLifeformAutoResearch)).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Transport).Count(); - rankSlotsPriority.Where(f => f.Feature == Feature.Expeditions).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Expedition).Count(); - rankSlotsPriority.Where(f => f.Feature == Feature.AutoFarm).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Attack).Count(); - rankSlotsPriority.Where(f => f.Feature == Feature.Colonize).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Colonize).Count(); - rankSlotsPriority.Where(f => f.Feature == Feature.AutoDiscovery).SingleOrDefault().SlotsUsed = fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count(); - rankSlotsPriority = rankSlotsPriority.OrderBy(r => r.Rank).ToList(); - RankSlotsPriority actualFeature = rankSlotsPriority.Where(f => (f.Feature == feature)).SingleOrDefault(); - - if (actualFeature.Rank > 0) { - reservedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Where(f => f.Rank < actualFeature.Rank).Sum(f => f.MaxSlots); - usedSlots += rankSlotsPriority.Where(f => f.Active).Sum(f => f.SlotsUsed); - otherSlots += rankSlotsPriority.Where(f => !f.Active).Sum(f => f.SlotsUsed); - /*otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank > actualFeature.Rank).Sum(f => f.SlotsUsed); - otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed);*/ - //slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots; // usedSlots is alread measured in reservedSlots variable - slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - otherSlots; - _logger.WriteLog(LogLevel.Information, logsender, $"Total slots: {slots.Total}. {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other. {slotsAvailable} are availables."); - if (slotsAvailable > 0) { - if ((actualFeature.MaxSlots - actualFeature.SlotsUsed) <= 0) { - _logger.WriteLog(LogLevel.Information, logsender, $"All reserved slots for {feature.ToString()} are used ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots})."); - return 0; - } else if (slotsAvailable < (actualFeature.MaxSlots - actualFeature.SlotsUsed)) { - _logger.WriteLog(LogLevel.Information, logsender, $"Less slots available. Steping back to {slotsAvailable} instead of {actualFeature.MaxSlots - actualFeature.SlotsUsed} ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots} used)"); - return slotsAvailable; - } else { - _logger.WriteLog(LogLevel.Information, logsender, $"{slots.Free} slots are Free. {slotsAvailable} are availables and {actualFeature.SlotsUsed}/{actualFeature.MaxSlots} used for {feature.ToString()}"); - return actualFeature.MaxSlots - actualFeature.SlotsUsed; - } - } else { - _logger.WriteLog(LogLevel.Information, logsender, $"No slots available."); - return 0; - } - } else { - reservedSlots += rankSlotsPriority.Where(f => f.Active).Where(f => f.Rank > 0).Sum(f => f.MaxSlots); - usedSlots += rankSlotsPriority.Where(f => f.Active).Sum(f => f.SlotsUsed); - otherSlots += rankSlotsPriority.Where(f => !f.Active).Sum(f => f.SlotsUsed); - /*otherSlots += rankSlotsPriority.Where(f => f.Rank > 0).Where(f => f.Rank > actualFeature.Rank).Sum(f => f.SlotsUsed); - otherSlots += rankSlotsPriority.Where(f => f.Rank == 0).Sum(f => f.SlotsUsed);*/ - //slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots; // usedSlots is alread measured in reservedSlots variable - slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - otherSlots; - if (slotsAvailable > 0) { - _logger.WriteLog(LogLevel.Information, logsender, $"Total slots: {slots.Total} and {slotsToLeaveFree} must remain free. {reservedSlots} slots are reserved ({usedSlots} used) and {otherSlots} are used for other. {slotsAvailable} are availables and can be used for {feature.ToString()}"); - return slotsAvailable; - } else { - _logger.WriteLog(LogLevel.Information, logsender, $"No slots available. Total slots: {slots.Total}, {slotsToLeaveFree} must remain free, {reservedSlots} slots are reserved and {otherSlots} are used for other."); - return 0; - } - } - } else { - _logger.WriteLog(LogLevel.Information, logsender, "No slots left, delaying"); + + // Handle Expedition slots separately and first. + int expeditionSlotsTotal = slots.ExpTotal; + int expeditionSlotsInUse = fleets.Count(fleet => fleet.Mission == Missions.Expedition); + int expeditionSlotsFree = expeditionSlotsTotal - expeditionSlotsInUse; + + if (feature == Feature.Expeditions) + { + var expeditionFeature = rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.Expeditions); + int maxExpeditions = expeditionFeature?.MaxSlots ?? 0; + int availableForExpedition = Math.Min(expeditionSlotsFree, maxExpeditions - expeditionSlotsInUse); + _logger.WriteLog(LogLevel.Information, logsender, $"Expedition slots: {expeditionSlotsInUse}/{expeditionSlotsTotal} used. Can send {availableForExpedition} more."); + return Math.Max(0, availableForExpedition); // Ensure it doesn't return negative + } + + // Calculation for normal fleet slots + // Normal slots are total slots MINUS expedition slots. + int normalSlotsTotal = slots.Total - expeditionSlotsTotal; + + // Update slots used for each feature based on current fleets + rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.BrainAutoMine || f.Feature == Feature.BrainAutoResearch || f.Feature == Feature.BrainLifeformAutoMine || f.Feature == Feature.BrainLifeformAutoResearch).SlotsUsed = fleets.Count(fleet => fleet.Mission == Missions.Transport); + rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.AutoFarm).SlotsUsed = fleets.Count(fleet => fleet.Mission == Missions.Attack); + rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.Colonize).SlotsUsed = fleets.Count(fleet => fleet.Mission == Missions.Colonize); + rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.AutoDiscovery).SlotsUsed = fleets.Count(fleet => fleet.Mission == Missions.Discovery); + rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.Expeditions).SlotsUsed = expeditionSlotsInUse; // Keep this updated for other parts of the bot + + // Slots used by fleets not managed by an active feature (excluding expeditions) + int otherSlots = fleets.Count(fleet => + fleet.Mission != Missions.Transport && + fleet.Mission != Missions.Expedition && + fleet.Mission != Missions.Attack && + fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Colonize && + fleet.Mission != Missions.Discovery); + + // Sum of slots currently in use by active features (excluding expeditions) + int usedSlotsByActiveFeatures = rankSlotsPriority.Where(f => f.Active && f.Feature != Feature.Expeditions).Sum(f => f.SlotsUsed); + + // Calculate available slots for normal fleets + int slotsAvailable = normalSlotsTotal - usedSlotsByActiveFeatures - otherSlots - slotsToLeaveFree; + + _logger.WriteLog(LogLevel.Information, logsender, $"Normal Slots: {normalSlotsTotal} total. Used by features: {usedSlotsByActiveFeatures}. Used by other: {otherSlots}. To leave free: {slotsToLeaveFree}. Available: {slotsAvailable}."); + + if (slotsAvailable <= 0) + { + _logger.WriteLog(LogLevel.Information, logsender, "No normal fleet slots available."); return 0; } + + // Check if the current feature can use the available slots + var actualFeature = rankSlotsPriority.SingleOrDefault(f => f.Feature == feature); + if (actualFeature != null && actualFeature.Active) + { + int canBeUsedByFeature = actualFeature.MaxSlots - actualFeature.SlotsUsed; + int result = Math.Min(slotsAvailable, canBeUsedByFeature); + _logger.WriteLog(LogLevel.Information, logsender, $"Feature {feature} can use up to {canBeUsedByFeature} slots. Granting: {result}"); + return Math.Max(0, result); + } + + // Default return for features not in priority list or inactive + return Math.Max(0, slotsAvailable); } public List> CalcMultipleOrigin(Celestial celestialToBuild, List allCelestials, Resources missingResources, TransportSettings transportSettings, List fleets, UserData userData) { diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index b9e03b6a..a28ceaa4 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -34,67 +34,72 @@ public AutoDiscoveryWorker(ITBotMain parentInstance, } protected override async Task Execute() { - bool delay = false; bool stop = false; - int failures = 0; int skips = 0; var rand = new Random(); - try { - if (_tbotInstance.UserData.discoveryBlackList == null) { + try + { + if (_tbotInstance.UserData.discoveryBlackList == null) + { _tbotInstance.UserData.discoveryBlackList = new Dictionary(); } - if (!_tbotInstance.UserData.isSleeping) { + if (!_tbotInstance.UserData.isSleeping) + { DoLog(LogLevel.Information, $"Starting AutoDiscovery..."); _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new() { + List rankSlotsPriority = new() + { new RankSlotsPriority(Feature.BrainAutoMine, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool)_tbotInstance.InstanceSettings.Brain.Active && (bool)_tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool)_tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int)_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), new RankSlotsPriority(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal), + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool)_tbotInstance.InstanceSettings.Expeditions.Active, + (int)_tbotInstance.UserData.slots.ExpTotal), new RankSlotsPriority(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool)_tbotInstance.InstanceSettings.AutoFarm.Active, + (int)_tbotInstance.InstanceSettings.AutoFarm.MaxSlots), new RankSlotsPriority(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool)_tbotInstance.InstanceSettings.AutoColonize.Active, + (bool)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : 1), new RankSlotsPriority(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool)_tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int)_tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), new RankSlotsPriority(Feature.Harvest, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, - (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool)_tbotInstance.InstanceSettings.AutoHarvest.Active, + (int)_tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) }; - int MaxSlots = _calculationService.CalcSlotsPriority(Feature.AutoDiscovery, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.AutoDiscovery, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree); Celestial origin = _tbotInstance.UserData.celestials .Unique() - .Where(c => c.Coordinate.Galaxy == (int) _tbotInstance.InstanceSettings.AutoDiscovery.Origin.Galaxy) - .Where(c => c.Coordinate.System == (int) _tbotInstance.InstanceSettings.AutoDiscovery.Origin.System) - .Where(c => c.Coordinate.Position == (int) _tbotInstance.InstanceSettings.AutoDiscovery.Origin.Position) - .Where(c => c.Coordinate.Type == Enum.Parse((string) _tbotInstance.InstanceSettings.AutoDiscovery.Origin.Type)) + .Where(c => c.Coordinate.Galaxy == (int)_tbotInstance.InstanceSettings.AutoDiscovery.Origin.Galaxy) + .Where(c => c.Coordinate.System == (int)_tbotInstance.InstanceSettings.AutoDiscovery.Origin.System) + .Where(c => c.Coordinate.Position == (int)_tbotInstance.InstanceSettings.AutoDiscovery.Origin.Position) + .Where(c => c.Coordinate.Type == Enum.Parse((string)_tbotInstance.InstanceSettings.AutoDiscovery.Origin.Type)) .SingleOrDefault() ?? new() { ID = 0 }; - if (origin.ID == 0) { + if (origin.ID == 0) + { stop = true; DoLog(LogLevel.Warning, "Unable to parse AutoDiscovery origin"); return; } - - if ((bool) _tbotInstance.InstanceSettings.SleepMode.Active) { - DateTime.TryParse((string) _tbotInstance.InstanceSettings.SleepMode.GoToSleep, out DateTime goToSleep); - DateTime.TryParse((string) _tbotInstance.InstanceSettings.SleepMode.WakeUp, out DateTime wakeUp); + + if ((bool)_tbotInstance.InstanceSettings.SleepMode.Active) + { + DateTime.TryParse((string)_tbotInstance.InstanceSettings.SleepMode.GoToSleep, out DateTime goToSleep); + DateTime.TryParse((string)_tbotInstance.InstanceSettings.SleepMode.WakeUp, out DateTime wakeUp); DateTime time = await _tbotOgameBridge.GetDateTime(); - if (GeneralHelper.ShouldSleep(time, goToSleep, wakeUp)) { + if (GeneralHelper.ShouldSleep(time, goToSleep, wakeUp)) + { DoLog(LogLevel.Warning, "Unable to send discovery fleet: bed time has passed"); stop = true; return; @@ -102,13 +107,13 @@ protected override async Task Execute() { } List possibleDestinations = new(); - for (int i = 1; i <= _tbotInstance.UserData.serverData.Systems; i++) { - for (int j = 1; j <= 15; j++) { - possibleDestinations.Add(new Coordinate() { - Galaxy = origin.Coordinate.Galaxy, - System = i, - Position = j - }); + int discoveries = await _ogameService.GetAvailableDiscoveries(origin); + if (discoveries > 0) + { + for (int i = 1; i <= _tbotInstance.UserData.serverData.Systems; i++) + { + var newDestinations = await _ogameService.GetPositionsAvailableForDiscoveryFleet(origin, new Coordinate() { Galaxy = origin.Coordinate.Galaxy, System = i, Position = 1 }); + possibleDestinations.AddRange(newDestinations); } } possibleDestinations = possibleDestinations @@ -118,88 +123,95 @@ protected override async Task Execute() { .OrderBy(c => _calculationService.CalcDistance(origin.Coordinate, c, _tbotInstance.UserData.serverData)) .ToList(); - while (possibleDestinations.Count > 0 && _tbotInstance.UserData.fleets.Where(s => s.Mission == Missions.Discovery).Count() < MaxSlots && _tbotInstance.UserData.slots.Free > (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + while (possibleDestinations.Count > 0 && _tbotInstance.UserData.fleets.Where(s => s.Mission == Missions.Discovery).Count() < MaxSlots && _tbotInstance.UserData.slots.Free > (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree) + { Coordinate dest = possibleDestinations.First(); possibleDestinations.Remove(dest); Coordinate blacklistedCoord = _tbotInstance.UserData.discoveryBlackList.Keys - .Where(c => c.Galaxy == dest.Galaxy) - .Where(c => c.System == dest.System) - .Where(c => c.Position == dest.Position) - .SingleOrDefault() ?? null; - if (blacklistedCoord != null) { - if (_tbotInstance.UserData.discoveryBlackList.Single(d => d.Key.Galaxy == dest.Galaxy && d.Key.System == dest.System && d.Key.Position == dest.Position).Value > DateTime.Now) { - //DoLog(LogLevel.Information, $"Skipping {dest.ToString()} because it's blacklisted until {_tbotInstance.UserData.discoveryBlackList[blacklistedCoord].ToString()}"); + .Where(c => c.Galaxy == dest.Galaxy && c.System == dest.System && c.Position == dest.Position) + .SingleOrDefault(); + + if (blacklistedCoord != null) + { + if (_tbotInstance.UserData.discoveryBlackList[blacklistedCoord] > DateTime.Now) + { skips++; - if (skips >= _tbotInstance.UserData.serverData.Systems * 15) { - DoLog(LogLevel.Information, $"Galaxy depleted: stopping"); - stop = true; - break; - } else { - continue; - } - } else { + continue; + } + else + { _tbotInstance.UserData.discoveryBlackList.Remove(blacklistedCoord); } } - origin = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Resources); - if (!origin.Resources.IsEnoughFor(new Resources { Metal = 5000, Crystal = 1000, Deuterium = 500 })) { - DoLog(LogLevel.Warning, $"Failed to send discovery fleet from {origin.ToString()}: not enough resources."); - return; - } - var result = await _ogameService.SendDiscovery(origin, dest); - if (!result) { - failures++; + if (!result) + { DoLog(LogLevel.Warning, $"Failed to send discovery fleet to {dest.ToString()} from {origin.ToString()}."); _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(1)); - } else { - DoLog(LogLevel.Information, $"Sent discovery fleet to {dest.ToString()} from {origin.ToString()}."); + } + else + { + DoLog(LogLevel.Information, $"Discovery fleet sent to {dest.ToString()} from {origin.ToString()}."); _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(7)); - } - - if (failures >= (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxFailures) { - DoLog(LogLevel.Warning, $"Max failures reached"); - break; } - + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - if (_tbotInstance.UserData.slots.Free <= _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, $"AutoDiscoveryWorker: No slots left, dealying"); - delay = true; + if (_tbotInstance.UserData.slots.Free <= _tbotInstance.InstanceSettings.General.SlotsToLeaveFree || _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery) >= MaxSlots) + { + long interval = 0; + if (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Any()) + { + interval = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Max(f => f.BackIn) ?? 0) * 1000; + } + + if (interval <= 0) + { + interval = Random.Shared.Next((int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax) * 1000; + } + + DoLog(LogLevel.Information, $"No more fleet slots available or max discovery fleets sent. Delaying for {TimeSpan.FromMilliseconds(interval).TotalSeconds}s."); + await Task.Delay((int)interval); break; } + await Task.Delay(Random.Shared.Next((int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax) * 1000); + } + if (skips > 0) + { + DoLog(LogLevel.Information, $"{skips} systems skipped (blacklisted)"); + } + if (possibleDestinations.Count == 0) + { + DoLog(LogLevel.Information, "No more systems to discover: stopping for now."); + stop = true; } } - else { + else + { + DoLog(LogLevel.Information, "Skipping: Sleep Mode is active."); stop = true; } - } catch (Exception ex) { - DoLog(LogLevel.Error, "AutoDiscovery exception"); - DoLog(LogLevel.Warning, ex.ToString()); } - finally { - if (stop) { - DoLog(LogLevel.Information, $"Stopping feature."); - await EndExecution(); - } else { - long interval = 0; - if (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Count() > 0) - interval = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - - if (delay) { - DoLog(LogLevel.Information, $"Delaying..."); - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - interval = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - } - if (interval <= 0) - interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - var time = await _tbotOgameBridge.GetDateTime(); - var newTime = time.AddMilliseconds(interval); - ChangeWorkerPeriod(interval); - DoLog(LogLevel.Information, $"Next AutoDiscovery check at {newTime.ToString()}"); + catch (Exception e) + { + DoLog(LogLevel.Error, $"AutoDiscovery Exception: {e.Message}"); + DoLog(LogLevel.Warning, $"Stacktrace: {e.StackTrace}"); + } + finally + { + if (stop) + { + DoLog(LogLevel.Information, "Stopping AutoDiscovery."); + await _tbotInstance.StopFeature(GetFeature()); + } + + else + { + var time = Random.Shared.Next((int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax); + DoLog(LogLevel.Information, $"Next AutoDiscovery check in {time}s."); + await Task.Delay(time * 1000); } await _tbotOgameBridge.CheckCelestials(); } diff --git a/TBot/Workers/ColonizeWorker.cs b/TBot/Workers/ColonizeWorker.cs index 65cceab5..57b4bc37 100644 --- a/TBot/Workers/ColonizeWorker.cs +++ b/TBot/Workers/ColonizeWorker.cs @@ -49,10 +49,9 @@ public override LogSender GetLogSender() { return LogSender.Colonize; } - protected override async Task Execute() { + protected override async Task Execute() { await _tbotOgameBridge.CheckCelestials(); bool stop = false; - bool delay = false; Fields fieldsSettings = new() { Total = (int) _tbotInstance.InstanceSettings.AutoColonize.Abandon.MinFields }; @@ -257,7 +256,14 @@ protected override async Task Execute() { return; } if (fleetId == (int) SendFleetCode.NotEnoughSlots) { - delay = true; + long delayInterval = 0; + try { + delayInterval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + } catch { + delayInterval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoColonize.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoColonize.CheckIntervalMax); + } + _tbotInstance.log(LogLevel.Information, LogSender.Colonize, $"Not enough fleet slots available. Delaying for {TimeSpan.FromMilliseconds(delayInterval).TotalSeconds}s."); + await Task.Delay((int)delayInterval); return; } var minWaitNextFleet = (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MinWaitNextFleet; @@ -355,20 +361,7 @@ protected override async Task Execute() { _tbotInstance.log(LogLevel.Information, LogSender.Colonize, $"Stopping feature."); await EndExecution(); } - if (delay) { - _tbotInstance.log(LogLevel.Information, LogSender.Colonize, $"Delaying..."); - var time = await _tbotOgameBridge.GetDateTime(); - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - long interval; - try { - interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - } catch { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoColonize.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoColonize.CheckIntervalMax); - } - var newTime = time.AddMilliseconds(interval); - ChangeWorkerPeriod(interval); - _tbotInstance.log(LogLevel.Information, LogSender.Colonize, $"Next check at {newTime}"); - } + await _tbotOgameBridge.CheckCelestials(); } } diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 980daf56..245ce8f7 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -511,11 +511,15 @@ public async Task SendFleet(Celestial origin, Ships ships, Coordinate desti payload.Deuterium = 0; if (payload.Food < 0) payload.Food = 0; - Fleet fleet = await _ogameService.SendFleet(origin, ships, destination, mission, speed, payload); - _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, "Fleet succesfully sent"); - _tbotInstance.UserData.fleets = await _ogameService.GetFleets(); + Fleet newFleet = await _ogameService.SendFleet(origin, ships, destination, mission, speed, payload); + if (newFleet == null) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Unable to send fleet from {origin.Coordinate.ToString()}: no ships to send."); + return (int) SendFleetCode.GenericError; + } + _tbotInstance.UserData.fleets.Add(newFleet); + _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, "Fleet sent successfully!"); _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - return fleet.ID; + return newFleet.ID; } catch (Exception e) { _tbotInstance.log(LogLevel.Error, LogSender.FleetScheduler, $"Unable to send fleet: an exception has occurred: {e.Message}"); _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Stacktrace: {e.StackTrace}"); From 9df2885d6379f289d17037cb745b66e49bc429a7 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sat, 26 Jul 2025 08:23:37 +0200 Subject: [PATCH 092/117] v3.3.1 --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 2001b84d..2e31257f 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.3.0 + 3.3.1 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.3.0 - 3.3.0 + 3.3.1 + 3.3.1 OGame Bot False ELK-Lab.pfx From 5ab659b30dc3c76d6bec9dac766a366768135780 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Tue, 5 Aug 2025 18:59:11 +0200 Subject: [PATCH 093/117] * small fixes --- TBot/Workers/AutoDiscoveryWorker.cs | 2 +- TBot/Workers/TBotOgamedBridge.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index a28ceaa4..50438059 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -174,7 +174,7 @@ protected override async Task Execute() { DoLog(LogLevel.Information, $"No more fleet slots available or max discovery fleets sent. Delaying for {TimeSpan.FromMilliseconds(interval).TotalSeconds}s."); await Task.Delay((int)interval); - break; + // break; // https://discord.com/channels/801453618770214923/919312220637249537/1402221089588903968 } await Task.Delay(Random.Shared.Next((int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax) * 1000); } diff --git a/TBot/Workers/TBotOgamedBridge.cs b/TBot/Workers/TBotOgamedBridge.cs index 7798c252..25c23fe3 100644 --- a/TBot/Workers/TBotOgamedBridge.cs +++ b/TBot/Workers/TBotOgamedBridge.cs @@ -130,7 +130,7 @@ public async Task UpdatePlanet(Celestial planet, UpdateTypes UpdateTy public async Task> UpdatePlanets(UpdateTypes UpdateTypes = UpdateTypes.Full) { // log(LogLevel.Information, LogSender.Tbot, $"Updating userData.celestials... Mode: {UpdateTypes.ToString()}"); - List localPlanets = await GetPlanets(); + List localPlanets = (await GetPlanets()).ToList(); List newPlanets = new(); try { foreach (Celestial planet in localPlanets) { @@ -239,7 +239,7 @@ public async Task UpdateUserInfo() { public async Task> UpdateCelestials() { try { - return await _ogameService.GetCelestials(); + return (await _ogameService.GetCelestials()).ToList(); } catch (Exception e) { _tbotInstance.log(LogLevel.Debug, LogSender.Tbot, $"UpdateCelestials() Exception: {e.Message}"); _tbotInstance.log(LogLevel.Warning, LogSender.Tbot, $"Stacktrace: {e.StackTrace}"); From c444f1f4a17edc66840530e0c09428cb9f6470f8 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Tue, 5 Aug 2025 19:00:12 +0200 Subject: [PATCH 094/117] v3.3.2 * minor fixes DiscoveryWorker * minor fixes OGameBridge --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 2e31257f..e9b97d4d 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.3.1 + 3.3.2 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.3.1 - 3.3.1 + 3.3.2 + 3.3.2 OGame Bot False ELK-Lab.pfx From 3723f67b00d1633cae931fe99f404c5d2fc9e626 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Fri, 22 Aug 2025 21:59:58 +0200 Subject: [PATCH 095/117] add Brain.AutoDefence feature, and some update --- TBot.Common/Logging/LogSender.cs | 1 + .../Logging/Sinks/TBotColoredConsoleSink.cs | 1 + TBot.Ogame.Infrastructure/Enums/Feature.cs | 1 + TBot.Ogame.Infrastructure/Enums/Features.cs | 1 + TBot.Ogame.Infrastructure/Models/Defences.cs | 178 +++++++++++- .../Models/LFBonusesBase.cs | 6 +- .../Models/LFBonusesCrawlers.cs | 8 +- .../Models/LFBonusesDens.cs | 8 +- .../Models/LFBonusesExpeditions.cs | 16 +- .../Models/LFBonusesMoons.cs | 8 +- .../Models/LFBonusesProduction.cs | 14 +- .../Models/LFBonusesShip.cs | 16 +- .../Models/LFBuildings.cs | 52 ++++ TBot.Ogame.Infrastructure/Models/LFTechs.cs | 75 +++++ .../Models/RankSlotsPriority.cs | 6 +- TBot/Includes/CalculationService.cs | 120 ++++---- TBot/Includes/ICalculationService.cs | 1 + TBot/Services/TBotMain.cs | 1 + TBot/Workers/AutoDiscoveryWorker.cs | 269 ++++++++---------- TBot/Workers/AutoFarmWorker.cs | 18 +- TBot/Workers/Brain/AutoDefenceWorker.cs | 157 ++++++++++ TBot/Workers/Brain/AutoMineCelestialWorker.cs | 22 +- TBot/Workers/Brain/AutoResearchWorker.cs | 18 +- .../Brain/LifeformsAutoMineCelestialWorker.cs | 18 +- .../LifeformsAutoResearchCelestialWorker.cs | 18 +- TBot/Workers/ColonizeWorker.cs | 18 +- TBot/Workers/ExpeditionsWorker.cs | 18 +- TBot/Workers/HarvestWorker.cs | 18 +- TBot/Workers/WorkerFactory.cs | 2 + TBot/instance_settings.json | 46 +-- 30 files changed, 816 insertions(+), 319 deletions(-) create mode 100644 TBot/Workers/Brain/AutoDefenceWorker.cs diff --git a/TBot.Common/Logging/LogSender.cs b/TBot.Common/Logging/LogSender.cs index 2c0592e0..5683270f 100644 --- a/TBot.Common/Logging/LogSender.cs +++ b/TBot.Common/Logging/LogSender.cs @@ -13,6 +13,7 @@ public enum LogSender { Brain, //Brain Features AutoCargo, + AutoDefence, AutoMine, AutoRepatriate, AutoResearch, diff --git a/TBot.Common/Logging/Sinks/TBotColoredConsoleSink.cs b/TBot.Common/Logging/Sinks/TBotColoredConsoleSink.cs index 80dfe81a..aa47dc65 100644 --- a/TBot.Common/Logging/Sinks/TBotColoredConsoleSink.cs +++ b/TBot.Common/Logging/Sinks/TBotColoredConsoleSink.cs @@ -37,6 +37,7 @@ public void Emit(LogEvent logEvent) { ConsoleColor consoleColor = sender switch { LogSender.Brain => ConsoleColor.Blue, LogSender.AutoCargo => ConsoleColor.Blue, + LogSender.AutoDefence => ConsoleColor.Blue, LogSender.AutoMine => ConsoleColor.Blue, LogSender.AutoRepatriate => ConsoleColor.Blue, LogSender.AutoResearch => ConsoleColor.Blue, diff --git a/TBot.Ogame.Infrastructure/Enums/Feature.cs b/TBot.Ogame.Infrastructure/Enums/Feature.cs index d9fdd956..555fd575 100644 --- a/TBot.Ogame.Infrastructure/Enums/Feature.cs +++ b/TBot.Ogame.Infrastructure/Enums/Feature.cs @@ -21,6 +21,7 @@ public enum Feature { BrainLifeformAutoMine = 12, BrainLifeformAutoResearch = 13, AutoDiscovery = 14, + BrainAutobuildDefence = 15, BrainCelestialAutoMine = 101, BrainCelestialLifeformAutoMine = 102, diff --git a/TBot.Ogame.Infrastructure/Enums/Features.cs b/TBot.Ogame.Infrastructure/Enums/Features.cs index 32f220ba..5d7dc956 100644 --- a/TBot.Ogame.Infrastructure/Enums/Features.cs +++ b/TBot.Ogame.Infrastructure/Enums/Features.cs @@ -9,6 +9,7 @@ public static class Features { public static readonly List AllFeatures = new List() { Feature.Defender, Feature.BrainAutobuildCargo, + Feature.BrainAutobuildDefence, Feature.BrainAutoRepatriate, Feature.BrainAutoMine, Feature.BrainLifeformAutoMine, diff --git a/TBot.Ogame.Infrastructure/Models/Defences.cs b/TBot.Ogame.Infrastructure/Models/Defences.cs index 926cca06..55823f5a 100644 --- a/TBot.Ogame.Infrastructure/Models/Defences.cs +++ b/TBot.Ogame.Infrastructure/Models/Defences.cs @@ -19,15 +19,179 @@ public class Defences { public long AntiBallisticMissiles { get; set; } public long InterplanetaryMissiles { get; set; } - public int GetAmount(Buildables defence) { - int output = 0; - foreach (PropertyInfo prop in GetType().GetProperties()) { - if (prop.Name == defence.ToString()) { - output = (int) prop.GetValue(this); + public Defences( + long rocketlauncher = 0, + long lightlaser = 0, + long heavylaser = 0, + long gausscannon = 0, + long ioncannon = 0, + long plasmaturret = 0, + long smallshielddome = 0, + long largeshielddome = 0, + long antiballisticmissiles = 0, + long interplanetarymissiles = 0 + ) { + RocketLauncher = rocketlauncher; + LightLaser = lightlaser; + HeavyLaser = heavylaser; + GaussCannon = gausscannon; + IonCannon = ioncannon; + PlasmaTurret = plasmaturret; + SmallShieldDome = smallshielddome; + LargeShieldDome = largeshielddome; + AntiBallisticMissiles = antiballisticmissiles; + InterplanetaryMissiles = interplanetarymissiles; + } + public bool IsEmpty() { + return RocketLauncher == 0 + && LightLaser == 0 + && HeavyLaser == 0 + && GaussCannon == 0 + && IonCannon == 0 + && PlasmaTurret == 0 + && SmallShieldDome == 0 + && LargeShieldDome == 0 + && AntiBallisticMissiles == 0 + && InterplanetaryMissiles == 0; + } + public long GetDefencePoints() { + long output = 0; + output += RocketLauncher * 20; + output += LightLaser * 20; + output += HeavyLaser * 80; + output += GaussCannon * 370; + output += IonCannon * 80; + output += PlasmaTurret * 1300; + output += SmallShieldDome * 200; + output += LargeShieldDome * 1000; + output += AntiBallisticMissiles * 100; + output += InterplanetaryMissiles * 245; + return output / 10; + } + public Resources GetDefenceCost() { + Resources output = new(); + output.Metal = RocketLauncher * 2000 + LightLaser * 1500 + HeavyLaser * 6000 + GaussCannon * 20000 + IonCannon * 3000 + PlasmaTurret * 50000 + SmallShieldDome * 10000 + LargeShieldDome * 50000 + AntiBallisticMissiles * 2000 + InterplanetaryMissiles * 5000; + output.Crystal = RocketLauncher * 1000 + LightLaser * 500 + HeavyLaser * 2000 + GaussCannon * 15000 + IonCannon * 1000 + PlasmaTurret * 50000 + SmallShieldDome * 5000 + LargeShieldDome * 25000 + AntiBallisticMissiles * 2000 + InterplanetaryMissiles * 2500; + output.Deuterium = RocketLauncher * 0 + LightLaser * 0 + HeavyLaser * 0 + GaussCannon * 0 + IonCannon * 0 + PlasmaTurret * 2000 + SmallShieldDome * 0 + LargeShieldDome * 10000 + AntiBallisticMissiles * 0 + InterplanetaryMissiles * 1000; + return output; + } + public Defences Add(String buildable, long quantity) { + foreach (PropertyInfo prop in this.GetType().GetProperties()) { + if (prop.Name == buildable) { + prop.SetValue(this, (long) prop.GetValue(this) + quantity); + } + } + return this; + } + + public Defences Remove(String buildable, int quantity) { + foreach (PropertyInfo prop in this.GetType().GetProperties()) { + if (prop.Name == buildable) { + long val = (long) prop.GetValue(this); + if (val >= quantity) + prop.SetValue(this, val); + else + prop.SetValue(this, 0); + } + } + return this; + } + + public long GetAmount(Defences buildable) { + foreach (PropertyInfo prop in this.GetType().GetProperties()) { + if (prop.Name == buildable.ToString()) { + return (long) prop.GetValue(this); + } + } + return 0; + } + + public void SetAmount(Defences buildable, long number) { + foreach (PropertyInfo prop in this.GetType().GetProperties()) { + if (prop.Name == buildable.ToString()) { + prop.SetValue(this, number); + return; } } + } + + public bool HasAtLeast(Defences defences, long times = 1) { + foreach (PropertyInfo prop in this.GetType().GetProperties()) { + if ((long) prop.GetValue(this) * times < (long) prop.GetValue(defences)) { + return false; + } + } + return true; + } + + public override string ToString() { + string output = ""; + foreach (PropertyInfo prop in this.GetType().GetProperties()) { + if ((long) prop.GetValue(this) == 0) + continue; + output += $"{prop.Name}: {prop.GetValue(this)}; "; + } return output; } - } + public Defences Sum(Defences defencesToSum) { + Defences output = new(); + output.RocketLauncher = RocketLauncher + defencesToSum.RocketLauncher; + output.LightLaser = LightLaser + defencesToSum.LightLaser; + output.HeavyLaser = HeavyLaser + defencesToSum.HeavyLaser; + output.GaussCannon = GaussCannon + defencesToSum.GaussCannon; + output.IonCannon = IonCannon + defencesToSum.IonCannon; + output.PlasmaTurret = PlasmaTurret + defencesToSum.PlasmaTurret; + output.SmallShieldDome = SmallShieldDome + defencesToSum.SmallShieldDome; + output.LargeShieldDome = LargeShieldDome + defencesToSum.LargeShieldDome; + output.AntiBallisticMissiles = AntiBallisticMissiles + defencesToSum.AntiBallisticMissiles; + output.InterplanetaryMissiles = InterplanetaryMissiles + defencesToSum.InterplanetaryMissiles; -} + return output; + } + public Defences Difference(Defences defencesToSubtract) { + Defences output = new(); + output.RocketLauncher = RocketLauncher - defencesToSubtract.RocketLauncher; + if (output.RocketLauncher < 0) + output.RocketLauncher = 0; + output.LightLaser = LightLaser - defencesToSubtract.LightLaser; + if (output.LightLaser < 0) + output.LightLaser = 0; + output.HeavyLaser = HeavyLaser - defencesToSubtract.HeavyLaser; + if (output.HeavyLaser < 0) + output.HeavyLaser = 0; + output.GaussCannon = GaussCannon - defencesToSubtract.GaussCannon; + if (output.GaussCannon < 0) + output.GaussCannon = 0; + output.IonCannon = IonCannon - defencesToSubtract.IonCannon; + if (output.IonCannon < 0) + output.IonCannon = 0; + output.PlasmaTurret = PlasmaTurret - defencesToSubtract.PlasmaTurret; + if (output.PlasmaTurret < 0) + output.PlasmaTurret = 0; + output.SmallShieldDome = SmallShieldDome - defencesToSubtract.SmallShieldDome; + if (output.SmallShieldDome < 0) + output.SmallShieldDome = 0; + output.LargeShieldDome = LargeShieldDome - defencesToSubtract.LargeShieldDome; + if (output.LargeShieldDome < 0) + output.LargeShieldDome = 0; + output.AntiBallisticMissiles = AntiBallisticMissiles - defencesToSubtract.AntiBallisticMissiles; + if (output.AntiBallisticMissiles < 0) + output.AntiBallisticMissiles = 0; + output.InterplanetaryMissiles = InterplanetaryMissiles - defencesToSubtract.InterplanetaryMissiles; + if (output.InterplanetaryMissiles < 0) + output.InterplanetaryMissiles = 0; + + return output; + } + public Dictionary GetDefenceTypesWithAmount() { + Dictionary defenceTypes = new(); + foreach (var prop in this.GetType().GetProperties()) { + Buildables buildable = (Buildables) Enum.Parse(typeof(Buildables), prop.Name); + long amount = (long) prop.GetValue(this); + if (amount > 0) + defenceTypes.Add(buildable, amount); + } + return defenceTypes; + } + } +} \ No newline at end of file diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesBase.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesBase.cs index 8cb9e220..229c92f0 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBonusesBase.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesBase.cs @@ -9,9 +9,9 @@ public class LFBonusesBase { public float Cost { get; set; } public float Duration { get; set; } - public LFBonusesBase() { - Cost = 0; - Duration = 0; + public LFBonusesBase(float cost = 0, float duration = 0) { + Cost = cost; + Duration = duration; } } } diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesCrawlers.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesCrawlers.cs index 3d97aa6d..3dc5987c 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBonusesCrawlers.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesCrawlers.cs @@ -10,10 +10,10 @@ public class LFBonusesCrawlers { public float Production { get; set; } public float Number { get; set; } - public LFBonusesCrawlers() { - EnergyReduction = 0; - Production = 0; - Number = 0; + public LFBonusesCrawlers(float energyReduction = 0, float production = 0, float number = 0) { + EnergyReduction = energyReduction; + Production = production; + Number = number; } } } diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesDens.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesDens.cs index e9155fd2..351c843d 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBonusesDens.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesDens.cs @@ -10,10 +10,10 @@ public class LFBonusesDens { public float Crystal { get; set; } public float Deuterium { get; set; } - public LFBonusesDens() { - Metal = 0; - Crystal = 0; - Deuterium = 0; + public LFBonusesDens(float metal = 0, float crystal = 0, float deuterium = 0) { + Metal = metal; + Crystal = crystal; + Deuterium = deuterium; } } } diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesExpeditions.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesExpeditions.cs index 40a44d95..e2f4cbe8 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBonusesExpeditions.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesExpeditions.cs @@ -14,14 +14,14 @@ public class LFBonusesExpeditions { public float Slots { get; set; } public float LessEnemies {get; set;} - public LFBonusesExpeditions() { - Ships = 0; - Resources = 0; - Speed = 0; - DarkMatter = 0; - FleetLoss = 0; - Slots = 0; - LessEnemies = 0; + public LFBonusesExpeditions(float ships = 0, float resources = 0, float speed = 0, float darkmatter = 0, float fleetloss = 0, float slots = 0, float lessenemies = 0) { + Ships = ships; + Resources = resources; + Speed = speed; + DarkMatter = darkmatter; + FleetLoss = fleetloss; + Slots = slots; + LessEnemies = lessenemies; } } } diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesMoons.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesMoons.cs index 9cb7d919..42e00f1b 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBonusesMoons.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesMoons.cs @@ -10,10 +10,10 @@ public class LFBonusesMoons { public float Size { get; set; } public float Chance { get; set; } - public LFBonusesMoons() { - Fields = 0; - Size = 0; - Chance = 0; + public LFBonusesMoons(float fields = 0, float size = 0, float chance = 0) { + Fields = fields; + Size = size; + Chance = chance; } } } diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesProduction.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesProduction.cs index 992dbf1e..3461e0de 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBonusesProduction.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesProduction.cs @@ -13,13 +13,13 @@ public class LFBonusesProduction { public float Food { get; set; } public float Population { get; set; } - public LFBonusesProduction() { - Metal = 0; - Crystal = 0; - Deuterium = 0; - Energy = 0; - Food = 0; - Population = 0; + public LFBonusesProduction(float metal = 0, float crystal = 0, float deuterium = 0, float energy = 0, float food = 0, float population = 0) { + Metal = metal; + Crystal = crystal; + Deuterium = deuterium; + Energy = energy; + Food = food; + Population = population; } } } diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesShip.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesShip.cs index 25bd6a48..f66f2a27 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBonusesShip.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesShip.cs @@ -14,14 +14,14 @@ public class LFBonusesShip { public float Consumption { get; set; } public float Duration { get; set; } - public LFBonusesShip() { - Armour = 0; - Shield = 0; - Weapon = 0; - Cargo = 0; - Speed = 0; - Consumption = 0; - Duration = 0; + public LFBonusesShip(float armour = 0, float shield = 0, float weapon = 0, float cargo = 0, float speed = 0, float consumption = 0, float duration = 0) { + Armour = armour; + Shield = shield; + Weapon = weapon; + Cargo = cargo; + Speed = speed; + Consumption = consumption; + Duration = duration; } } } diff --git a/TBot.Ogame.Infrastructure/Models/LFBuildings.cs b/TBot.Ogame.Infrastructure/Models/LFBuildings.cs index 01368af3..e4c03c6d 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBuildings.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBuildings.cs @@ -66,6 +66,58 @@ public class LFBuildings { public int ShipManufacturingHall { get; set; } public int SupraRefractor { get; set; } + public LFBuildings(int lifeformType = 0, int residentialsector = 0, int biospherefarm = 0, int researchcentre = 0, int academyofsciences = 0, int neurocalibrationcentre = 0, int highenergysmelting = 0, int foodsilo = 0, int fusionpoweredproduction = 0, int skyscraper = 0, int biotechlab = 0, int metropolis = 0, int planetaryshield = 0, int meditationenclave = 0, int crystalfarm = 0, int runetechnologium = 0, int runeforge = 0, int oriktorium = 0, int magmaforge = 0, int disruptionchamber = 0, int megalith = 0, int crystalrefinery = 0, int deuteriumsynthesiser = 0, int mineralresearchcentre = 0, int advancedrecyclingplant = 0, int assemblyline = 0, int fusioncellfactory = 0, int roboticsresearchcentre = 0, int updatenetwork = 0, int quantumcomputercentre = 0, int automatisedassemblycentre = 0, int highperformancetransformer = 0, int microchipassemblyline = 0, int productionassemblyhall = 0, int highperformancesynthesiser = 0, int chipmassproduction = 0, int nanorepairbots = 0, int sanctuary = 0, int antimattercondenser = 0, int vortexchamber = 0, int hallsofrealisation = 0, int forumoftranscendence = 0, int antimatterconvector = 0, int cloninglaboratory = 0, int chrysalisaccelerator = 0, int biomodifier = 0, int psionicmodulator = 0, int shipmanufacturinghall = 0, int suprarefractor = 0) { + LifeformType = lifeformType; + ResidentialSector = residentialsector; + BiosphereFarm = biospherefarm; + ResearchCentre = researchcentre; + AcademyOfSciences = academyofsciences; + NeuroCalibrationCentre = neurocalibrationcentre; + HighEnergySmelting = highenergysmelting; + FoodSilo = foodsilo; + FusionPoweredProduction = fusionpoweredproduction; + Skyscraper = skyscraper; + BiotechLab = biotechlab; + Metropolis = metropolis; + PlanetaryShield = planetaryshield; + MeditationEnclave = meditationenclave; + CrystalFarm = crystalfarm; + RuneTechnologium = runetechnologium; + RuneForge = runeforge; + Oriktorium = oriktorium; + MagmaForge = magmaforge; + DisruptionChamber = disruptionchamber; + Megalith = megalith; + CrystalRefinery = crystalrefinery; + DeuteriumSynthesiser = deuteriumsynthesiser; + MineralResearchCentre = mineralresearchcentre; + AdvancedRecyclingPlant = advancedrecyclingplant; + AssemblyLine = assemblyline; + FusionCellFactory = fusioncellfactory; + RoboticsResearchCentre = roboticsresearchcentre; + UpdateNetwork = updatenetwork; + QuantumComputerCentre = quantumcomputercentre; + AutomatisedAssemblyCentre = automatisedassemblycentre; + HighPerformanceTransformer = highperformancetransformer; + MicrochipAssemblyLine = microchipassemblyline; + ProductionAssemblyHall = productionassemblyhall; + HighPerformanceSynthesiser = highperformancesynthesiser; + ChipMassProduction = chipmassproduction; + NanoRepairBots = nanorepairbots; + Sanctuary = sanctuary; + AntimatterCondenser = antimattercondenser; + VortexChamber = vortexchamber; + HallsOfRealisation = hallsofrealisation; + ForumOfTranscendence = forumoftranscendence; + AntimatterConvector = antimatterconvector; + CloningLaboratory = cloninglaboratory; + ChrysalisAccelerator = chrysalisaccelerator; + BioModifier = biomodifier; + PsionicModulator = psionicmodulator; + ShipManufacturingHall = shipmanufacturinghall; + SupraRefractor = suprarefractor; + } + public int GetLevel(LFBuildables building) { int output = 0; foreach (PropertyInfo prop in GetType().GetProperties()) { diff --git a/TBot.Ogame.Infrastructure/Models/LFTechs.cs b/TBot.Ogame.Infrastructure/Models/LFTechs.cs index 7fa22278..c2cf47bf 100644 --- a/TBot.Ogame.Infrastructure/Models/LFTechs.cs +++ b/TBot.Ogame.Infrastructure/Models/LFTechs.cs @@ -89,6 +89,81 @@ public class LFTechs { public int? PsionicShieldMatrix { get; set; } public int? KaeleshDiscovererEnhancement { get; set; } + public LFTechs(int? intergalacticenvoys = null, int? highperformanceextractors = null, int? fusiondrives = null, int? stealthfieldgenerator = null, int? orbitalden = null, int? researchai = null, int? highperformanceterraformer = null, int? enhancedproductiontechnologies = null, int? lightfightermkii = null, int? cruisermkii = null, int? improvedlabtechnology = null, int? plasmaterraformer = null, int? lowtemperaturedrives = null, int? bombermkii = null, int? destroyermkii = null, int? battlecruisermkii = null, int? robotassistants = null, int? supercomputer = null, int? volcanicbatteries = null, int? acousticscanning = null, int? highenergypumpsystems = null, int? cargoholdexpansioncivilianships = null, int? magmapoweredproduction = null, int? geothermalpowerplants = null, int? depthsounding = null, int? ioncrystalenhancementheavyfighter = null, int? improvedstellarator = null, int? hardeneddiamonddrillheads = null, int? seismicminingtechnology = null, int? magmapoweredpumpsystems = null, int? ioncrystalmodules = null, int? optimisedsiloconstructionmethod = null, int? diamondenergytransmitter = null, int? obsidianshieldreinforcement = null, int? runeshields = null, int? rocktalcollectorenhancement = null, int? catalysertechnology = null, int? plasmadrive = null, int? efficiencymodule = null, int? depotai = null, int? generaloverhaullightfighter = null, int? automatedtransportlines = null, int? improveddroneai = null, int? experimentalrecyclingtechnology = null, int? generaloverhaulcruiser = null, int? slingshotautopilot = null, int? hightemperaturesuperconductors = null, int? generaloverhaulbattleship = null, int? artificialswarmintelligence = null, int? generaloverhaulbattlecruiser = null, int? generaloverhaulbomber = null, int? generaloverhauldestroyer = null, int? experimentalweaponstechnology = null, int? mechangeneralenhancement = null, int? heatrecovery = null, int? sulphideprocess = null, int? psionicnetwork = null, int? telekinetictractorbeam = null, int? enhancedsensortechnology = null, int? neuromodalcompressor = null, int? neurointerface = null, int? interplanetaryanalysisnetwork = null, int? overclockingheavyfighter = null, int? telekineticdrive = null, int? sixthsense = null, int? psychoharmoniser = null, int? efficientswarmintelligence = null, int? overclockinglargecargo = null, int? gravitationsensors = null, int? overclockingbattleship = null, int? psionicshieldmatrix = null, int? kaeleshdiscovererenhancement = null) { + IntergalacticEnvoys = intergalacticenvoys ?? 0; + HighPerformanceExtractors = highperformanceextractors ?? 0; + FusionDrives = fusiondrives ?? 0; + StealthFieldGenerator = stealthfieldgenerator ?? 0; + OrbitalDen = orbitalden ?? 0; + ResearchAI = researchai ?? 0; + HighPerformanceTerraformer = highperformanceterraformer ?? 0; + EnhancedProductionTechnologies = enhancedproductiontechnologies ?? 0; + LightFighterMkII = lightfightermkii ?? 0; + CruiserMkII = cruisermkii ?? 0; + ImprovedLabTechnology = improvedlabtechnology ?? 0; + PlasmaTerraformer = plasmaterraformer ?? 0; + LowTemperatureDrives = lowtemperaturedrives ?? 0; + BomberMkII = bombermkii ?? 0; + DestroyerMkII = destroyermkii ?? 0; + BattlecruiserMkII = battlecruisermkii ?? 0; + RobotAssistants = robotassistants ?? 0; + Supercomputer = supercomputer ?? 0; + VolcanicBatteries = volcanicbatteries ?? 0; + AcousticScanning = acousticscanning ?? 0; + HighEnergyPumpSystems = highenergypumpsystems ?? 0; + CargoHoldExpansionCivilianShips = cargoholdexpansioncivilianships ?? 0; + MagmaPoweredProduction = magmapoweredproduction ?? 0; + GeothermalPowerPlants = geothermalpowerplants ?? 0; + DepthSounding = depthsounding ?? 0; + IonCrystalEnhancementHeavyFighter = ioncrystalenhancementheavyfighter ?? 0; + ImprovedStellarator = improvedstellarator ?? 0; + HardenedDiamondDrillHeads = hardeneddiamonddrillheads ?? 0; + SeismicMiningTechnology = seismicminingtechnology ?? 0; + MagmaPoweredPumpSystems = magmapoweredpumpsystems ?? 0; + IonCrystalModules = ioncrystalmodules ?? 0; + OptimisedSiloConstructionMethod = optimisedsiloconstructionmethod ?? 0; + DiamondEnergyTransmitter = diamondenergytransmitter ?? 0; + ObsidianShieldReinforcement = obsidianshieldreinforcement ?? 0; + RuneShields = runeshields ?? 0; + RocktalCollectorEnhancement = rocktalcollectorenhancement ?? 0; + CatalyserTechnology = catalysertechnology ?? 0; + PlasmaDrive = plasmadrive ?? 0; + EfficiencyModule = efficiencymodule ?? 0; + DepotAI = depotai ?? 0; + GeneralOverhaulLightFighter = generaloverhaullightfighter ?? 0; + AutomatedTransportLines = automatedtransportlines ?? 0; + ImprovedDroneAI = improveddroneai ?? 0; + ExperimentalRecyclingTechnology = experimentalrecyclingtechnology ?? 0; + GeneralOverhaulCruiser = generaloverhaulcruiser ?? 0; + SlingshotAutopilot = slingshotautopilot ?? 0; + HighTemperatureSuperconductors = hightemperaturesuperconductors ?? 0; + GeneralOverhaulBattleship = generaloverhaulbattleship ?? 0; + ArtificialSwarmIntelligence = artificialswarmintelligence ?? 0; + GeneralOverhaulBattlecruiser = generaloverhaulbattlecruiser ?? 0; + GeneralOverhaulBomber = generaloverhaulbomber ?? 0; + GeneralOverhaulDestroyer = generaloverhauldestroyer ?? 0; + ExperimentalWeaponsTechnology = experimentalweaponstechnology ?? 0; + MechanGeneralEnhancement = mechangeneralenhancement ?? 0; + HeatRecovery = heatrecovery ?? 0; + SulphideProcess = sulphideprocess ?? 0; + PsionicNetwork = psionicnetwork ?? 0; + TelekineticTractorBeam = telekinetictractorbeam ?? 0; + EnhancedSensorTechnology = enhancedsensortechnology ?? 0; + NeuromodalCompressor = neuromodalcompressor ?? 0; + NeuroInterface = neurointerface ?? 0; + InterplanetaryAnalysisNetwork = interplanetaryanalysisnetwork ?? 0; + OverclockingHeavyFighter = overclockingheavyfighter ?? 0; + TelekineticDrive = telekineticdrive ?? 0; + SixthSense = sixthsense ?? 0; + Psychoharmoniser = psychoharmoniser ?? 0; + EfficientSwarmIntelligence = efficientswarmintelligence ?? 0; + OverclockingLargeCargo = overclockinglargecargo ?? 0; + GravitationSensors = gravitationsensors ?? 0; + OverclockingBattleship = overclockingbattleship ?? 0; + PsionicShieldMatrix = psionicshieldmatrix ?? 0; + KaeleshDiscovererEnhancement = kaeleshdiscovererenhancement ?? 0; + } + public int GetLevel(LFTechno building) { int output = 0; foreach (PropertyInfo prop in GetType().GetProperties()) { diff --git a/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs b/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs index 1be10a91..4cadc455 100644 --- a/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs +++ b/TBot.Ogame.Infrastructure/Models/RankSlotsPriority.cs @@ -8,8 +8,8 @@ namespace TBot.Ogame.Infrastructure.Models { public class RankSlotsPriority { - public RankSlotsPriority(Feature feature = Feature.Null, int rank = int.MaxValue, bool active = false, int maxSlots = 0, int slotsUsed = 0) { - Rank = rank < 1 ? int.MaxValue : rank; + public RankSlotsPriority(Feature feature = Feature.Null, int rank = int.MinValue, bool active = false, int maxSlots = 0, int slotsUsed = 0) { + Rank = rank < 1 ? int.MinValue : (int) rank; Active = active; MaxSlots = maxSlots; SlotsUsed = slotsUsed; @@ -24,7 +24,7 @@ public bool HasPriorityOn(RankSlotsPriority feature) { return this.Rank < feature.Rank; } public override string ToString() { - return $"{Rank} -- {Feature.ToString()} is {Active}, using {SlotsUsed}/{MaxSlots}"; + return $"Rank {Rank} -- {Feature.ToString()} is {Active}, using {SlotsUsed}/{MaxSlots}"; } } diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index eb5f1b43..edbcc7b9 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -3029,6 +3029,29 @@ public long CalcMaxBuildableNumber(Buildables buildable, Resources resources) { return output; } + public Defences CalcmaxDefencesBuildable(Defences defences, Resources resources) { + Defences output = new(); + Dictionary defenceTypes = defences.GetDefenceTypesWithAmount(); + Resources resourcesLeft = resources; + + bool canBuild = true; + while (canBuild) { + canBuild = false; + foreach (var (defenceType, amountNeeded) in defenceTypes) { + if (amountNeeded <= 0) + continue; + Resources unitCost = CalcPrice(defenceType, 1); + if (resourcesLeft.IsEnoughFor(unitCost)) { + output.Add(defenceType.ToString(), 1); + resourcesLeft = resourcesLeft.Difference(unitCost); + defenceTypes[defenceType]--; + canBuild = true; + } + } + } + return output; + } + public long GetRequiredEnergyDelta(Buildables buildable, int level) { if (buildable == Buildables.MetalMine || buildable == Buildables.CrystalMine || buildable == Buildables.DeuteriumSynthesizer) { if (level > 1) { @@ -4841,11 +4864,9 @@ public bool IsThereMoonHere(List planets, Celestial celestial) { return moon.ID == 0 ? false: true; } - public int CalcSlotsPriority(Feature feature, List rankSlotsPriority, Slots slots, List fleets, int slotsToLeaveFree = 0) - { + public int CalcSlotsPriority(Feature feature, List rankSlotsPriority, Slots slots, List fleets, int slotsToLeaveFree = 0) { LogSender logsender; - switch (feature) - { + switch (feature) { case Feature.BrainAutoMine: logsender = LogSender.AutoMine; break; case Feature.BrainAutoResearch: logsender = LogSender.AutoResearch; break; case Feature.BrainLifeformAutoMine: logsender = LogSender.LifeformsAutoMine; break; @@ -4857,67 +4878,56 @@ public int CalcSlotsPriority(Feature feature, List rankSlotsP case Feature.Harvest: logsender = LogSender.Harvest; break; default: logsender = LogSender.FleetScheduler; break; } - - // Handle Expedition slots separately and first. - int expeditionSlotsTotal = slots.ExpTotal; - int expeditionSlotsInUse = fleets.Count(fleet => fleet.Mission == Missions.Expedition); - int expeditionSlotsFree = expeditionSlotsTotal - expeditionSlotsInUse; - - if (feature == Feature.Expeditions) - { - var expeditionFeature = rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.Expeditions); - int maxExpeditions = expeditionFeature?.MaxSlots ?? 0; - int availableForExpedition = Math.Min(expeditionSlotsFree, maxExpeditions - expeditionSlotsInUse); - _logger.WriteLog(LogLevel.Information, logsender, $"Expedition slots: {expeditionSlotsInUse}/{expeditionSlotsTotal} used. Can send {availableForExpedition} more."); - return Math.Max(0, availableForExpedition); // Ensure it doesn't return negative - } - - // Calculation for normal fleet slots - // Normal slots are total slots MINUS expedition slots. - int normalSlotsTotal = slots.Total - expeditionSlotsTotal; - - // Update slots used for each feature based on current fleets - rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.BrainAutoMine || f.Feature == Feature.BrainAutoResearch || f.Feature == Feature.BrainLifeformAutoMine || f.Feature == Feature.BrainLifeformAutoResearch).SlotsUsed = fleets.Count(fleet => fleet.Mission == Missions.Transport); - rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.AutoFarm).SlotsUsed = fleets.Count(fleet => fleet.Mission == Missions.Attack); - rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.Colonize).SlotsUsed = fleets.Count(fleet => fleet.Mission == Missions.Colonize); - rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.AutoDiscovery).SlotsUsed = fleets.Count(fleet => fleet.Mission == Missions.Discovery); - rankSlotsPriority.SingleOrDefault(f => f.Feature == Feature.Expeditions).SlotsUsed = expeditionSlotsInUse; // Keep this updated for other parts of the bot - - // Slots used by fleets not managed by an active feature (excluding expeditions) + RankSlotsPriority actualFeature = rankSlotsPriority.Single(f => f.Feature == feature); + int slotsAvailable = 0; + int reservedSlots = 0; + int usedSlots = 0; int otherSlots = fleets.Count(fleet => fleet.Mission != Missions.Transport && fleet.Mission != Missions.Expedition && - fleet.Mission != Missions.Attack && fleet.Mission != Missions.Spy && + fleet.Mission != Missions.Attack && fleet.Mission != Missions.Colonize && - fleet.Mission != Missions.Discovery); - - // Sum of slots currently in use by active features (excluding expeditions) - int usedSlotsByActiveFeatures = rankSlotsPriority.Where(f => f.Active && f.Feature != Feature.Expeditions).Sum(f => f.SlotsUsed); - - // Calculate available slots for normal fleets - int slotsAvailable = normalSlotsTotal - usedSlotsByActiveFeatures - otherSlots - slotsToLeaveFree; - - _logger.WriteLog(LogLevel.Information, logsender, $"Normal Slots: {normalSlotsTotal} total. Used by features: {usedSlotsByActiveFeatures}. Used by other: {otherSlots}. To leave free: {slotsToLeaveFree}. Available: {slotsAvailable}."); - - if (slotsAvailable <= 0) - { - _logger.WriteLog(LogLevel.Information, logsender, "No normal fleet slots available."); + fleet.Mission != Missions.Discovery && + fleet.Mission != Missions.Harvest); + + if (actualFeature.MaxSlots - actualFeature.SlotsUsed <= 0) { + _logger.WriteLog(LogLevel.Information, logsender, $"All slots for feature {feature} are already used ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots})."); return 0; } - // Check if the current feature can use the available slots - var actualFeature = rankSlotsPriority.SingleOrDefault(f => f.Feature == feature); - if (actualFeature != null && actualFeature.Active) - { - int canBeUsedByFeature = actualFeature.MaxSlots - actualFeature.SlotsUsed; - int result = Math.Min(slotsAvailable, canBeUsedByFeature); - _logger.WriteLog(LogLevel.Information, logsender, $"Feature {feature} can use up to {canBeUsedByFeature} slots. Granting: {result}"); - return Math.Max(0, result); + if (actualFeature.Rank > 0) { + reservedSlots = rankSlotsPriority.Where(fp => fp.Active) + .Where(fp => fp.Rank > 0) + .Where(fp => fp.Rank < actualFeature.Rank) + .Sum(fp => fp.MaxSlots); + usedSlots = rankSlotsPriority.Where(fp => fp.Active) + .Where(fp => fp.Rank > actualFeature.Rank) + .Sum(fp => fp.SlotsUsed); + otherSlots += rankSlotsPriority.Where(fp => !fp.Active) + .Sum(fp => fp.SlotsUsed); + slotsAvailable = slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots < 0 ? 0 : slots.Total - slotsToLeaveFree - reservedSlots - usedSlots - otherSlots; + } else { + slotsAvailable = slots.Free - slotsToLeaveFree < 0 ? 0 : slots.Free - slotsToLeaveFree; + } + if (slotsAvailable <= 0) { + _logger.WriteLog(LogLevel.Information, logsender, $"No slots available for feature {feature}. Slots available: {slotsAvailable}."); + return 0; + } else { + if (actualFeature.Rank > 0) { + _logger.WriteLog(LogLevel.Information, logsender, $"Slots Total: {slots.Total}, Reserved: {reservedSlots + slotsToLeaveFree}, Other: {usedSlots + otherSlots}. Available: {slotsAvailable}."); + if (slotsAvailable < actualFeature.MaxSlots) { + _logger.WriteLog(LogLevel.Information, logsender, $"Less slots available ({slotsAvailable}) than maximum usable slots ({actualFeature.MaxSlots}). Stepping down to usable slots."); + actualFeature.MaxSlots = slotsAvailable; + } + slotsAvailable = Math.Min(slotsAvailable, actualFeature.MaxSlots - actualFeature.SlotsUsed); + _logger.WriteLog(LogLevel.Information, logsender, $"{feature} will use {slotsAvailable} slots ({actualFeature.SlotsUsed}/{actualFeature.MaxSlots} already used)."); + } else { + _logger.WriteLog(LogLevel.Information, logsender, $"{feature} has no rank and can use all available slots: {slotsAvailable}."); + } } - // Default return for features not in priority list or inactive - return Math.Max(0, slotsAvailable); + return slotsAvailable; } public List> CalcMultipleOrigin(Celestial celestialToBuild, List allCelestials, Resources missingResources, TransportSettings transportSettings, List fleets, UserData userData) { diff --git a/TBot/Includes/ICalculationService.cs b/TBot/Includes/ICalculationService.cs index 070294e8..ab84d941 100644 --- a/TBot/Includes/ICalculationService.cs +++ b/TBot/Includes/ICalculationService.cs @@ -38,6 +38,7 @@ public interface ICalculationService { Ships CalcFullExpeditionShips(Ships fleet, Buildables primaryShip, int expeditionsNumber, ServerData serverdata, Researches researches, LFBonuses LFBonuses, CharacterClass playerClass = CharacterClass.NoClass, int probeCargo = 0); Ships CalcIdealExpeditionShips(Buildables buildable, int hyperspaceTech, float expeditionResourcesBonus, Dictionary shipsBonus, ServerData serverData, CharacterClass playerClass = CharacterClass.NoClass, int probeCargo = 0); long CalcMaxBuildableNumber(Buildables buildable, Resources resources); + Defences CalcmaxDefencesBuildable(Defences defences, Resources resources); int CalcMaxCrawlers(Planet planet, CharacterClass userClass, bool hasGeologist); int CalcMaxExpeditions(int astrophysics, bool isDiscoverer, bool hasAdmiral); int CalcMaxExpeditions(Researches researches, CharacterClass playerClass, Staff staff); diff --git a/TBot/Services/TBotMain.cs b/TBot/Services/TBotMain.cs index 2abb6ec7..4e5959fe 100644 --- a/TBot/Services/TBotMain.cs +++ b/TBot/Services/TBotMain.cs @@ -375,6 +375,7 @@ public async Task InitializeFeature(Feature feat) { long dueTime = feat switch { Feature.Defender => RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds), Feature.BrainAutobuildCargo => RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo), + Feature.BrainAutobuildDefence => RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo), Feature.BrainAutoRepatriate => RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds), Feature.BrainAutoMine => RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds), Feature.BrainLifeformAutoMine => RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds), diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index 50438059..df06f277 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -34,187 +34,158 @@ public AutoDiscoveryWorker(ITBotMain parentInstance, } protected override async Task Execute() { + bool delay = false; bool stop = false; int skips = 0; var rand = new Random(); - try - { - if (_tbotInstance.UserData.discoveryBlackList == null) - { + try { + DoLog(LogLevel.Information, $"Starting AutoDiscovery..."); + if (_tbotInstance.UserData.discoveryBlackList == null) { _tbotInstance.UserData.discoveryBlackList = new Dictionary(); } - if (!_tbotInstance.UserData.isSleeping) - { - DoLog(LogLevel.Information, $"Starting AutoDiscovery..."); + if (!_tbotInstance.UserData.isSleeping) { + if ((bool) _tbotInstance.InstanceSettings.SleepMode.Active) { + DateTime.TryParse((string) _tbotInstance.InstanceSettings.SleepMode.GoToSleep, out DateTime goToSleep); + DateTime.TryParse((string) _tbotInstance.InstanceSettings.SleepMode.WakeUp, out DateTime wakeUp); + DateTime timeSleep = await _tbotOgameBridge.GetDateTime(); + if (GeneralHelper.ShouldSleep(timeSleep, goToSleep, wakeUp)) { + DoLog(LogLevel.Warning, "Unable to send discovery fleet: bed time has passed"); + stop = true; + return; + } + } + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new() - { - new RankSlotsPriority(Feature.BrainAutoMine, - (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, - ((bool)_tbotInstance.InstanceSettings.Brain.Active && (bool)_tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool)_tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int)_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), - new RankSlotsPriority(Feature.Expeditions, - (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, - (bool)_tbotInstance.InstanceSettings.Expeditions.Active, - (int)_tbotInstance.UserData.slots.ExpTotal), - new RankSlotsPriority(Feature.AutoFarm, - (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, - (bool)_tbotInstance.InstanceSettings.AutoFarm.Active, - (int)_tbotInstance.InstanceSettings.AutoFarm.MaxSlots), - new RankSlotsPriority(Feature.Colonize, - (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, - (bool)_tbotInstance.InstanceSettings.AutoColonize.Active, - (bool)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1), - new RankSlotsPriority(Feature.AutoDiscovery, - (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, - (bool)_tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int)_tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), - new RankSlotsPriority(Feature.Harvest, - (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, - (bool)_tbotInstance.InstanceSettings.AutoHarvest.Active, - (int)_tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainAutoMine, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool)_tbotInstance.InstanceSettings.Brain.Active && (bool)_tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool)_tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), (int)_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), + new RankSlotsPriority(Feature.Expeditions, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool)_tbotInstance.InstanceSettings.Expeditions.Active, (int)_tbotInstance.UserData.slots.ExpTotal, (int)_tbotInstance.UserData.slots.ExpInUse), + new RankSlotsPriority(Feature.AutoFarm, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool)_tbotInstance.InstanceSettings.AutoFarm.Active, (int)_tbotInstance.InstanceSettings.AutoFarm.MaxSlots, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), + new RankSlotsPriority(Feature.Colonize, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool)_tbotInstance.InstanceSettings.AutoColonize.Active, (bool)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : 1, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), + new RankSlotsPriority(Feature.AutoDiscovery, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool)_tbotInstance.InstanceSettings.AutoDiscovery.Active, (int)_tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), + new RankSlotsPriority(Feature.Harvest, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool)_tbotInstance.InstanceSettings.AutoHarvest.Active, (int)_tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; - int MaxSlots = _calculationService.CalcSlotsPriority(Feature.AutoDiscovery, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree); + int fleetsToSend = _calculationService.CalcSlotsPriority(Feature.AutoDiscovery, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); + + if (fleetsToSend <= 0) { + delay = true; + return; + } - Celestial origin = _tbotInstance.UserData.celestials - .Unique() - .Where(c => c.Coordinate.Galaxy == (int)_tbotInstance.InstanceSettings.AutoDiscovery.Origin.Galaxy) - .Where(c => c.Coordinate.System == (int)_tbotInstance.InstanceSettings.AutoDiscovery.Origin.System) - .Where(c => c.Coordinate.Position == (int)_tbotInstance.InstanceSettings.AutoDiscovery.Origin.Position) - .Where(c => c.Coordinate.Type == Enum.Parse((string)_tbotInstance.InstanceSettings.AutoDiscovery.Origin.Type)) - .SingleOrDefault() ?? new() { ID = 0 }; - if (origin.ID == 0) - { + var celestials = await _ogameService.GetCelestials(); + var configureddestinationCoord = _tbotInstance.InstanceSettings.AutoDiscovery.Origin; + Celestial origin = celestials.FirstOrDefault(c => c.Coordinate.Galaxy == configureddestinationCoord.Galaxy && + c.Coordinate.System == configureddestinationCoord.System && + c.Coordinate.Position == configureddestinationCoord.Position && + c.Coordinate.Type.ToString().Equals(configureddestinationCoord.Type, StringComparison.OrdinalIgnoreCase)); + + if (origin == null) { stop = true; DoLog(LogLevel.Warning, "Unable to parse AutoDiscovery origin"); return; } - if ((bool)_tbotInstance.InstanceSettings.SleepMode.Active) - { - DateTime.TryParse((string)_tbotInstance.InstanceSettings.SleepMode.GoToSleep, out DateTime goToSleep); - DateTime.TryParse((string)_tbotInstance.InstanceSettings.SleepMode.WakeUp, out DateTime wakeUp); - DateTime time = await _tbotOgameBridge.GetDateTime(); - if (GeneralHelper.ShouldSleep(time, goToSleep, wakeUp)) - { - DoLog(LogLevel.Warning, "Unable to send discovery fleet: bed time has passed"); - stop = true; - return; - } + int discoveries = await _ogameService.GetAvailableDiscoveries(origin); + if (discoveries <= 0) { + DoLog(LogLevel.Information, "No discoveries available at the moment."); + stop = true; + return; } + DoLog(LogLevel.Information, $"There are {discoveries} discoveries available."); - List possibleDestinations = new(); - int discoveries = await _ogameService.GetAvailableDiscoveries(origin); - if (discoveries > 0) - { - for (int i = 1; i <= _tbotInstance.UserData.serverData.Systems; i++) - { - var newDestinations = await _ogameService.GetPositionsAvailableForDiscoveryFleet(origin, new Coordinate() { Galaxy = origin.Coordinate.Galaxy, System = i, Position = 1 }); - possibleDestinations.AddRange(newDestinations); + List destinationCoord = new(); + if (!((bool) _tbotInstance.InstanceSettings.AutoDiscovery.RandomizeDestination)) { + int maxGalaxy = _tbotInstance.UserData.serverData.Galaxies; + int maxSystem = _tbotInstance.UserData.serverData.Systems; + for (int galaxy = 1; galaxy <= maxGalaxy; galaxy++) { + for (int system = 1; system <= maxSystem; system++) { + for (int position = 1; position <= 15; position++) { + destinationCoord.Add(new Coordinate { Galaxy = galaxy, System = system, Position = position }); + } + } } + destinationCoord = destinationCoord.Where(c => !_tbotInstance.UserData.discoveryBlackList.ContainsKey(c)) + .OrderBy(c => _calculationService.CalcDistance(new(origin.Coordinate.Galaxy, origin.Coordinate.System), c, _tbotInstance.UserData.serverData)) + .ToList(); } - possibleDestinations = possibleDestinations - .Shuffle() - .OrderBy(c => c.Position) - .OrderBy(c => c.System) - .OrderBy(c => _calculationService.CalcDistance(origin.Coordinate, c, _tbotInstance.UserData.serverData)) - .ToList(); - while (possibleDestinations.Count > 0 && _tbotInstance.UserData.fleets.Where(s => s.Mission == Missions.Discovery).Count() < MaxSlots && _tbotInstance.UserData.slots.Free > (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree) - { - Coordinate dest = possibleDestinations.First(); - possibleDestinations.Remove(dest); - - Coordinate blacklistedCoord = _tbotInstance.UserData.discoveryBlackList.Keys - .Where(c => c.Galaxy == dest.Galaxy && c.System == dest.System && c.Position == dest.Position) - .SingleOrDefault(); - - if (blacklistedCoord != null) - { - if (_tbotInstance.UserData.discoveryBlackList[blacklistedCoord] > DateTime.Now) - { - skips++; - continue; + while (discoveries > 0 && !stop && fleetsToSend > 0 && _tbotInstance.UserData.slots.Free > (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + Coordinate dest; + if ((bool) _tbotInstance.InstanceSettings.AutoDiscovery.RandomizeDestination) { + dest = new() { Galaxy = origin.Coordinate.Galaxy, System = Random.Shared.Next(1, _tbotInstance.UserData.serverData.Systems + 1), Position = Random.Shared.Next(1, 16) + }; + } else { + dest = destinationCoord.First(); + destinationCoord.RemoveAt(0); } - else - { - _tbotInstance.UserData.discoveryBlackList.Remove(blacklistedCoord); + Coordinate blacklistedCoord = _tbotInstance.UserData.discoveryBlackList.Keys.SingleOrDefault(c => c.Galaxy == dest.Galaxy && c.System == dest.System && c.Position == dest.Position); + if (blacklistedCoord != null) { + if (_tbotInstance.UserData.discoveryBlackList[blacklistedCoord] > DateTime.Now) { + skips++; + continue; + } else { + _tbotInstance.UserData.discoveryBlackList.Remove(blacklistedCoord); + } } - } - - var result = await _ogameService.SendDiscovery(origin, dest); - if (!result) - { - DoLog(LogLevel.Warning, $"Failed to send discovery fleet to {dest.ToString()} from {origin.ToString()}."); - _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(1)); - } - else - { - DoLog(LogLevel.Information, $"Discovery fleet sent to {dest.ToString()} from {origin.ToString()}."); - _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(7)); - } - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - if (_tbotInstance.UserData.slots.Free <= _tbotInstance.InstanceSettings.General.SlotsToLeaveFree || _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery) >= MaxSlots) - { - long interval = 0; - if (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Any()) - { - interval = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).Max(f => f.BackIn) ?? 0) * 1000; + var result = await _ogameService.SendDiscovery(origin, dest); + if (!result) { + DoLog(LogLevel.Warning, $"Failed to send discovery fleet to {dest.ToString()} from {origin.ToString()}."); + _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(7)); + } else { + DoLog(LogLevel.Information, $"Discovery fleet sent to {dest.ToString()} from {origin.ToString()}."); + _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(7)); + discoveries--; + fleetsToSend--; } - if (interval <= 0) - { - interval = Random.Shared.Next((int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax) * 1000; + if (_tbotInstance.UserData.slots.Free <= (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + DoLog(LogLevel.Information, "No more fleet slots available for AutoDiscovery in this cycle."); + stop = true; + break; } - - DoLog(LogLevel.Information, $"No more fleet slots available or max discovery fleets sent. Delaying for {TimeSpan.FromMilliseconds(interval).TotalSeconds}s."); - await Task.Delay((int)interval); - // break; // https://discord.com/channels/801453618770214923/919312220637249537/1402221089588903968 + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); } - await Task.Delay(Random.Shared.Next((int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax) * 1000); - } + if (skips > 0) - { - DoLog(LogLevel.Information, $"{skips} systems skipped (blacklisted)"); - } - if (possibleDestinations.Count == 0) - { - DoLog(LogLevel.Information, "No more systems to discover: stopping for now."); - stop = true; - } - } - else - { - DoLog(LogLevel.Information, "Skipping: Sleep Mode is active."); + DoLog(LogLevel.Information, $"{skips} positions skipped (blacklisted)"); + + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + long interval = (_tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).ToList().First().BackIn *1000 ?? 0) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds);; + DateTime time = await _tbotOgameBridge.GetDateTime(); + if (interval < 0) + interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + time = time.AddMilliseconds(interval); + ChangeWorkerPeriod(interval); + DoLog(LogLevel.Information, $"Next check at {time.ToString()}"); + await _tbotOgameBridge.CheckCelestials(); + } else { stop = true; } - } - catch (Exception e) - { - DoLog(LogLevel.Error, $"AutoDiscovery Exception: {e.Message}"); - DoLog(LogLevel.Warning, $"Stacktrace: {e.StackTrace}"); - } - finally - { - if (stop) - { - DoLog(LogLevel.Information, "Stopping AutoDiscovery."); - await _tbotInstance.StopFeature(GetFeature()); + } catch (Exception e) { + DoLog(LogLevel.Error, $"An error occured: {e.Message}"); + DoLog(LogLevel.Debug, e.StackTrace); + } finally { + if (stop) { + DoLog(LogLevel.Information, $"Stopping feature."); + await EndExecution(); } - - else - { - var time = Random.Shared.Next((int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax); - DoLog(LogLevel.Information, $"Next AutoDiscovery check in {time}s."); - await Task.Delay(time * 1000); + if (delay) { + DoLog(LogLevel.Information, $"Delaying..."); + var timeDelay = await _tbotOgameBridge.GetDateTime(); + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + long intervalDelay = 0; + try { + intervalDelay = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + } catch { + intervalDelay = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax); + } + var newTimeDelay = timeDelay.AddMilliseconds(intervalDelay); + ChangeWorkerPeriod(intervalDelay); + DoLog(LogLevel.Information, $"Next AutoDiscovery check at {newTimeDelay.ToString()}"); } await _tbotOgameBridge.CheckCelestials(); - } + } } public override bool IsWorkerEnabledBySettings() { diff --git a/TBot/Workers/AutoFarmWorker.cs b/TBot/Workers/AutoFarmWorker.cs index 105508dd..85393598 100644 --- a/TBot/Workers/AutoFarmWorker.cs +++ b/TBot/Workers/AutoFarmWorker.cs @@ -586,29 +586,35 @@ protected override async Task Execute() { new RankSlotsPriority(Feature.BrainAutoMine, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), new RankSlotsPriority(Feature.Expeditions, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal), + (int) _tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.UserData.slots.ExpInUse), new RankSlotsPriority(Feature.AutoFarm, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), new RankSlotsPriority(Feature.Colonize, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1), + 1, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), new RankSlotsPriority(Feature.AutoDiscovery, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), new RankSlotsPriority(Feature.Harvest, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; int MaxSlots = _calculationService.CalcSlotsPriority(Feature.AutoFarm, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); diff --git a/TBot/Workers/Brain/AutoDefenceWorker.cs b/TBot/Workers/Brain/AutoDefenceWorker.cs new file mode 100644 index 00000000..c49c2c43 --- /dev/null +++ b/TBot/Workers/Brain/AutoDefenceWorker.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Tbot.Helpers; +using Tbot.Includes; +using Tbot.Services; +using TBot.Common.Logging; +using TBot.Model; +using TBot.Ogame.Infrastructure; +using TBot.Ogame.Infrastructure.Enums; +using TBot.Ogame.Infrastructure.Models; + +namespace Tbot.Workers.Brain { + public class AutoDefenceWorker : WorkerBase { + private readonly IOgameService _ogameService; + private readonly IFleetScheduler _fleetScheduler; + private readonly ICalculationService _calculationService; + private readonly ITBotOgamedBridge _tbotOgameBridge; + public AutoDefenceWorker(ITBotMain parentInstance, + IOgameService ogameService, + IFleetScheduler fleetScheduler, + ICalculationService calculationService, + ITBotOgamedBridge tbotOgameBridge) : + base(parentInstance) { + _ogameService = ogameService; + _fleetScheduler = fleetScheduler; + _calculationService = calculationService; + _tbotOgameBridge = tbotOgameBridge; + } + + protected override async Task Execute() { + try { + DoLog(LogLevel.Information, "Running autodefence..."); + + List newCelestials = _tbotInstance.UserData.celestials.ToList(); + List celestialsToExclude = _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.Brain.AutoDefence.Exclude, _tbotInstance.UserData.celestials); + + Defences neededDefences = new( + (long) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.RocketLauncher, + (long) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.LightLaser, + (long) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.HeavyLaser, + (long) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.GaussCannon, + (long) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.IonCannon, + (long) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.PlasmaTurret, + (long) ((bool) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.SmallShieldDome ? 1: 0), + (long) ((bool) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.LargeShieldDome ? 1: 0), + (long) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.AntiBallisticMissiles, + (long) _tbotInstance.InstanceSettings.Brain.AutoDefence.DefenceToReach.InterplanetaryMissiles + ); + foreach (Celestial celestial in (bool) _tbotInstance.InstanceSettings.Brain.AutoDefence.RandomOrder ? _tbotInstance.UserData.celestials.Shuffle().ToList() : _tbotInstance.UserData.celestials) { + if (celestialsToExclude.Has(celestial)) { + DoLog(LogLevel.Information, $"Skipping {celestial.ToString()}: celestial in exclude list."); + continue; + } + + var tempCelestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Fast); + + tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.Productions); + if (tempCelestial.HasProduction()) { + DoLog(LogLevel.Warning, $"Skipping {tempCelestial.ToString()}: there is already a production ongoing."); + foreach (Production production in tempCelestial.Productions) { + Buildables productionType = (Buildables) production.ID; + DoLog(LogLevel.Information, $"Skipping {tempCelestial.ToString()}: {production.Nbr}x{productionType.ToString()} are already in production."); + } + continue; + } + tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.Constructions); + if (tempCelestial.Constructions.BuildingID == (int) Buildables.Shipyard || tempCelestial.Constructions.BuildingID == (int) Buildables.NaniteFactory) { + Buildables buildingInProgress = (Buildables) tempCelestial.Constructions.BuildingID; + DoLog(LogLevel.Information, $"Skipping {tempCelestial.ToString()}: {buildingInProgress.ToString()} is upgrading."); + continue; + } + + tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.Ships); + tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.Defences); + tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.Resources); + tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.LFBonuses); + + var capacity = _calculationService.CalcFleetCapacity(tempCelestial.Ships, _tbotInstance.UserData.serverData, _tbotInstance.UserData.researches.HyperspaceTechnology, tempCelestial.LFBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); + if (tempCelestial.Coordinate.Type == Celestials.Moon && (bool) _tbotInstance.InstanceSettings.Brain.AutoDefence.ExcludeMoons) { + DoLog(LogLevel.Information, $"Skipping {tempCelestial.ToString()}: celestial is a moon."); + continue; + } + Defences currentDefences = tempCelestial.Defences; + Defences defencesToBuild = neededDefences.Difference(currentDefences); + if (defencesToBuild.IsEmpty()) { + DoLog(LogLevel.Information, $"Skipping {tempCelestial.ToString()}: all defences are already built."); + continue; + } else { + Resources defenceCost = defencesToBuild.GetDefenceCost(); + if (!tempCelestial.Resources.IsEnoughFor(defenceCost)) { + DoLog(LogLevel.Information, $"{tempCelestial.ToString()}: Not enough resources to build all defences. Will build only what is possible."); + defencesToBuild = _calculationService.CalcmaxDefencesBuildable(defencesToBuild, tempCelestial.Resources); + } + if (defencesToBuild.IsEmpty()) { + DoLog(LogLevel.Information, $"{tempCelestial.ToString()}: Not enough resources to build any defence."); + continue; + } + DoLog(LogLevel.Information, $"{tempCelestial.ToString()}: Defences to build: {defencesToBuild.ToString()}"); + try { + foreach (var (defenceType, amountNeeded) in defencesToBuild.GetDefenceTypesWithAmount()) { + await _ogameService.BuildDefences(tempCelestial, defenceType, amountNeeded); + } + DoLog(LogLevel.Information, "Production succesfully started."); + } catch { + DoLog(LogLevel.Warning, "Unable to start defence production."); + } + tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.Productions); + foreach (Production production in tempCelestial.Productions) { + Buildables productionType = (Buildables) production.ID; + DoLog(LogLevel.Information, $"{tempCelestial.ToString()}: {production.Nbr}x{productionType.ToString()} are in production."); + } + } + + newCelestials.Remove(celestial); + newCelestials.Add(tempCelestial); + } + _tbotInstance.UserData.celestials = newCelestials; + } catch (Exception e) { + DoLog(LogLevel.Error, $"Unable to complete autodefence: {e.Message}"); + DoLog(LogLevel.Warning, $"Stacktrace: {e.StackTrace}"); + } finally { + var time = await _tbotOgameBridge.GetDateTime(); + var interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.AutoDefence.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.AutoDefence.CheckIntervalMax); + if (interval <= 0) + interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + var newTime = time.AddMilliseconds(interval); + ChangeWorkerPeriod(interval); + DoLog(LogLevel.Information, $"Next Defence check at {newTime.ToString()}"); + await _tbotOgameBridge.CheckCelestials(); + } + } + + public override bool IsWorkerEnabledBySettings() { + try { + return ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.AutoDefence.Active); + } catch(Exception) { + return false; + } + } + + public override string GetWorkerName() { + return "AutoDefence"; + } + public override Feature GetFeature() { + return Feature.BrainAutobuildDefence; + } + + public override LogSender GetLogSender() { + return LogSender.AutoDefence; + } + } +} diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index e7e15184..2bbb3db3 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -308,31 +308,37 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings new RankSlotsPriority(Feature.BrainAutoMine, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), new RankSlotsPriority(Feature.Expeditions, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal), + (int) _tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.UserData.slots.ExpInUse), new RankSlotsPriority(Feature.AutoFarm, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), new RankSlotsPriority(Feature.Colonize, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1), + 1, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), new RankSlotsPriority(Feature.AutoDiscovery, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), new RankSlotsPriority(Feature.Harvest, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) - }; - int MaxSlots = _calculationService.CalcSlotsPriority(Feature.BrainAutoMine, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) + }; + int MaxSlots = _calculationService.CalcSlotsPriority(Feature.BrainAutoMine, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); if (MaxSlots > 0) { if (!_calculationService.IsThereTransportTowardsCelestial(celestial, _tbotInstance.UserData.fleets)) { diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 3e1129d4..3f887d3e 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -182,29 +182,35 @@ protected override async Task Execute() { new RankSlotsPriority(Feature.BrainAutoResearch, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), new RankSlotsPriority(Feature.Expeditions, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal), + (int) _tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.UserData.slots.ExpInUse), new RankSlotsPriority(Feature.AutoFarm, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), new RankSlotsPriority(Feature.Colonize, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1), + 1, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), new RankSlotsPriority(Feature.AutoDiscovery, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), new RankSlotsPriority(Feature.Harvest, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; int MaxSlots = _calculationService.CalcSlotsPriority(Feature.BrainAutoResearch, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index 678cece4..dc58bf84 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -188,29 +188,35 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { new RankSlotsPriority(Feature.BrainLifeformAutoMine, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), new RankSlotsPriority(Feature.Expeditions, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal), + (int) _tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.UserData.slots.ExpInUse), new RankSlotsPriority(Feature.AutoFarm, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), new RankSlotsPriority(Feature.Colonize, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1), + 1, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), new RankSlotsPriority(Feature.AutoDiscovery, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), new RankSlotsPriority(Feature.Harvest, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; int MaxSlots = _calculationService.CalcSlotsPriority(Feature.BrainLifeformAutoMine, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); diff --git a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs index 8a7ac865..54c38f72 100644 --- a/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoResearchCelestialWorker.cs @@ -198,29 +198,35 @@ private async Task LifeformAutoResearchCelestial(Celestial celestial) { new RankSlotsPriority(Feature.BrainLifeformAutoResearch, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), new RankSlotsPriority(Feature.Expeditions, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal), + (int) _tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.UserData.slots.ExpInUse), new RankSlotsPriority(Feature.AutoFarm, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), new RankSlotsPriority(Feature.Colonize, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1), + 1, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), new RankSlotsPriority(Feature.AutoDiscovery, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), new RankSlotsPriority(Feature.Harvest, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; int MaxSlots = _calculationService.CalcSlotsPriority(Feature.BrainLifeformAutoResearch, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); diff --git a/TBot/Workers/ColonizeWorker.cs b/TBot/Workers/ColonizeWorker.cs index 57b4bc37..213069ee 100644 --- a/TBot/Workers/ColonizeWorker.cs +++ b/TBot/Workers/ColonizeWorker.cs @@ -103,29 +103,35 @@ protected override async Task Execute() { new RankSlotsPriority(Feature.BrainAutoMine, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), new RankSlotsPriority(Feature.Expeditions, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal), + (int) _tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.UserData.slots.ExpInUse), new RankSlotsPriority(Feature.AutoFarm, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), new RankSlotsPriority(Feature.Colonize, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1), + 1, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), new RankSlotsPriority(Feature.AutoDiscovery, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), new RankSlotsPriority(Feature.Harvest, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; int MaxSlots = _calculationService.CalcSlotsPriority(Feature.Colonize, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index 35357aa3..bcfa777f 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -79,29 +79,35 @@ protected override async Task Execute() { new RankSlotsPriority(Feature.BrainAutoMine, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), new RankSlotsPriority(Feature.Expeditions, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal), + (int) _tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.UserData.slots.ExpInUse), new RankSlotsPriority(Feature.AutoFarm, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), new RankSlotsPriority(Feature.Colonize, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1), + 1, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), new RankSlotsPriority(Feature.AutoDiscovery, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), new RankSlotsPriority(Feature.Harvest, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; int MaxSlots = _calculationService.CalcSlotsPriority(Feature.Expeditions, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); diff --git a/TBot/Workers/HarvestWorker.cs b/TBot/Workers/HarvestWorker.cs index 2aa9ca69..93c0464c 100644 --- a/TBot/Workers/HarvestWorker.cs +++ b/TBot/Workers/HarvestWorker.cs @@ -147,29 +147,35 @@ protected override async Task Execute() { new RankSlotsPriority(Feature.BrainAutoMine, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots), + (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), new RankSlotsPriority(Feature.Expeditions, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal), + (int) _tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.UserData.slots.ExpInUse), new RankSlotsPriority(Feature.AutoFarm, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), new RankSlotsPriority(Feature.Colonize, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1), + 1, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), new RankSlotsPriority(Feature.AutoDiscovery, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots), + (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), new RankSlotsPriority(Feature.Harvest, (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots) + (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; int MaxSlots = _calculationService.CalcSlotsPriority(Feature.Harvest, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); diff --git a/TBot/Workers/WorkerFactory.cs b/TBot/Workers/WorkerFactory.cs index c2f24866..36e363a1 100644 --- a/TBot/Workers/WorkerFactory.cs +++ b/TBot/Workers/WorkerFactory.cs @@ -42,6 +42,7 @@ public ITBotWorker InitializeWorker(Feature feat, ITBotMain tbotMainInstance, IT ITBotWorker newWorker = feat switch { Feature.Defender => new DefenderWorker(tbotMainInstance, _ogameService, _fleetScheduler, tbotOgameBridge), Feature.BrainAutobuildCargo => new AutoCargoWorker(tbotMainInstance, _ogameService, _fleetScheduler, _calculationService, tbotOgameBridge), + Feature.BrainAutobuildDefence => new AutoDefenceWorker(tbotMainInstance, _ogameService, _fleetScheduler, _calculationService, tbotOgameBridge), Feature.BrainAutoRepatriate => new AutoRepatriateWorker(tbotMainInstance, _fleetScheduler, _calculationService, tbotOgameBridge), Feature.BrainAutoMine => new AutoMineWorker(tbotMainInstance, _ogameService, _fleetScheduler, _calculationService, tbotOgameBridge, this), Feature.BrainOfferOfTheDay => new BuyOfferOfTheDayWorker(tbotMainInstance, _ogameService, tbotOgameBridge), @@ -105,6 +106,7 @@ public ITBotCelestialWorker GetCelestialWorker(ITBotWorker parentWorker, Celesti private bool IsBrain(Feature feat) { switch (feat) { case Feature.BrainAutobuildCargo: + case Feature.BrainAutobuildDefence: case Feature.BrainAutoRepatriate: case Feature.BrainAutoMine: case Feature.BrainOfferOfTheDay: diff --git a/TBot/instance_settings.json b/TBot/instance_settings.json index f508926c..6f77812b 100644 --- a/TBot/instance_settings.json +++ b/TBot/instance_settings.json @@ -304,6 +304,29 @@ "CheckIntervalMin": 60, "CheckIntervalMax": 240 }, + "AutoDefence": { + "Active": false, + "ExcludeMoons": true, + "RandomOrder": true, + "DefenceToReach": { + "RocketLauncher": 100000, + "HeavyLaser": 10000, + "GaussCannon": 1000, + "PlasmaTurret": 1000, + "SmallShieldDome": true, + "LargeShieldDome": true + }, + "Exclude": [ + { + "Galaxy": 3, + "System": 333, + "Position": 15, + "Type": "Moon" + } + ], + "CheckIntervalMin": 60, + "CheckIntervalMax": 240 + }, "AutoRepatriate": { "Active": true, "ExcludeMoons": false, @@ -322,24 +345,12 @@ ], "TargetAssociateMoon": false, "CargoType": "LargeCargo", - "RandomOrder": true, + "RandomOrder": false, "SkipIfIncomingTransport": true, - "Exclude": [ - { - "Galaxy": 3, - "System": 482, - "Position": 7, - "Type": "Planet" - } - ], - "TargetAssociateMoon": true, - "CargoType": "SmallCargo", - "RandomOrder": false, - "SkipIfIncomingTransport": true, - "Exclude": [], - "CheckIntervalMin": 3000, - "CheckIntervalMax": 6000 - }, + "Exclude": [], + "CheckIntervalMin": 3000, + "CheckIntervalMax": 6000 + }, "BuyOfferOfTheDay": { "Active": false, "CheckIntervalMin": 240, @@ -501,6 +512,7 @@ }, "MaxSlots": 5, "MaxFailures": 5, + "RandomizeDestination": false, "CheckIntervalMin": 30, "CheckIntervalMax": 60 } From c5785e77ae4b1743e5d8ff99db4a9f95dc5a4f91 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 24 Aug 2025 08:37:43 +0200 Subject: [PATCH 096/117] =?UTF-8?q?v3.3.3=20=E2=80=A2=20Add=20a=20new=20fe?= =?UTF-8?q?ature:=20Brain.AutoDefense.=20It=20works=20in=20the=20same=20wa?= =?UTF-8?q?y=20as=20AutoCargo,=20but=20for=20defense=20=E2=80=A2=20Rework?= =?UTF-8?q?=20CalcSlotsPriority()=20=E2=80=A2=20Rework=20AutoDiscoveryWork?= =?UTF-8?q?er=20feature=20=E2=80=A2=20Update=20instance=5Fsettings.json=20?= =?UTF-8?q?=E2=80=A2=20Update=20various=20LFBonuses=20files=20(waiting=20f?= =?UTF-8?q?or=20information=20on=20/bot/lfbonuses=20to=20complete=20it)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TBot.Common/TBot.Common.csproj | 4 ++-- .../TBot.Ogame.Infrastructure.csproj | 4 ++-- TBot.WebUI/TBot.WebUI.csproj | 6 +++--- TBot/TBot.csproj | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/TBot.Common/TBot.Common.csproj b/TBot.Common/TBot.Common.csproj index 8ed27095..f2a0a7fe 100644 --- a/TBot.Common/TBot.Common.csproj +++ b/TBot.Common/TBot.Common.csproj @@ -7,9 +7,9 @@ - + - + diff --git a/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj b/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj index d530990e..1ee9fcb4 100644 --- a/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj +++ b/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj @@ -7,9 +7,9 @@ - + - + diff --git a/TBot.WebUI/TBot.WebUI.csproj b/TBot.WebUI/TBot.WebUI.csproj index efef6a73..0272c640 100644 --- a/TBot.WebUI/TBot.WebUI.csproj +++ b/TBot.WebUI/TBot.WebUI.csproj @@ -35,9 +35,9 @@ - - - + + + diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index e9b97d4d..5dee14fe 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,14 +5,14 @@ net9.0 disable TBot - 3.3.2 + 3.3.3 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.3.2 + 3.3.3 3.3.2 OGame Bot False @@ -42,12 +42,12 @@ - - + + - - + + From 680e7622e6b7f55642b86872b65773a96c16db71 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Sun, 31 Aug 2025 20:40:17 +0200 Subject: [PATCH 097/117] update LFBonuses --- TBot.Ogame.Infrastructure/Models/LFBonuses.cs | 44 ++++++++++++++++--- .../Models/LFBonusesCharacterClasses.cs | 14 ++++++ .../Models/LFBonusesMisc.cs | 15 +++++++ .../Models/LFBonusesResources.cs | 14 ++++++ .../Models/LFBonusesShip.cs | 28 ++++++------ TBot.Ogame.Infrastructure/OgameService.cs | 3 +- TBot/Includes/CalculationService.cs | 22 +++++----- TBot/Services/TBotMain.cs | 4 +- TBot/Workers/Brain/AutoMineCelestialWorker.cs | 7 +-- TBot/Workers/Brain/AutoResearchWorker.cs | 3 +- .../Brain/LifeformsAutoMineCelestialWorker.cs | 4 +- 11 files changed, 119 insertions(+), 39 deletions(-) create mode 100644 TBot.Ogame.Infrastructure/Models/LFBonusesCharacterClasses.cs create mode 100644 TBot.Ogame.Infrastructure/Models/LFBonusesMisc.cs create mode 100644 TBot.Ogame.Infrastructure/Models/LFBonusesResources.cs diff --git a/TBot.Ogame.Infrastructure/Models/LFBonuses.cs b/TBot.Ogame.Infrastructure/Models/LFBonuses.cs index 42e0b6bb..c3f96945 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBonuses.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBonuses.cs @@ -8,6 +8,32 @@ namespace TBot.Ogame.Infrastructure.Models { public class LFBonuses { + + public LFBonusesResources LfResourceBonuses { get; set; } + public LFBonusesCharacterClasses CharacterClassesBonuses { get; set; } + public Dictionary LfShipBonuses { get; set; } + public Dictionary CostTimeBonuses { get; set; } + public LFBonusesMisc MiscBonuses { get; set; } + public Dictionary LfShipBonusesInt { + get { + if (LfShipBonuses == null) + return new Dictionary(); + return LfShipBonuses + .Where(kvp => int.TryParse(kvp.Key, out _)) + .ToDictionary(kvp => int.Parse(kvp.Key), kvp => kvp.Value); + } + } + public Dictionary CostTimeBonusesInt { + get { + if (CostTimeBonuses == null) + return new Dictionary(); + return CostTimeBonuses + .Where(kvp => int.TryParse(kvp.Key, out _)) + .ToDictionary(kvp => int.Parse(kvp.Key), kvp => kvp.Value); + } + } + + public LFBonusesProduction Production { get; set; } public LFBonusesExpeditions Expeditions { get; set; } public LFBonusesDens Dens { get; set; } @@ -29,6 +55,12 @@ public class LFBonuses { public float InactivesLoot { get; set; } public LFBonuses() { + LfResourceBonuses = new LFBonusesResources(); + CharacterClassesBonuses = new LFBonusesCharacterClasses(); + LfShipBonuses = new Dictionary(); + CostTimeBonuses = new Dictionary(); + MiscBonuses = new LFBonusesMisc(); + Production = new LFBonusesProduction(); Expeditions = new LFBonusesExpeditions(); Dens = new LFBonusesDens(); @@ -44,24 +76,24 @@ public LFBonuses() { public float GetShipCargoBonus(Buildables buildable) { float bonusCargo = 0; - if (this != null && Ships != null && Ships.Count > 0 && Ships.ContainsKey((int) buildable)) { - bonusCargo = Ships.GetValueOrDefault((int) buildable).Cargo; + if (this != null && LfShipBonusesInt != null && LfShipBonusesInt.Count > 0 && LfShipBonusesInt.ContainsKey((int) buildable)) { + bonusCargo = LfShipBonusesInt.GetValueOrDefault((int) buildable).CargoCapacity; } return bonusCargo; } public float GetShipSpeedBonus(Buildables buildable) { float bonusSpeed = 0; - if (this != null && Ships != null && Ships.Count > 0 && Ships.ContainsKey((int) buildable)) { - bonusSpeed = Ships.GetValueOrDefault((int) buildable).Speed; + if (this != null && LfShipBonusesInt != null && LfShipBonusesInt.Count > 0 && LfShipBonusesInt.ContainsKey((int) buildable)) { + bonusSpeed = LfShipBonusesInt.GetValueOrDefault((int) buildable).Speed; } return bonusSpeed; } public float GetShipConsumptionBonus(Buildables buildable) { float bonusCons = 0; - if (this != null && Ships != null && Ships.Count > 0 && Ships.ContainsKey((int) buildable)) { - bonusCons = Ships.GetValueOrDefault((int) buildable).Consumption; + if (this != null && LfShipBonusesInt != null && LfShipBonusesInt.Count > 0 && LfShipBonusesInt.ContainsKey((int) buildable)) { + bonusCons = LfShipBonusesInt.GetValueOrDefault((int) buildable).FuelConsumption; } return bonusCons; } diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesCharacterClasses.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesCharacterClasses.cs new file mode 100644 index 00000000..fef8ab6e --- /dev/null +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesCharacterClasses.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TBot.Ogame.Infrastructure.Models { + public class LFBonusesCharacterClasses { + public float Characterclasses3 { get; set; } + public LFBonusesCharacterClasses(float characterclasses3 = 0) { + Characterclasses3 = characterclasses3; + } + } +} diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesMisc.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesMisc.cs new file mode 100644 index 00000000..8013f286 --- /dev/null +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesMisc.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TBot.Ogame.Infrastructure.Models { + public class LFBonusesMisc { + public float PhalanxRange { get; set; } + + public LFBonusesMisc(float phalanxrange = 0) { + PhalanxRange = phalanxrange; + } + } +} diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesResources.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesResources.cs new file mode 100644 index 00000000..1c8c57ab --- /dev/null +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesResources.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TBot.Ogame.Infrastructure.Models { + public class LFBonusesResources { + public float ResourcesExpedition { get; set; } + public LFBonusesResources(float resourcesexpedition = 0) { + ResourcesExpedition = resourcesexpedition; + } + } +} diff --git a/TBot.Ogame.Infrastructure/Models/LFBonusesShip.cs b/TBot.Ogame.Infrastructure/Models/LFBonusesShip.cs index f66f2a27..bc266456 100644 --- a/TBot.Ogame.Infrastructure/Models/LFBonusesShip.cs +++ b/TBot.Ogame.Infrastructure/Models/LFBonusesShip.cs @@ -6,22 +6,22 @@ namespace TBot.Ogame.Infrastructure.Models { public class LFBonusesShip { - public float Armour { get; set; } - public float Shield { get; set; } - public float Weapon { get; set; } - public float Cargo { get; set; } - public float Speed { get; set; } - public float Consumption { get; set; } - public float Duration { get; set; } + public int ID { get; set; } + public float StructuralIntegrity { get; set; } + public float ShieldPower { get; set; } + public float WeaponPower { get; set; } + public float Speed { get; set; } + public float CargoCapacity { get; set; } + public float FuelConsumption { get; set; } - public LFBonusesShip(float armour = 0, float shield = 0, float weapon = 0, float cargo = 0, float speed = 0, float consumption = 0, float duration = 0) { - Armour = armour; - Shield = shield; - Weapon = weapon; - Cargo = cargo; + public LFBonusesShip(int id = -1, float armour = 0, float shield = 0, float weapon = 0, float speed = 0, float cargo = 0, float consumption = 0) { + ID = id; + StructuralIntegrity = armour; + ShieldPower = shield; + WeaponPower = weapon; Speed = speed; - Consumption = consumption; - Duration = duration; + CargoCapacity = cargo; + FuelConsumption = consumption; } } } diff --git a/TBot.Ogame.Infrastructure/OgameService.cs b/TBot.Ogame.Infrastructure/OgameService.cs index b44dddc4..744c44f0 100644 --- a/TBot.Ogame.Infrastructure/OgameService.cs +++ b/TBot.Ogame.Infrastructure/OgameService.cs @@ -441,7 +441,8 @@ public async Task GetLFBuildings(Celestial celestial) { } public async Task GetLFBonuses(Celestial celestial) { - return await GetAsync($"/bot/planets/{celestial.ID}/lifeform-bonuses"); + //return await GetAsync($"/bot/planets/{celestial.ID}/lifeform-bonuses"); + return await GetAsync($"/bot/lfbonuses"); } public async Task GetLFTechs(Celestial celestial) { diff --git a/TBot/Includes/CalculationService.cs b/TBot/Includes/CalculationService.cs index edbcc7b9..f45390c9 100644 --- a/TBot/Includes/CalculationService.cs +++ b/TBot/Includes/CalculationService.cs @@ -155,7 +155,7 @@ public int CalcShipCapacity(Buildables buildable, int hyperspaceTech, ServerData default: return 0; } - double totalBonus = Math.Round(Math.Round((double) bonus / 100, 2, MidpointRounding.ToZero) + Math.Round((double) buildableCargoBonus / 100, 2, MidpointRounding.ToZero), 2, MidpointRounding.ToZero) - 0.01; + double totalBonus = Math.Round(Math.Round((double) bonus / 100, 2, MidpointRounding.ToZero) + Math.Round((double) buildableCargoBonus, 2, MidpointRounding.ToZero), 2, MidpointRounding.ToZero) - 0.01; int output = (int) Math.Floor((double) baseCargo + (double) (baseCargo * totalBonus)); return output; } @@ -311,7 +311,7 @@ public int CalcShipSpeed(Buildables buildable, int combustionDrive, int impulseD default: return 0; } - var output = ((float) baseSpeed * (lfBonus / 100)) + ((float) baseSpeed * ((float) bonus + 10) / 10); + var output = ((float) baseSpeed * (lfBonus)) + ((float) baseSpeed * ((float) bonus + 10) / 10); return (int) Math.Round(output, MidpointRounding.ToZero); } @@ -422,7 +422,7 @@ public int CalcShipConsumption(Buildables buildable, int impulseDrive, int hyper default: return 0; } - double fuelConsumption = (double) deuteriumSaveFactor * (double) baseConsumption * (1 - lfBonus / 100); + double fuelConsumption = (double) deuteriumSaveFactor * (double) baseConsumption * (1 - lfBonus); if (playerClass == CharacterClass.General) fuelConsumption /= 2; fuelConsumption = Math.Round(fuelConsumption); @@ -595,7 +595,7 @@ public Ships CalcIdealExpeditionShips(Buildables buildable, int hyperspaceTech, float topOnePoints = serverData.TopScore; float buildableCargoBonus = 0; if (shipBonus != null && shipBonus.Count > 0 && shipBonus.ContainsKey((int) buildable)) { - buildableCargoBonus = shipBonus.GetValueOrDefault((int) buildable).Cargo; + buildableCargoBonus = shipBonus.GetValueOrDefault((int) buildable).CargoCapacity; } int freightCap; if (topOnePoints < 10000) @@ -623,7 +623,7 @@ public Ships CalcIdealExpeditionShips(Buildables buildable, int hyperspaceTech, freightCap *= 2; if(expeditionResourcesBonus > 0) - freightCap += (int) Math.Round((float) freightCap * expeditionResourcesBonus / 100, MidpointRounding.ToPositiveInfinity); + freightCap += (int) Math.Round((float) freightCap * expeditionResourcesBonus, MidpointRounding.ToPositiveInfinity); int oneCargoCapacity = CalcShipCapacity(buildable, hyperspaceTech, serverData, buildableCargoBonus, playerClass, probeCargo); int cargoNumber = (int) Math.Round((float) freightCap / (float) oneCargoCapacity, MidpointRounding.ToPositiveInfinity); @@ -673,7 +673,7 @@ public Ships CalcExpeditionShips(Ships fleet, Buildables primaryShip, int expedi } public Ships CalcExpeditionShips(Ships fleet, Buildables primaryShip, int expeditionsNumber, ServerData serverdata, Researches researches, LFBonuses LFBonuses, CharacterClass playerClass = CharacterClass.NoClass, int probeCargo = 0) { - return CalcExpeditionShips(fleet, primaryShip, expeditionsNumber, researches.HyperspaceTechnology, LFBonuses.Expeditions.Resources, LFBonuses.Ships, serverdata, playerClass, probeCargo); + return CalcExpeditionShips(fleet, primaryShip, expeditionsNumber, researches.HyperspaceTechnology, LFBonuses.LfResourceBonuses.ResourcesExpedition, LFBonuses.LfShipBonusesInt, serverdata, playerClass, probeCargo); } public bool MayAddShipToExpedition(Ships fleet, Buildables buildable, int expeditionsNumber) { @@ -1228,12 +1228,12 @@ public Resources CalcPrice(Buildables buildable, int level, LFBonuses lfBonuses } if (lfBonuses != null) { - float reduction = 0; - if (lfBonuses.Buildings.Keys.Any(b => b == (int) buildable)) { - reduction = lfBonuses.Buildings[(int) buildable].Cost; + float reduction = 0; + if (lfBonuses.CostTimeBonusesInt.Keys.Any(b => b == (int) buildable)) { + reduction = lfBonuses.CostTimeBonusesInt[(int) buildable].Cost; } - else if (lfBonuses.Researches.Keys.Any(b => b == (int) buildable)) { - reduction = lfBonuses.Researches[(int) buildable].Cost; + else if (lfBonuses.CostTimeBonusesInt.Keys.Any(b => b == (int) buildable)) { + reduction = lfBonuses.CostTimeBonusesInt[(int) buildable].Cost; } output.Metal = (long) (output.Metal - (output.Metal * reduction)); output.Crystal = (long) (output.Crystal - (output.Crystal * reduction)); diff --git a/TBot/Services/TBotMain.cs b/TBot/Services/TBotMain.cs index 4e5959fe..7b42deb8 100644 --- a/TBot/Services/TBotMain.cs +++ b/TBot/Services/TBotMain.cs @@ -899,7 +899,7 @@ public async Task TelegramJumpGate(Celestial origin, Coordinate destination, str if (mode.Equals("auto")) { float cargoBonus = 0; if (origin.LFBonuses != null && origin.LFBonuses.Ships != null && origin.LFBonuses.Ships.Count > 0 && origin.LFBonuses.Ships.ContainsKey((int) Buildables.SmallCargo)) { - cargoBonus = origin.LFBonuses.Ships.GetValueOrDefault((int) Buildables.SmallCargo).Cargo; + cargoBonus = origin.LFBonuses.Ships.GetValueOrDefault((int) Buildables.SmallCargo).CargoCapacity; } long idealSmallCargo = _helpersService.CalcShipNumberForPayload(payload, Buildables.SmallCargo, userData.researches.HyperspaceTechnology, userData.serverData, cargoBonus, userData.userInfo.Class, userData.serverData.ProbeCargo); @@ -908,7 +908,7 @@ public async Task TelegramJumpGate(Celestial origin, Coordinate destination, str } else { cargoBonus = 0; if (origin.LFBonuses != null && origin.LFBonuses.Ships != null && origin.LFBonuses.Ships.Count > 0 && origin.LFBonuses.Ships.ContainsKey((int) Buildables.LargeCargo)) { - cargoBonus = origin.LFBonuses.Ships.GetValueOrDefault((int) Buildables.LargeCargo).Cargo; + cargoBonus = origin.LFBonuses.Ships.GetValueOrDefault((int) Buildables.LargeCargo).CargoCapacity; } long idealLargeCargo = _helpersService.CalcShipNumberForPayload(payload, Buildables.LargeCargo, userData.researches.HyperspaceTechnology, userData.serverData, cargoBonus, userData.userInfo.Class, userData.serverData.ProbeCargo); if (idealLargeCargo <= origin.Ships.GetAmount(Buildables.LargeCargo)) { diff --git a/TBot/Workers/Brain/AutoMineCelestialWorker.cs b/TBot/Workers/Brain/AutoMineCelestialWorker.cs index 2bbb3db3..83401c54 100644 --- a/TBot/Workers/Brain/AutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/AutoMineCelestialWorker.cs @@ -204,7 +204,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings DoLog(LogLevel.Debug, $"Days of investment return: {Math.Round(DOIR, 2).ToString()} days."); } - Resources xCostBuildable = _calculationService.CalcPrice(buildable, level);//, celestial.LFBonuses); + Resources xCostBuildable = _calculationService.CalcPrice(buildable, level, celestial.LFBonuses); if (celestial is Moon) xCostBuildable.Deuterium += (long) autoMinerSettings.DeutToLeaveOnMoons; @@ -214,7 +214,7 @@ private async Task AutoMineCelestial(Celestial celestial, Buildings maxBuildings if ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.BuildSolarSatellites) { buildable = Buildables.SolarSatellite; level = _calculationService.CalcNeededSolarSatellites(celestial as Planet, xCostBuildable.Energy - celestial.ResourcesProduction.Energy.CurrentProduction, _tbotInstance.UserData.userInfo.Class == CharacterClass.Collector, _tbotInstance.UserData.staff.Engineer, _tbotInstance.UserData.staff.IsFull); - xCostBuildable = _calculationService.CalcPrice(buildable, level); + xCostBuildable = _calculationService.CalcPrice(buildable, level, celestial.LFBonuses); } else { DoLog(LogLevel.Information, $"Unable to build SolarSatellites for Terraformer. Stopping AutoMiner for celestial {celestial.ToString()}"); @@ -704,9 +704,10 @@ private async Task CalcAutoMineTimer(Celestial celestial, Buildables build } else { celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Buildings); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Facilities); + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses); if (buildable != Buildables.Null) { - var price = _calculationService.CalcPrice(buildable, level); + var price = _calculationService.CalcPrice(buildable, level, celestial.LFBonuses); var productionTime = long.MaxValue; var transportTime = long.MaxValue; var returningExpoTime = long.MaxValue; diff --git a/TBot/Workers/Brain/AutoResearchWorker.cs b/TBot/Workers/Brain/AutoResearchWorker.cs index 3f887d3e..6476d364 100644 --- a/TBot/Workers/Brain/AutoResearchWorker.cs +++ b/TBot/Workers/Brain/AutoResearchWorker.cs @@ -165,7 +165,8 @@ protected override async Task Execute() { if (research != Buildables.Null) { celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Resources) as Planet; celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.Ships) as Planet; - Resources cost = _calculationService.CalcPrice(research, level); + celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.LFBonuses) as Planet; + Resources cost = _calculationService.CalcPrice(research, level, celestial.LFBonuses); if (celestial.Resources.IsEnoughFor(cost)) { try { await _ogameService.BuildCancelable(celestial, research); diff --git a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs index dc58bf84..cc68cff9 100644 --- a/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs +++ b/TBot/Workers/Brain/LifeformsAutoMineCelestialWorker.cs @@ -459,7 +459,9 @@ private async Task LifeformAutoMineCelestial(Celestial celestial) { interval = delayTime; } else { if (fleetId == (int) SendFleetCode.QuickerToWaitForProduction) { - var price = _calculationService.CalcPrice(buildable, level); + float costReduction = _calculationService.CalcLFBuildingsResourcesCostBonus(celestial); + float popReduction = _calculationService.CalcLFBuildingsPopulationCostBonus(celestial); + var price = _calculationService.CalcPrice(buildable, level, costReduction, 0, popReduction); long productionTime = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.CheckIntervalMax); celestial = await _tbotOgameBridge.UpdatePlanet(celestial, UpdateTypes.ResourcesProduction); DateTime now = await _tbotOgameBridge.GetDateTime(); From b6fe213c556110e9b21f2f5e3e3d6450a8e6f6d2 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Tue, 9 Sep 2025 19:08:37 +0200 Subject: [PATCH 098/117] * update deps --- TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj | 2 +- TBot/TBot.csproj | 4 ++-- ogame | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj b/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj index 1ee9fcb4..239fa33a 100644 --- a/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj +++ b/TBot.Ogame.Infrastructure/TBot.Ogame.Infrastructure.csproj @@ -9,7 +9,7 @@ - + diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 5dee14fe..e16cdd27 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -13,7 +13,7 @@ https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot 3.3.3 - 3.3.2 + 3.3.3 OGame Bot False ELK-Lab.pfx @@ -47,7 +47,7 @@ - + diff --git a/ogame b/ogame index f1d908f0..ba8df9ac 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit f1d908f0c2a8d89e814884eb95211d87c6a80b11 +Subproject commit ba8df9ac49b457b08aa6c5eef5270f59d6e43d7d From d8495dce75a27cdbd3528c653c3eaab596b89dcc Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Tue, 9 Sep 2025 19:09:58 +0200 Subject: [PATCH 099/117] v3.3.4 update deps --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index e16cdd27..e35f4be4 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.3.3 + 3.3.4 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.3.3 - 3.3.3 + 3.3.4 + 3.3.4 OGame Bot False ELK-Lab.pfx From 08b7d8753808456c7bb6ad47e5576b05980fe11f Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Wed, 17 Sep 2025 19:16:43 +0200 Subject: [PATCH 100/117] add /collectall --- TBot/Includes/IFleetScheduler.cs | 4 ++-- TBot/Services/TBotMain.cs | 5 ++--- TBot/Services/TelegramMessenger.cs | 12 ++++++++++++ TBot/Workers/FleetScheduler.cs | 8 ++++---- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/TBot/Includes/IFleetScheduler.cs b/TBot/Includes/IFleetScheduler.cs index d4703d19..f029c3ec 100644 --- a/TBot/Includes/IFleetScheduler.cs +++ b/TBot/Includes/IFleetScheduler.cs @@ -20,8 +20,8 @@ public interface IFleetScheduler { void RetireFleet(object fleet); Task HandleMinerTransport(Celestial origin, Celestial destination, Celestial differentDestination, Resources resources, Buildables buildable = Buildables.Null, Buildings maxBuildings = null, Facilities maxFacilities = null, Facilities maxLunarFacilities = null, AutoMinerSettings autoMinerSettings = null); Task HandleMinerTransport(Celestial origin, Celestial destination, Celestial differentDestination, Resources resources, LFBuildables buildable = LFBuildables.None, LFBuildings maxLFBuildings = null, bool preventIfMoreExpensiveThanNextMine = false); - Task Collect(); - Task CollectImpl(bool fromTelegram = false); + Task Collect(bool noLimit = false); + Task CollectImpl(bool fromTelegram = false, bool noLimit = false); Task CollectDeut(long minAmount = 0); } } diff --git a/TBot/Services/TBotMain.cs b/TBot/Services/TBotMain.cs index 4e5959fe..60743990 100644 --- a/TBot/Services/TBotMain.cs +++ b/TBot/Services/TBotMain.cs @@ -841,9 +841,8 @@ await SendTelegramMessage($"Auction done with Resources of Planet {celestial.Nam } } - public void TelegramCollect() { - _fleetScheduler.Collect(); - + public void TelegramCollect(bool noLimit = false) { + _fleetScheduler.Collect(noLimit); return; } diff --git a/TBot/Services/TelegramMessenger.cs b/TBot/Services/TelegramMessenger.cs index de9330dc..1815b268 100644 --- a/TBot/Services/TelegramMessenger.cs +++ b/TBot/Services/TelegramMessenger.cs @@ -240,6 +240,7 @@ public async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, "/wakeup", "/build", "/collect", + "/collectall", "/collectdeut", "/minexpecargo", "/stopexpe", @@ -425,6 +426,7 @@ await SendMessage(botClient, message.Chat, "/spycrash - Create a debris field by crashing a probe on target or automatically selected planet. Format: /spycrash 2:41:9/auto\n" + "/recall - Enable/disable fleet auto recall. Format: /recall true/false\n" + "/collect - Collect planets resources to JSON setting celestial\n" + + "/collectall - Collect planets resources to JSON setting celestial with no MinimumResources\n" + "/build - Try to build buildable on each planet. Build max possible if no number value sent /build LightFighter [100]\n" + "/collectdeut - Collect planets only deut resources -> to JSON repatriate setting celestial\n" + "/msg - Send a message to current attacker. Format: /msg hello dude\n" + @@ -918,6 +920,16 @@ await SendMessage(botClient, message.Chat, return; + case "/collectall": + if (message.Text.Split(' ').Length != 1) { + await SendMessage(botClient, message.Chat, "No argument accepted with this command!"); + return; + } + + currInstance.TelegramCollect(true); + return; + + case "/collectdeut": if (message.Text.Split(' ').Length != 2) { await SendMessage(botClient, message.Chat, "Need minimum deut amount argument /collectdeut 500000"); diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 245ce8f7..c283db8e 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -1141,8 +1141,8 @@ public async Task HandleMinerTransport(Celestial origin, Celestial destinat } } - public async Task Collect() { - await CollectImpl(true); + public async Task Collect(bool noLimit = false) { + await CollectImpl(true, noLimit); } public async Task CollectDeut(long MinAmount = 0) { @@ -1228,7 +1228,7 @@ public async Task CollectDeut(long MinAmount = 0) { } } - public async Task CollectImpl(bool fromTelegram) { + public async Task CollectImpl(bool fromTelegram, bool noLimit = false) { try { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, "Repatriating resources..."); @@ -1314,7 +1314,7 @@ public async Task CollectImpl(bool fromTelegram) { } } - if (payload.TotalResources < (long) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.MinimumResources || payload.IsEmpty()) { + if ((payload.TotalResources < (long) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.MinimumResources || payload.IsEmpty()) && !noLimit) { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping {tempCelestial.ToString()}: resources under set limit"); continue; } From 238017bb9bc49a816fea2a6fe4ea7b945734c690 Mon Sep 17 00:00:00 2001 From: Cheeeh Date: Wed, 17 Sep 2025 19:27:31 +0200 Subject: [PATCH 101/117] typo --- TBot/Workers/FleetScheduler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index c283db8e..860ade9f 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -1314,7 +1314,7 @@ public async Task CollectImpl(bool fromTelegram, bool noLimit = } } - if ((payload.TotalResources < (long) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.MinimumResources || payload.IsEmpty()) && !noLimit) { + if ((!noLimit && payload.TotalResources < (long) _tbotInstance.InstanceSettings.Brain.AutoRepatriate.MinimumResources) || payload.IsEmpty()) { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Skipping {tempCelestial.ToString()}: resources under set limit"); continue; } From 1623323815cdc73fd81a99809f2461ee96041565 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 30 Oct 2025 16:16:07 +0100 Subject: [PATCH 102/117] * delay instance loading --- TBot/Services/InstanceManager.cs | 5 +++++ TBot/Services/TBotMain.cs | 1 + 2 files changed, 6 insertions(+) diff --git a/TBot/Services/InstanceManager.cs b/TBot/Services/InstanceManager.cs index fc2ac212..a3f4ab20 100644 --- a/TBot/Services/InstanceManager.cs +++ b/TBot/Services/InstanceManager.cs @@ -149,6 +149,11 @@ public async void OnSettingsChanged() { string alias = instanceToBeInited.Alias; _logger.WriteLog(LogLevel.Information, LogSender.Main, $"Asynchronously initializing instance \"{alias}\" \"{cInstanceSettingPath}\""); awaitingInstances.Add(StartTBotMain(cInstanceSettingPath, alias)); + //Generate random sleeptime + Random waitTime = new Random(); + int millisecondsTimeout = waitTime.Next(3, 6) * 1000; + //Put the thread to sleep + System.Threading.Thread.Sleep(millisecondsTimeout); } // Await initialization and add initialized instances diff --git a/TBot/Services/TBotMain.cs b/TBot/Services/TBotMain.cs index 4e5959fe..f183f2d0 100644 --- a/TBot/Services/TBotMain.cs +++ b/TBot/Services/TBotMain.cs @@ -185,6 +185,7 @@ private async Task InitializeOgame() { _ogameService.Initialize(GetCredentialsFromSettings(), GetDeviceFromSettings(), proxy, (string) host, int.Parse(port), (string) captchaKey); + await Task.Delay(RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds)); } private async Task ResolveCaptcha() { From 890c1a42c29cb252a28e6d818f16f71eb4da3084 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Thu, 30 Oct 2025 16:18:19 +0100 Subject: [PATCH 103/117] v3.3.5 * delay instance loading * Add a Telegram command to collect resources without MinimumResources /collectall * Update the implementation of LFBonuses Expeditions now use the LFExpeditionBonus bonus, certain cost and duration bonuses are applied, and upgraded ships are finally recognized. --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index e35f4be4..3d02ba3b 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.3.4 + 3.3.5 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.3.4 - 3.3.4 + 3.3.5 + 3.3.5 OGame Bot False ELK-Lab.pfx From 467319539c417d97e99294afdb591e7fa9afa10e Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 10 Dec 2025 11:42:29 +0100 Subject: [PATCH 104/117] * v3.3.6 * fix login issue * update ogemd deps * delay ogamed login to prevent login measurements --- TBot/Services/InstanceManager.cs | 2 +- TBot/TBot.csproj | 6 +++--- ogame | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/TBot/Services/InstanceManager.cs b/TBot/Services/InstanceManager.cs index a3f4ab20..f06c6e6c 100644 --- a/TBot/Services/InstanceManager.cs +++ b/TBot/Services/InstanceManager.cs @@ -151,7 +151,7 @@ public async void OnSettingsChanged() { awaitingInstances.Add(StartTBotMain(cInstanceSettingPath, alias)); //Generate random sleeptime Random waitTime = new Random(); - int millisecondsTimeout = waitTime.Next(3, 6) * 1000; + int millisecondsTimeout = waitTime.Next(30, 60) * 1000; //Put the thread to sleep System.Threading.Thread.Sleep(millisecondsTimeout); } diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 3d02ba3b..1d40f446 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.3.5 + 3.3.6 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.3.5 - 3.3.5 + 3.3.6 + 3.3.6 OGame Bot False ELK-Lab.pfx diff --git a/ogame b/ogame index ba8df9ac..af553018 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit ba8df9ac49b457b08aa6c5eef5270f59d6e43d7d +Subproject commit af553018498cddf36fcfa7f8d01cd085f99094cf From fd9f38e206368af7a9d856a7d8ddaad555d2598d Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Wed, 4 Feb 2026 18:04:12 +0100 Subject: [PATCH 105/117] v3.3.7 * update fix ogamed login issues --- TBot/TBot.csproj | 4 ++-- ogame | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 1d40f446..8519e699 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,14 +5,14 @@ net9.0 disable TBot - 3.3.6 + 3.3.7 Tbot.Program AnyCPU;x64;x86 2025 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.3.6 + 3.3.7 3.3.6 OGame Bot False diff --git a/ogame b/ogame index af553018..a7eed63e 160000 --- a/ogame +++ b/ogame @@ -1 +1 @@ -Subproject commit af553018498cddf36fcfa7f8d01cd085f99094cf +Subproject commit a7eed63e62de4e7092a97d7a786221a0abc15559 From 8ca809b7bb2666775ffa1472a6ca60fc1031e3f6 Mon Sep 17 00:00:00 2001 From: Killer Date: Fri, 20 Feb 2026 22:54:20 +0100 Subject: [PATCH 106/117] Refactor AutoDiscoveryWorker logic and cleanup --- TBot/Workers/AutoDiscoveryWorker.cs | 466 ++++++++++++++++++++-------- 1 file changed, 345 insertions(+), 121 deletions(-) diff --git a/TBot/Workers/AutoDiscoveryWorker.cs b/TBot/Workers/AutoDiscoveryWorker.cs index df06f277..e4b2c261 100644 --- a/TBot/Workers/AutoDiscoveryWorker.cs +++ b/TBot/Workers/AutoDiscoveryWorker.cs @@ -21,6 +21,21 @@ public class AutoDiscoveryWorker : WorkerBase { private readonly IFleetScheduler _fleetScheduler; private readonly ICalculationService _calculationService; private readonly ITBotOgamedBridge _tbotOgameBridge; + + private sealed class OriginCursor { + public int System; + public int NextPosition; + } + private readonly Dictionary _originCursors = new(); + + private sealed class DiscoveryRunContext { + public int FleetsToSend; + public bool Stop; + public int Skips; + public int GlobalAttempts; + public int MaxGlobalAttempts; + } + public AutoDiscoveryWorker(ITBotMain parentInstance, IOgameService ogameService, IFleetScheduler fleetScheduler, @@ -33,170 +48,379 @@ public AutoDiscoveryWorker(ITBotMain parentInstance, _tbotOgameBridge = tbotOgameBridge; } + private sealed class CoordinateComparer : IEqualityComparer { + public bool Equals(Coordinate x, Coordinate y) { + if (ReferenceEquals(x, y)) return true; + if (x is null || y is null) return false; + return x.Galaxy == y.Galaxy && x.System == y.System && x.Position == y.Position && x.Type == y.Type; + } + + public int GetHashCode(Coordinate obj) { + if (obj is null) return 0; + unchecked { + int hash = 17; + hash = hash * 31 + obj.Galaxy.GetHashCode(); + hash = hash * 31 + obj.System.GetHashCode(); + hash = hash * 31 + obj.Position.GetHashCode(); + hash = hash * 31 + obj.Type.GetHashCode(); + return hash; + } + } + } + + private static readonly IEqualityComparer _coordinateComparer = new CoordinateComparer(); + + private void EnsureBlacklistInitialized() { + if (_tbotInstance?.UserData == null) return; + + if (_tbotInstance.UserData.discoveryBlackList == null) { + _tbotInstance.UserData.discoveryBlackList = new Dictionary(_coordinateComparer); + return; + } + + if (!ReferenceEquals(_tbotInstance.UserData.discoveryBlackList.Comparer, _coordinateComparer)) { + var old = _tbotInstance.UserData.discoveryBlackList; + var fresh = new Dictionary(_coordinateComparer); + foreach (var kv in old) { + + if (fresh.TryGetValue(kv.Key, out var existing)) { + if (kv.Value > existing) fresh[kv.Key] = kv.Value; + } else { + fresh[kv.Key] = kv.Value; + } + } + _tbotInstance.UserData.discoveryBlackList = fresh; + } + } + + private void CleanupExpiredBlacklistAll(DateTime now) { + if (_tbotInstance?.UserData?.discoveryBlackList == null) return; + var toRemove = _tbotInstance.UserData.discoveryBlackList + .Where(kv => kv.Value <= now) + .Select(kv => kv.Key) + .ToList(); + foreach (var k in toRemove) + _tbotInstance.UserData.discoveryBlackList.Remove(k); + } + + private bool IsBlacklistedAndActive(Coordinate c, DateTime now) { + if (_tbotInstance?.UserData?.discoveryBlackList == null) return false; + return _tbotInstance.UserData.discoveryBlackList.TryGetValue(c, out var until) && until > now; + } + + private void UpsertBlacklist(Coordinate c, DateTime until) { + if (_tbotInstance?.UserData?.discoveryBlackList == null) return; + _tbotInstance.UserData.discoveryBlackList[c] = until; + } + + private List GetConfiguredOrigins(List celestials) { + var result = new List(); + if (celestials == null || celestials.Count == 0) return result; + + var originsCfg = _tbotInstance?.InstanceSettings?.AutoDiscovery?.Origin; + if (originsCfg == null) return result; + + foreach (var o in originsCfg) { + int galaxy = Convert.ToInt32(o.Galaxy); + int system = Convert.ToInt32(o.System); + int position = Convert.ToInt32(o.Position); + string typeStr = Convert.ToString(o.Type) ?? "Planet"; + + Celestials wantedType = Celestials.Planet; + if (Enum.TryParse(typeStr, true, out Celestials parsed)) + wantedType = parsed; + + var found = celestials.FirstOrDefault(c => + c?.Coordinate != null && + c.Coordinate.Galaxy == galaxy && + c.Coordinate.System == system && + c.Coordinate.Position == position && + c.Coordinate.Type == wantedType + ); + + if (found != null) + result.Add(found); + else + _tbotInstance.log(LogLevel.Warning, LogSender.AutoDiscovery, + $"AutoDiscovery origin not found in user celestials: {galaxy}:{system}:{position} ({typeStr})"); + } + + return result; + } + + private string OriginKey(Celestial origin) { + + return $"{origin.Coordinate.Galaxy}:{origin.Coordinate.System}:{origin.Coordinate.Position}:{origin.Coordinate.Type}"; + } + + private OriginCursor GetOrInitCursor(Celestial origin) { + var key = OriginKey(origin); + if (!_originCursors.TryGetValue(key, out var cursor) || cursor == null) { + cursor = new OriginCursor { + System = origin.Coordinate.System, + NextPosition = 1 + }; + _originCursors[key] = cursor; + } + + int maxSystem = _tbotInstance.UserData.serverData.Systems; + if (cursor.System < 1 || cursor.System > maxSystem) cursor.System = origin.Coordinate.System; + if (cursor.NextPosition < 1 || cursor.NextPosition > 15) cursor.NextPosition = 1; + + return cursor; + } + + private int AdvanceSystem(int system) { + int maxSystem = _tbotInstance.UserData.serverData.Systems; + system++; + if (system > maxSystem) system = 1; + return system; + } + + private async Task ProcessOneSystemForOrigin( + Celestial origin, + OriginCursor cursor, + int discoveries, + DiscoveryRunContext ctx) { + + if (origin?.Coordinate == null) return discoveries; + if (discoveries <= 0 || ctx.FleetsToSend <= 0 || ctx.Stop) return discoveries; + + int systemToDo = cursor.System; + + DateTime now = await _tbotOgameBridge.GetDateTime(); + int resumeNextPos = cursor.NextPosition; + for (int pos = cursor.NextPosition; pos <= 15; pos++) { + resumeNextPos = pos; + + if (discoveries <= 0 || ctx.FleetsToSend <= 0 || ctx.Stop) break; + if (_tbotInstance.UserData.slots.Free <= (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { ctx.Stop = true; break; } + + if (++ctx.GlobalAttempts > ctx.MaxGlobalAttempts) { ctx.Stop = true; break; } + + var dest = new Coordinate { + Galaxy = origin.Coordinate.Galaxy, + System = systemToDo, + Position = pos, + Type = Celestials.Planet + }; + + if (IsBlacklistedAndActive(dest, now)) { ctx.Skips++; continue; } + + var ok = await _ogameService.SendDiscovery(origin, dest); + if (!ok) { + DoLog(LogLevel.Warning, $"Failed to send discovery fleet to {dest} from {origin}."); + UpsertBlacklist(dest, now.AddDays(7)); + } else { + DoLog(LogLevel.Information, $"Discovery fleet sent to {dest} from {origin}."); + UpsertBlacklist(dest, now.AddDays(7)); + discoveries--; + ctx.FleetsToSend--; + } + + resumeNextPos = pos + 1; + + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + } + + if (!ctx.Stop && resumeNextPos > 15 && discoveries > 0 && ctx.FleetsToSend > 0 && + _tbotInstance.UserData.slots.Free > (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { + + cursor.System = AdvanceSystem(systemToDo); + cursor.NextPosition = 1; + } else { + + if (resumeNextPos < 1) resumeNextPos = 1; + if (resumeNextPos > 15) resumeNextPos = 15; + cursor.NextPosition = resumeNextPos; + } + + return discoveries; + } + + + private long CalcFallbackIntervalMs() { + return RandomizeHelper.CalcRandomInterval( + (int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, + (int)_tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax + ); + } + + private long CalcNextIntervalFromDiscoveryFleetsOrFallback() { + var discFleet = _tbotInstance.UserData.fleets + .Where(f => f.Mission == Missions.Discovery && f.BackIn.HasValue) + .OrderBy(f => f.BackIn.Value) + .FirstOrDefault(); + + if (discFleet == null) return CalcFallbackIntervalMs(); + + long backInSec = discFleet.BackIn ?? 0; + long interval = backInSec * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + if (interval <= 0) interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + return interval; + } + protected override async Task Execute() { bool delay = false; bool stop = false; int skips = 0; - var rand = new Random(); + try { DoLog(LogLevel.Information, $"Starting AutoDiscovery..."); - if (_tbotInstance.UserData.discoveryBlackList == null) { - _tbotInstance.UserData.discoveryBlackList = new Dictionary(); - } - if (!_tbotInstance.UserData.isSleeping) { - if ((bool) _tbotInstance.InstanceSettings.SleepMode.Active) { - DateTime.TryParse((string) _tbotInstance.InstanceSettings.SleepMode.GoToSleep, out DateTime goToSleep); - DateTime.TryParse((string) _tbotInstance.InstanceSettings.SleepMode.WakeUp, out DateTime wakeUp); - DateTime timeSleep = await _tbotOgameBridge.GetDateTime(); - if (GeneralHelper.ShouldSleep(timeSleep, goToSleep, wakeUp)) { - DoLog(LogLevel.Warning, "Unable to send discovery fleet: bed time has passed"); - stop = true; - return; - } - } - _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - List rankSlotsPriority = new() { - new RankSlotsPriority(Feature.BrainAutoMine, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, ((bool)_tbotInstance.InstanceSettings.Brain.Active && (bool)_tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool)_tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), (int)_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), - new RankSlotsPriority(Feature.Expeditions, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, (bool)_tbotInstance.InstanceSettings.Expeditions.Active, (int)_tbotInstance.UserData.slots.ExpTotal, (int)_tbotInstance.UserData.slots.ExpInUse), - new RankSlotsPriority(Feature.AutoFarm, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, (bool)_tbotInstance.InstanceSettings.AutoFarm.Active, (int)_tbotInstance.InstanceSettings.AutoFarm.MaxSlots, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), - new RankSlotsPriority(Feature.Colonize, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, (bool)_tbotInstance.InstanceSettings.AutoColonize.Active, (bool)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : 1, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), - new RankSlotsPriority(Feature.AutoDiscovery, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, (bool)_tbotInstance.InstanceSettings.AutoDiscovery.Active, (int)_tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), - new RankSlotsPriority(Feature.Harvest, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, (bool)_tbotInstance.InstanceSettings.AutoHarvest.Active, (int)_tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) - }; - int fleetsToSend = _calculationService.CalcSlotsPriority(Feature.AutoDiscovery, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); - - if (fleetsToSend <= 0) { - delay = true; - return; - } + EnsureBlacklistInitialized(); - var celestials = await _ogameService.GetCelestials(); - var configureddestinationCoord = _tbotInstance.InstanceSettings.AutoDiscovery.Origin; - Celestial origin = celestials.FirstOrDefault(c => c.Coordinate.Galaxy == configureddestinationCoord.Galaxy && - c.Coordinate.System == configureddestinationCoord.System && - c.Coordinate.Position == configureddestinationCoord.Position && - c.Coordinate.Type.ToString().Equals(configureddestinationCoord.Type, StringComparison.OrdinalIgnoreCase)); + if (_tbotInstance.UserData.isSleeping) { + stop = true; + return; + } - if (origin == null) { + if ((bool)_tbotInstance.InstanceSettings.SleepMode.Active) { + DateTime.TryParse((string)_tbotInstance.InstanceSettings.SleepMode.GoToSleep, out DateTime goToSleep); + DateTime.TryParse((string)_tbotInstance.InstanceSettings.SleepMode.WakeUp, out DateTime wakeUp); + DateTime timeSleep = await _tbotOgameBridge.GetDateTime(); + if (GeneralHelper.ShouldSleep(timeSleep, goToSleep, wakeUp)) { + DoLog(LogLevel.Warning, "Unable to send discovery fleet: bed time has passed"); stop = true; - DoLog(LogLevel.Warning, "Unable to parse AutoDiscovery origin"); return; } + } + + DateTime now = await _tbotOgameBridge.GetDateTime(); + CleanupExpiredBlacklistAll(now); + + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + + List rankSlotsPriority = new() { + new RankSlotsPriority(Feature.BrainAutoMine, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool)_tbotInstance.InstanceSettings.Brain.Active && (bool)_tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool)_tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int)_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport) + ), + new RankSlotsPriority(Feature.Expeditions, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool)_tbotInstance.InstanceSettings.Expeditions.Active, + (int)_tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.UserData.slots.ExpInUse + ), + new RankSlotsPriority(Feature.AutoFarm, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool)_tbotInstance.InstanceSettings.AutoFarm.Active, + (int)_tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack) + ), + new RankSlotsPriority(Feature.Colonize, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool)_tbotInstance.InstanceSettings.AutoColonize.Active, + (bool)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? (int)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : 1, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize) + ), + new RankSlotsPriority(Feature.AutoDiscovery, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool)_tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int)_tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery) + ), + new RankSlotsPriority(Feature.Harvest, (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool)_tbotInstance.InstanceSettings.AutoHarvest.Active, + (int)_tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest) + ) + }; + + int fleetsToSend = _calculationService.CalcSlotsPriority( + Feature.AutoDiscovery, rankSlotsPriority, + _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, + (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree + ); + + if (fleetsToSend <= 0) { + delay = true; + return; + } + + var celestials = await _ogameService.GetCelestials(); + var origins = GetConfiguredOrigins(celestials); + + if (origins == null || origins.Count == 0) { + stop = true; + DoLog(LogLevel.Warning, "Unable to parse AutoDiscovery origin."); + return; + } + + var ctx = new DiscoveryRunContext { + FleetsToSend = fleetsToSend, + Stop = false, + Skips = 0, + GlobalAttempts = 0, + MaxGlobalAttempts = 600 + }; + + foreach (var origin in origins) { + if (ctx.Stop) break; + if (ctx.FleetsToSend <= 0) break; + if (origin?.Coordinate == null) continue; int discoveries = await _ogameService.GetAvailableDiscoveries(origin); if (discoveries <= 0) { - DoLog(LogLevel.Information, "No discoveries available at the moment."); - stop = true; - return; - } - DoLog(LogLevel.Information, $"There are {discoveries} discoveries available."); - - List destinationCoord = new(); - if (!((bool) _tbotInstance.InstanceSettings.AutoDiscovery.RandomizeDestination)) { - int maxGalaxy = _tbotInstance.UserData.serverData.Galaxies; - int maxSystem = _tbotInstance.UserData.serverData.Systems; - for (int galaxy = 1; galaxy <= maxGalaxy; galaxy++) { - for (int system = 1; system <= maxSystem; system++) { - for (int position = 1; position <= 15; position++) { - destinationCoord.Add(new Coordinate { Galaxy = galaxy, System = system, Position = position }); - } - } - } - destinationCoord = destinationCoord.Where(c => !_tbotInstance.UserData.discoveryBlackList.ContainsKey(c)) - .OrderBy(c => _calculationService.CalcDistance(new(origin.Coordinate.Galaxy, origin.Coordinate.System), c, _tbotInstance.UserData.serverData)) - .ToList(); + DoLog(LogLevel.Information, $"No discoveries available from {origin} right now."); + continue; } - while (discoveries > 0 && !stop && fleetsToSend > 0 && _tbotInstance.UserData.slots.Free > (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - Coordinate dest; - if ((bool) _tbotInstance.InstanceSettings.AutoDiscovery.RandomizeDestination) { - dest = new() { Galaxy = origin.Coordinate.Galaxy, System = Random.Shared.Next(1, _tbotInstance.UserData.serverData.Systems + 1), Position = Random.Shared.Next(1, 16) - }; - } else { - dest = destinationCoord.First(); - destinationCoord.RemoveAt(0); - } - Coordinate blacklistedCoord = _tbotInstance.UserData.discoveryBlackList.Keys.SingleOrDefault(c => c.Galaxy == dest.Galaxy && c.System == dest.System && c.Position == dest.Position); - if (blacklistedCoord != null) { - if (_tbotInstance.UserData.discoveryBlackList[blacklistedCoord] > DateTime.Now) { - skips++; - continue; - } else { - _tbotInstance.UserData.discoveryBlackList.Remove(blacklistedCoord); - } - } - - var result = await _ogameService.SendDiscovery(origin, dest); - if (!result) { - DoLog(LogLevel.Warning, $"Failed to send discovery fleet to {dest.ToString()} from {origin.ToString()}."); - _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(7)); - } else { - DoLog(LogLevel.Information, $"Discovery fleet sent to {dest.ToString()} from {origin.ToString()}."); - _tbotInstance.UserData.discoveryBlackList.Add(dest, DateTime.Now.AddDays(7)); - discoveries--; - fleetsToSend--; - } - - if (_tbotInstance.UserData.slots.Free <= (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree) { - DoLog(LogLevel.Information, "No more fleet slots available for AutoDiscovery in this cycle."); - stop = true; - break; - } - _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - } - - if (skips > 0) - DoLog(LogLevel.Information, $"{skips} positions skipped (blacklisted)"); + var cursor = GetOrInitCursor(origin); + DoLog(LogLevel.Information, $"Origin {origin} cursor system={cursor.System}, nextPos={cursor.NextPosition} (discoveries={discoveries})"); - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - long interval = (_tbotInstance.UserData.fleets.Where(f => f.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).ToList().First().BackIn *1000 ?? 0) + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds);; - DateTime time = await _tbotOgameBridge.GetDateTime(); - if (interval < 0) - interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - time = time.AddMilliseconds(interval); - ChangeWorkerPeriod(interval); - DoLog(LogLevel.Information, $"Next check at {time.ToString()}"); - await _tbotOgameBridge.CheckCelestials(); - } else { - stop = true; + discoveries = await ProcessOneSystemForOrigin(origin, cursor, discoveries, ctx); + + fleetsToSend = ctx.FleetsToSend; + stop = ctx.Stop; + skips = ctx.Skips; } - } catch (Exception e) { + + if (skips > 0) + DoLog(LogLevel.Information, $"{skips} positions skipped (blacklisted)"); + + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + + long interval = CalcNextIntervalFromDiscoveryFleetsOrFallback(); + DateTime time = await _tbotOgameBridge.GetDateTime(); + var nextTime = time.AddMilliseconds(interval); + + ChangeWorkerPeriod(interval); + DoLog(LogLevel.Information, $"Next AutoDiscovery check at {nextTime.ToString()}"); + await _tbotOgameBridge.CheckCelestials(); + } catch (Exception e) { DoLog(LogLevel.Error, $"An error occured: {e.Message}"); DoLog(LogLevel.Debug, e.StackTrace); - } finally { + } finally { if (stop) { DoLog(LogLevel.Information, $"Stopping feature."); await EndExecution(); } + if (delay) { DoLog(LogLevel.Information, $"Delaying..."); var timeDelay = await _tbotOgameBridge.GetDateTime(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - long intervalDelay = 0; - try { - intervalDelay = (_tbotInstance.UserData.fleets.Where(fleet => fleet.Mission == Missions.Discovery).OrderByDescending(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - } catch { - intervalDelay = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.AutoDiscovery.CheckIntervalMax); - } + + long intervalDelay = CalcNextIntervalFromDiscoveryFleetsOrFallback(); var newTimeDelay = timeDelay.AddMilliseconds(intervalDelay); + ChangeWorkerPeriod(intervalDelay); DoLog(LogLevel.Information, $"Next AutoDiscovery check at {newTimeDelay.ToString()}"); } + await _tbotOgameBridge.CheckCelestials(); } } public override bool IsWorkerEnabledBySettings() { try { - return - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active - ; + return (bool)_tbotInstance.InstanceSettings.AutoDiscovery.Active; } catch (Exception) { return false; } } + public override string GetWorkerName() { return "AutoDiscovery"; } From a98144ecdf236b22d0bb49fa1366234cc9d1bb58 Mon Sep 17 00:00:00 2001 From: Killer Date: Fri, 20 Feb 2026 23:16:51 +0100 Subject: [PATCH 107/117] Update UserData service --- TBot/Services/UserData.cs | 54 ++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/TBot/Services/UserData.cs b/TBot/Services/UserData.cs index 228a821d..2330f71f 100644 --- a/TBot/Services/UserData.cs +++ b/TBot/Services/UserData.cs @@ -9,31 +9,33 @@ namespace Tbot.Services { - // Data required by TBotMain instances - public class UserData { - public Server serverInfo = new(); - public ServerData serverData; - public UserInfo userInfo; - public AllianceClass allianceClass; - public List celestials; - public List fleets; - public List attacks; - public Slots slots; - public Researches researches; + public class UserData { + public Server serverInfo = new(); + public ServerData serverData; + public UserInfo userInfo; + public AllianceClass allianceClass; + public List celestials; + public List fleets; + public List attacks; + public Slots slots; + public Researches researches; - public List scheduledFleets; - public List farmTargets; - public Dictionary discoveryBlackList; - public float lastDOIR; - public float nextDOIR; - public Staff staff; - public bool isSleeping = false; - } + public List scheduledFleets; + public List farmTargets; + public Dictionary discoveryBlackList; + public float lastDOIR; + public float nextDOIR; + public Staff staff; + public bool isSleeping = false; - // Data used by TelegramMessenger binded to TBotMain - public class TelegramUserData { - public Celestial CurrentCelestial; // Willingly left to null - public Celestial CurrentCelestialToSave; // Willingly left to null - public Missions Mission = Missions.None; - } -} + public int autoFarmLastGalaxy = 0; + public int autoFarmLastSystem = 0; + public int autoFarmLastRangeIndex = 0; + } + + public class TelegramUserData { + public Celestial CurrentCelestial; + public Celestial CurrentCelestialToSave; + public Missions Mission = Missions.None; + } +} \ No newline at end of file From deeee4b93e13cc08012d4dac884f64c34633d13f Mon Sep 17 00:00:00 2001 From: Killer Date: Fri, 20 Feb 2026 23:27:24 +0100 Subject: [PATCH 108/117] Add Model folder with AutoFarm state models --- TBot/Model/AutoFarmBlacklist.cs | 168 +++++++ TBot/Model/AutoFarmSuccessfulTargets.cs | 306 ++++++++++++ TBot/Model/SharedFarmState.cs | 601 ++++++++++++++++++++++++ 3 files changed, 1075 insertions(+) create mode 100644 TBot/Model/AutoFarmBlacklist.cs create mode 100644 TBot/Model/AutoFarmSuccessfulTargets.cs create mode 100644 TBot/Model/SharedFarmState.cs diff --git a/TBot/Model/AutoFarmBlacklist.cs b/TBot/Model/AutoFarmBlacklist.cs new file mode 100644 index 00000000..2a17ff72 --- /dev/null +++ b/TBot/Model/AutoFarmBlacklist.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Newtonsoft.Json; +using TBot.Ogame.Infrastructure.Models; + +namespace TBot.Model { + public enum BlacklistReason { + HasFleet, + HasDefense, + LowResources, + ManuallyAdded + } + + public class BlacklistedTarget { + public Coordinate Coordinate { get; set; } + public BlacklistReason Reason { get; set; } + public DateTime BlacklistedAt { get; set; } + public DateTime ExpiresAt { get; set; } + + public BlacklistedTarget() { + } + + public BlacklistedTarget(Coordinate coordinate, BlacklistReason reason, DateTime expiresAt) { + Coordinate = coordinate; + Reason = reason; + BlacklistedAt = DateTime.UtcNow; + ExpiresAt = expiresAt; + } + + public bool IsExpired() { + return DateTime.UtcNow >= ExpiresAt; + } + } + + public class AutoFarmBlacklist { + private List _blacklistedTargets; + private readonly object _lock = new object(); + private string _filePath; + + public AutoFarmBlacklist() { + _blacklistedTargets = new List(); + } + + public AutoFarmBlacklist(string filePath) { + string dataFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data"); + if (!Directory.Exists(dataFolder)) { + Directory.CreateDirectory(dataFolder); + } + _filePath = Path.Combine(dataFolder, filePath); + _blacklistedTargets = new List(); + LoadFromFile(); + } + + public void AddTarget(Coordinate coordinate, BlacklistReason reason, int hoursUntilReset) { + lock (_lock) { + _blacklistedTargets.RemoveAll(t => t.Coordinate.Galaxy == coordinate.Galaxy + && t.Coordinate.System == coordinate.System + && t.Coordinate.Position == coordinate.Position); + + DateTime expiresAt = DateTime.UtcNow.AddHours(hoursUntilReset); + _blacklistedTargets.Add(new BlacklistedTarget(coordinate, reason, expiresAt)); + SaveToFile(); + } + } + + public bool IsBlacklisted(Coordinate coordinate) { + lock (_lock) { + CleanupExpiredTargets(); + + return _blacklistedTargets.Any(t => + t.Coordinate.Galaxy == coordinate.Galaxy + && t.Coordinate.System == coordinate.System + && t.Coordinate.Position == coordinate.Position); + } + } + + public BlacklistedTarget GetBlacklistedTarget(Coordinate coordinate) { + lock (_lock) { + CleanupExpiredTargets(); + + return _blacklistedTargets.FirstOrDefault(t => + t.Coordinate.Galaxy == coordinate.Galaxy + && t.Coordinate.System == coordinate.System + && t.Coordinate.Position == coordinate.Position); + } + } + + public void RemoveTarget(Coordinate coordinate) { + lock (_lock) { + _blacklistedTargets.RemoveAll(t => + t.Coordinate.Galaxy == coordinate.Galaxy + && t.Coordinate.System == coordinate.System + && t.Coordinate.Position == coordinate.Position); + } + SaveToFile(); + } + + public void ClearAll() { + lock (_lock) { + _blacklistedTargets.Clear(); + } + SaveToFile(); + } + + public int GetBlacklistedCount() { + lock (_lock) { + CleanupExpiredTargets(); + return _blacklistedTargets.Count; + } + } + + public List GetAllBlacklisted() { + lock (_lock) { + CleanupExpiredTargets(); + return new List(_blacklistedTargets); + } + } + + private void CleanupExpiredTargets() { + _blacklistedTargets.RemoveAll(t => t.IsExpired()); + } + + public void ManualCleanup() { + lock (_lock) { + CleanupExpiredTargets(); + } + } + private void LoadFromFile() { + if (string.IsNullOrEmpty(_filePath) || !File.Exists(_filePath)) { + return; + } + + try { + string json = File.ReadAllText(_filePath); + var loaded = JsonConvert.DeserializeObject>(json); + if (loaded != null) { + lock (_lock) { + _blacklistedTargets = loaded; + CleanupExpiredTargets(); + } + } + } catch (Exception) { + lock (_lock) { + _blacklistedTargets = new List(); + } +} + } + + private void SaveToFile() { + if (string.IsNullOrEmpty(_filePath)) { + return; + } + + List snapshot; + lock (_lock) { + snapshot = _blacklistedTargets.ToList(); + } + + try { + string json = JsonConvert.SerializeObject(snapshot, Formatting.Indented); + File.WriteAllText(_filePath, json); + } catch (Exception) { + } + } + } +} diff --git a/TBot/Model/AutoFarmSuccessfulTargets.cs b/TBot/Model/AutoFarmSuccessfulTargets.cs new file mode 100644 index 00000000..eef9351b --- /dev/null +++ b/TBot/Model/AutoFarmSuccessfulTargets.cs @@ -0,0 +1,306 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Newtonsoft.Json; +using TBot.Ogame.Infrastructure.Models; + +namespace TBot.Model +{ + public class SuccessfulTarget + { + public string Coordinate { get; set; } + public DateTime FirstAttacked { get; set; } + public DateTime LastAttacked { get; set; } + public int TimesAttacked { get; set; } + public Resources TotalLootCollected { get; set; } + public Resources AverageLoot { get; set; } + + public SuccessfulTarget() + { + TotalLootCollected = new Resources(); + AverageLoot = new Resources(); + } + + public SuccessfulTarget(string coordinate, Resources loot) + { + Coordinate = coordinate; + FirstAttacked = DateTime.UtcNow; + LastAttacked = DateTime.UtcNow; + TimesAttacked = 1; + + TotalLootCollected = new Resources + { + Metal = loot.Metal, + Crystal = loot.Crystal, + Deuterium = loot.Deuterium + }; + + AverageLoot = new Resources + { + Metal = loot.Metal, + Crystal = loot.Crystal, + Deuterium = loot.Deuterium + }; + } + + public void AddAttack(Resources loot) + { + LastAttacked = DateTime.UtcNow; + TimesAttacked++; + + TotalLootCollected.Metal += loot.Metal; + TotalLootCollected.Crystal += loot.Crystal; + TotalLootCollected.Deuterium += loot.Deuterium; + + AverageLoot.Metal = TotalLootCollected.Metal / TimesAttacked; + AverageLoot.Crystal = TotalLootCollected.Crystal / TimesAttacked; + AverageLoot.Deuterium = TotalLootCollected.Deuterium / TimesAttacked; + } + } + + public class AutoFarmSuccessfulTargets + { + private List _successfulTargets; + private readonly object _lock = new object(); + + private string _filePath; + + private DateTime _lastSaveUtc = DateTime.MinValue; + private int _pendingChanges = 0; + + private readonly TimeSpan _saveInterval = TimeSpan.FromSeconds(60); + private const int SaveAfterChanges = 20; + + private const int MaxTargets = 5000; + private readonly TimeSpan _staleCutoff = TimeSpan.FromDays(30); + + public AutoFarmSuccessfulTargets() + { + _successfulTargets = new List(); + } + + public AutoFarmSuccessfulTargets(string fileName) + { + string dataFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data"); + if (!Directory.Exists(dataFolder)) + { + Directory.CreateDirectory(dataFolder); + } + + string safeFileName = MakeSafeFileName(fileName); + _filePath = Path.Combine(dataFolder, safeFileName); + + _successfulTargets = new List(); + LoadFromFile(); + } + + public void RecordAttack(Coordinate coordinate, Resources loot) + { + lock (_lock) + { + string coordStr = $"{coordinate.Galaxy}:{coordinate.System}:{coordinate.Position}"; + + var existing = _successfulTargets.FirstOrDefault(t => t.Coordinate == coordStr); + if (existing != null) + { + existing.AddAttack(loot); + } + else + { + _successfulTargets.Add(new SuccessfulTarget(coordStr, loot)); + } + + _pendingChanges++; + + CleanupUnsafeGrowth_NoThrow(); + + SaveIfNeeded_NoThrow(); + } + } + + public SuccessfulTarget GetTarget(Coordinate coordinate) + { + lock (_lock) + { + string coordStr = $"{coordinate.Galaxy}:{coordinate.System}:{coordinate.Position}"; + return _successfulTargets.FirstOrDefault(t => t.Coordinate == coordStr); + } + } + + public List GetAllTargets() + { + lock (_lock) + { + return new List(_successfulTargets); + } + } + + public int GetTotalCount() + { + lock (_lock) + { + return _successfulTargets.Count; + } + } + + public long GetTotalLootCollected() + { + lock (_lock) + { + return _successfulTargets.Sum(t => + t.TotalLootCollected.Metal + + t.TotalLootCollected.Crystal + + t.TotalLootCollected.Deuterium + ); + } + } + + + public void ForceSave() + { + lock (_lock) + { + SaveToFile_NoThrow(force: true); + } + } + + private void LoadFromFile() + { + if (string.IsNullOrEmpty(_filePath) || !File.Exists(_filePath)) + { + return; + } + + try + { + string json = File.ReadAllText(_filePath); + var loaded = JsonConvert.DeserializeObject>(json); + if (loaded != null) + { + _successfulTargets = loaded; + } + } + catch (Exception ex) + { + _successfulTargets = new List(); + WriteError_NoThrow($"LoadFromFile failed: {ex.GetType().Name}: {ex.Message}"); + } + } + + private void SaveIfNeeded_NoThrow() + { + if (string.IsNullOrEmpty(_filePath)) + return; + + var now = DateTime.UtcNow; + + bool timeDue = (now - _lastSaveUtc) >= _saveInterval; + bool changesDue = _pendingChanges >= SaveAfterChanges; + + if (timeDue || changesDue) + { + SaveToFile_NoThrow(force: false); + } + } + + private void SaveToFile_NoThrow(bool force) + { + if (string.IsNullOrEmpty(_filePath)) + return; + + try + { + if (!force && _pendingChanges <= 0) + return; + + string json = JsonConvert.SerializeObject(_successfulTargets, Formatting.Indented); + + string tmpPath = _filePath + ".tmp"; + + File.WriteAllText(tmpPath, json); + + if (File.Exists(_filePath)) + { + try + { + File.Replace(tmpPath, _filePath, null); + } + catch + { + File.Delete(_filePath); + File.Move(tmpPath, _filePath); + } + } + else + { + File.Move(tmpPath, _filePath); + } + + _lastSaveUtc = DateTime.UtcNow; + _pendingChanges = 0; + } + catch (Exception ex) + { + WriteError_NoThrow($"SaveToFile failed: {ex.GetType().Name}: {ex.Message}"); + } + } + + private void CleanupUnsafeGrowth_NoThrow() + { + try + { + var cutoff = DateTime.UtcNow - _staleCutoff; + _successfulTargets.RemoveAll(t => t.LastAttacked < cutoff); + + if (_successfulTargets.Count > MaxTargets) + { + _successfulTargets = _successfulTargets + .OrderByDescending(t => t.LastAttacked) + .Take(MaxTargets) + .ToList(); + } + } + catch (Exception ex) + { + WriteError_NoThrow($"Cleanup failed: {ex.GetType().Name}: {ex.Message}"); + } + } + + private static string MakeSafeFileName(string fileName) + { + if (string.IsNullOrWhiteSpace(fileName)) + return "autofarm_successful_targets.json"; + + string name = Path.GetFileName(fileName); + + if (!name.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) + name += ".json"; + + foreach (char c in Path.GetInvalidFileNameChars()) + { + name = name.Replace(c, '_'); + } + + return name; + } + + private void WriteError_NoThrow(string message) + { + try + { + string baseDir = Path.GetDirectoryName(_filePath); + if (string.IsNullOrEmpty(baseDir)) + return; + + string errPath = Path.Combine(baseDir, "autofarm_successful_targets.errors.log"); + string line = $"[{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC] {message}{Environment.NewLine}"; + File.AppendAllText(errPath, line); + } + catch + { + + } + } + } +} diff --git a/TBot/Model/SharedFarmState.cs b/TBot/Model/SharedFarmState.cs new file mode 100644 index 00000000..299b993c --- /dev/null +++ b/TBot/Model/SharedFarmState.cs @@ -0,0 +1,601 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using Newtonsoft.Json; +using TBot.Ogame.Infrastructure.Models; +using TBot.Ogame.Infrastructure.Enums; + +namespace TBot.Model +{ + + public class FarmBotInstance + { + public string Name { get; set; } + public DateTime LastHeartbeat { get; set; } + public bool IsActive { get; set; } + + public bool IsAlive(TimeSpan timeout) + { + return (DateTime.UtcNow - LastHeartbeat) < timeout; + } + } + + public class ScannedTarget + { + public string Coord { get; set; } + public string ScannedBy { get; set; } + public DateTime ScannedAt { get; set; } + public DateTime ExpiresAt { get; set; } + public long TotalResources { get; set; } + public bool HasFleet { get; set; } + public bool HasDefense { get; set; } + + public bool IsExpired() + { + return DateTime.UtcNow >= ExpiresAt; + } + + public Coordinate GetCoordinate() + { + if (string.IsNullOrWhiteSpace(Coord)) + return null; + + var parts = Coord.Split(':'); + if (parts.Length != 3) + return null; + + if (!int.TryParse(parts[0], out var g)) return null; + if (!int.TryParse(parts[1], out var s)) return null; + if (!int.TryParse(parts[2], out var p)) return null; + + return new Coordinate + { + Galaxy = g, + System = s, + Position = p, + Type = Celestials.Planet + }; + } + } + + public class ClaimedAttack + { + public string Coord { get; set; } + public string ClaimedBy { get; set; } + public DateTime ClaimedAt { get; set; } + public DateTime? AttackSentAt { get; set; } + public DateTime ReturnsAt { get; set; } + + public bool IsExpired() + { + if (DateTime.UtcNow >= ReturnsAt) + return true; + + if (!AttackSentAt.HasValue && (DateTime.UtcNow - ClaimedAt).TotalHours > 2) + return true; + + return false; + } + + public Coordinate GetCoordinate() + { + if (string.IsNullOrWhiteSpace(Coord)) + return null; + + var parts = Coord.Split(':'); + if (parts.Length != 3) + return null; + + if (!int.TryParse(parts[0], out var g)) return null; + if (!int.TryParse(parts[1], out var s)) return null; + if (!int.TryParse(parts[2], out var p)) return null; + + return new Coordinate + { + Galaxy = g, + System = s, + Position = p, + Type = Celestials.Planet + }; + } + } + + public class SharedFarmState + { + private const string DEFAULT_FILENAME = "shared_farm_state.json"; + private const int MAX_RETRY_ATTEMPTS = 5; + private const int RETRY_DELAY_MS = 100; + private const string MUTEX_GLOBAL_NAME = @"Global\TBot_SharedFarmState_Mutex"; + private const string MUTEX_LOCAL_NAME = @"Local\TBot_SharedFarmState_Mutex"; + + public string Version { get; set; } = "1.1"; + public DateTime LastUpdated { get; set; } + public List Instances { get; set; } + public List ScannedTargets { get; set; } + public List ClaimedAttacks { get; set; } + + private static readonly object _globalLock = new object(); + private string _filePath; + + public SharedFarmState() + { + Instances = new List(); + ScannedTargets = new List(); + ClaimedAttacks = new List(); + LastUpdated = DateTime.UtcNow; + } + + public static SharedFarmState Initialize(string instanceName = null) + { + string dataFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data"); + if (!Directory.Exists(dataFolder)) + Directory.CreateDirectory(dataFolder); + + string filePath = Path.Combine(dataFolder, DEFAULT_FILENAME); + var state = LoadFromFile(filePath); + state._filePath = filePath; + + if (!string.IsNullOrEmpty(instanceName)) + { + state.UpdateInstanceHeartbeat(instanceName); + state.Save(); + } + + return state; + } + + private static SharedFarmState LoadFromFile(string filePath) + { + lock (_globalLock) + { + if (!File.Exists(filePath)) + return new SharedFarmState(); + + for (int attempt = 0; attempt < MAX_RETRY_ATTEMPTS; attempt++) + { + try + { + string json = File.ReadAllText(filePath); + var state = JsonConvert.DeserializeObject(json); + + if (state != null) + { + state._filePath = filePath; + state.CleanupExpiredEntries(); + return state; + } + } + catch (IOException) when (attempt < MAX_RETRY_ATTEMPTS - 1) + { + Thread.Sleep(RETRY_DELAY_MS * (attempt + 1)); + } + catch (JsonException) + { + try + { + string backupPath = filePath + ".corrupt." + DateTime.UtcNow.Ticks; + File.Move(filePath, backupPath); + } + catch {} + return new SharedFarmState(); + } + catch + { + return new SharedFarmState(); + } + } + + return new SharedFarmState(); + } + } + + private static Mutex CreateNamedMutex() + { + try + { + return new Mutex(false, MUTEX_GLOBAL_NAME); + } + catch + { + return new Mutex(false, MUTEX_LOCAL_NAME); + } + } + + private static bool WithCrossProcessMutex(TimeSpan timeout, Action action) + { + using (var mutex = CreateNamedMutex()) + { + try + { + if (!mutex.WaitOne(timeout)) + return false; + + try + { + action(); + return true; + } + finally + { + try { mutex.ReleaseMutex(); } catch { } + } + } + catch (AbandonedMutexException) + { + try + { + action(); + return true; + } + finally + { + try { mutex.ReleaseMutex(); } catch { } + } + } + catch + { + return false; + } + } + } + + public void Save() + { + if (string.IsNullOrEmpty(_filePath)) + return; + + WithCrossProcessMutex(TimeSpan.FromSeconds(5), () => + { + SaveNoMutex(); + }); + } + + private void SaveNoMutex() + { + lock (_globalLock) + { + LastUpdated = DateTime.UtcNow; + CleanupExpiredEntries(); + + string tempPath = _filePath + ".tmp"; + string backupPath = _filePath + ".bak"; + + try + { + string json = JsonConvert.SerializeObject(this, Formatting.Indented); + File.WriteAllText(tempPath, json); + + try + { + if (File.Exists(_filePath)) + File.Replace(tempPath, _filePath, backupPath, ignoreMetadataErrors: true); + else + File.Move(tempPath, _filePath); + } + catch + { + if (File.Exists(_filePath)) + File.Delete(_filePath); + + File.Move(tempPath, _filePath); + } + } + catch + { + if (File.Exists(tempPath)) + { + try { File.Delete(tempPath); } catch { } + } + } + } + } + + public void Reload() + { + if (string.IsNullOrEmpty(_filePath)) + return; + + var fresh = LoadFromFile(_filePath); + fresh._filePath = _filePath; + + Version = fresh.Version; + LastUpdated = fresh.LastUpdated; + Instances = fresh.Instances; + ScannedTargets = fresh.ScannedTargets; + ClaimedAttacks = fresh.ClaimedAttacks; + } + + public void UpdateInstanceHeartbeat(string instanceName) + { + var instance = Instances.FirstOrDefault(i => i.Name == instanceName); + if (instance == null) + { + instance = new FarmBotInstance + { + Name = instanceName, + IsActive = true + }; + Instances.Add(instance); + } + + instance.LastHeartbeat = DateTime.UtcNow; + instance.IsActive = true; + } + + public List GetActiveBots() + { + return Instances.Where(i => i.IsAlive(TimeSpan.FromMinutes(5))).ToList(); + } + + public ScannedTarget GetRecentScan(Coordinate coord, int withinHours = 8) + { + string coordStr = $"{coord.Galaxy}:{coord.System}:{coord.Position}"; + return ScannedTargets.FirstOrDefault(s => + s.Coord == coordStr && + (DateTime.UtcNow - s.ScannedAt).TotalHours < withinHours); + } + + public void AddScannedTarget(Coordinate coord, string scannedBy, long totalResources, + bool hasFleet, bool hasDefense, int expiresInHours = 8) + { + string coordStr = $"{coord.Galaxy}:{coord.System}:{coord.Position}"; + + ScannedTargets.RemoveAll(s => s.Coord == coordStr); + + ScannedTargets.Add(new ScannedTarget + { + Coord = coordStr, + ScannedBy = scannedBy, + ScannedAt = DateTime.UtcNow, + ExpiresAt = DateTime.UtcNow.AddHours(expiresInHours), + TotalResources = totalResources, + HasFleet = hasFleet, + HasDefense = hasDefense + }); + } + + public void UpdateScannedTarget(Coordinate coord, long totalResources, bool hasFleet, bool hasDefense) + { + string coordStr = $"{coord.Galaxy}:{coord.System}:{coord.Position}"; + var existing = ScannedTargets.FirstOrDefault(s => s.Coord == coordStr); + + if (existing != null) + { + existing.TotalResources = totalResources; + existing.HasFleet = hasFleet; + existing.HasDefense = hasDefense; + } + } + + public List GetGoodTargets(long minResources, int maxAgeMinutes = 30) + { + return ScannedTargets + .Where(s => !s.IsExpired()) + .Where(s => (DateTime.UtcNow - s.ScannedAt).TotalMinutes <= maxAgeMinutes) + .Where(s => s.TotalResources > 0) + .Where(s => s.TotalResources >= minResources) + .Where(s => !s.HasFleet) + .Where(s => !s.HasDefense) + .Where(s => !IsTargetClaimed(s.GetCoordinate())) + .OrderByDescending(s => s.TotalResources) + .ToList(); + } + + public List GetTargetsWithoutReports(string scannedByInstance = null) + { + var query = ScannedTargets + .Where(s => !s.IsExpired()) + .Where(s => s.TotalResources == 0); + + if (!string.IsNullOrEmpty(scannedByInstance)) + query = query.Where(s => s.ScannedBy == scannedByInstance); + + return query.OrderBy(s => s.ScannedAt).ToList(); + } + + public bool ShouldRescan(Coordinate coord, int maxAgeMinutes = 30) + { + string coordStr = $"{coord.Galaxy}:{coord.System}:{coord.Position}"; + var scan = ScannedTargets.FirstOrDefault(s => s.Coord == coordStr && !s.IsExpired()); + + if (scan == null) return true; + if (scan.TotalResources == 0) return true; + + return (DateTime.UtcNow - scan.ScannedAt).TotalMinutes > maxAgeMinutes; + } + + public bool TryClaimAttack(Coordinate coord, string claimedBy, DateTime returnsAt) + { + Reload(); + return TryClaimAttack_NoReload(coord, claimedBy, returnsAt); + } + + private bool TryClaimAttack_NoReload(Coordinate coord, string claimedBy, DateTime returnsAt) + { + string coordStr = $"{coord.Galaxy}:{coord.System}:{coord.Position}"; + + var existingClaim = ClaimedAttacks.FirstOrDefault(c => c.Coord == coordStr && !c.IsExpired()); + if (existingClaim != null && existingClaim.ClaimedBy != claimedBy) + return false; + + ClaimedAttacks.RemoveAll(c => c.Coord == coordStr); + ClaimedAttacks.Add(new ClaimedAttack + { + Coord = coordStr, + ClaimedBy = claimedBy, + ClaimedAt = DateTime.UtcNow, + AttackSentAt = null, + ReturnsAt = returnsAt + }); + + return true; + } + + public void MarkAttackSent(Coordinate coord, string claimedBy) + { + string coordStr = $"{coord.Galaxy}:{coord.System}:{coord.Position}"; + var claim = ClaimedAttacks.FirstOrDefault(c => c.Coord == coordStr && c.ClaimedBy == claimedBy); + if (claim != null) + { + claim.AttackSentAt = DateTime.UtcNow; + } + } + + public bool IsTargetClaimed(Coordinate coord) + { + if (coord == null) return false; + string coordStr = $"{coord.Galaxy}:{coord.System}:{coord.Position}"; + return ClaimedAttacks.Any(c => c.Coord == coordStr && !c.IsExpired()); + } + + public string GetClaimOwner(Coordinate coord) + { + if (coord == null) return null; + string coordStr = $"{coord.Galaxy}:{coord.System}:{coord.Position}"; + return ClaimedAttacks.FirstOrDefault(c => c.Coord == coordStr && !c.IsExpired())?.ClaimedBy; + } + + private void CleanupExpiredEntries() + { + ScannedTargets.RemoveAll(s => s.IsExpired()); + ClaimedAttacks.RemoveAll(c => c.IsExpired()); + + foreach (var instance in Instances) + { + if (!instance.IsAlive(TimeSpan.FromMinutes(5))) + instance.IsActive = false; + } + } + + public string GetStats() + { + CleanupExpiredEntries(); + return $"Instances: {Instances.Count(i => i.IsActive)} active, " + + $"Scanned: {ScannedTargets.Count}, " + + $"Claims: {ClaimedAttacks.Count}"; + } + + public static void AddScannedTargetAtomic(string filePath, Coordinate coord, string scannedBy, + long totalResources, bool hasFleet, bool hasDefense) + { + WithCrossProcessMutex(TimeSpan.FromSeconds(5), () => + { + var state = LoadFromFile(filePath); + state._filePath = filePath; + + state.AddScannedTarget(coord, scannedBy, totalResources, hasFleet, hasDefense); + state.SaveNoMutex(); + }); + } + + public static void UpdateScannedTargetAtomic(string filePath, Coordinate coord, long totalResources, bool hasFleet, bool hasDefense) + { + WithCrossProcessMutex(TimeSpan.FromSeconds(5), () => + { + var state = LoadFromFile(filePath); + state._filePath = filePath; + + state.UpdateScannedTarget(coord, totalResources, hasFleet, hasDefense); + state.SaveNoMutex(); + }); + } + + public static void MarkAttackSentAtomic(string filePath, Coordinate coord, string claimedBy) + { + WithCrossProcessMutex(TimeSpan.FromSeconds(5), () => + { + var state = LoadFromFile(filePath); + state._filePath = filePath; + + state.MarkAttackSent(coord, claimedBy); + state.SaveNoMutex(); + }); + } + + public static bool TryReserveScan(string filePath, Coordinate coord, string scannedBy, + int withinHours = 8, int maxAgeMinutes = 30) + { + bool result = false; + + bool acquired = WithCrossProcessMutex(TimeSpan.FromSeconds(5), () => + { + var state = LoadFromFile(filePath); + state._filePath = filePath; + + if (state.ShouldRescan(coord, maxAgeMinutes)) + { + state.AddScannedTarget(coord, scannedBy, 0, false, false); + state.SaveNoMutex(); + result = true; + return; + } + + string coordStr = $"{coord.Galaxy}:{coord.System}:{coord.Position}"; + var recentScan = state.ScannedTargets.FirstOrDefault(s => + s.Coord == coordStr && + (DateTime.UtcNow - s.ScannedAt).TotalHours < withinHours); + + if (recentScan != null) + { + if (recentScan.ScannedBy == scannedBy) + { + if (state.ShouldRescan(coord, maxAgeMinutes)) + { + state.AddScannedTarget(coord, scannedBy, 0, false, false); + state.SaveNoMutex(); + result = true; + return; + } + result = false; + return; + } + else + { + if ((DateTime.UtcNow - recentScan.ScannedAt).TotalMinutes <= maxAgeMinutes) + { + result = false; + return; + } + + state.AddScannedTarget(coord, scannedBy, 0, false, false); + state.SaveNoMutex(); + result = true; + return; + } + } + + state.AddScannedTarget(coord, scannedBy, 0, false, false); + state.SaveNoMutex(); + result = true; + }); + + if (!acquired) + return false; + + return result; + } + + public static bool TryClaimAttackAtomic(string filePath, Coordinate coord, string claimedBy, DateTime returnsAt) + { + bool claimed = false; + + bool acquired = WithCrossProcessMutex(TimeSpan.FromSeconds(5), () => + { + var state = LoadFromFile(filePath); + state._filePath = filePath; + + claimed = state.TryClaimAttack_NoReload(coord, claimedBy, returnsAt); + + if (claimed) + state.SaveNoMutex(); + }); + + if (!acquired) + return false; + + return claimed; + } + } +} From c9f630004f675275499268a08d7e20ab0cebc0bb Mon Sep 17 00:00:00 2001 From: Killer Date: Fri, 20 Feb 2026 23:52:40 +0100 Subject: [PATCH 109/117] Fix concurrency and async handling in DefenderWorker --- TBot/Workers/DefenderWorker.cs | 106 +++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 26 deletions(-) diff --git a/TBot/Workers/DefenderWorker.cs b/TBot/Workers/DefenderWorker.cs index 2e167bff..5d864d90 100644 --- a/TBot/Workers/DefenderWorker.cs +++ b/TBot/Workers/DefenderWorker.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Linq; using System.Text; using System.Threading; @@ -18,6 +19,9 @@ namespace Tbot.Workers { internal class DefenderWorker : WorkerBase { + private static readonly ConcurrentDictionary _handledAttackIds = new(); + private static readonly TimeSpan _handledAttackTtl = TimeSpan.FromMinutes(60); + private readonly IFleetScheduler _fleetScheduler; private readonly IOgameService _ogameService; private readonly ITBotOgamedBridge _tbotOgameBridge; @@ -41,12 +45,11 @@ protected override async Task Execute() { DateTime time = await _tbotOgameBridge.GetDateTime(); if (isUnderAttack) { if ((bool) _tbotInstance.InstanceSettings.Defender.Alarm.Active) - await Task.Factory.StartNew(() => ConsoleHelpers.PlayAlarm(), _ct); - // UpdateTitle(false, true); + await Task.Run(() => ConsoleHelpers.PlayAlarm(), _ct); DoLog(LogLevel.Warning, "ENEMY ACTIVITY!!!"); _tbotInstance.UserData.attacks = await _ogameService.GetAttacks(); foreach (AttackerFleet attack in _tbotInstance.UserData.attacks) { - HandleAttack(attack); + await HandleAttack(attack); } } else { DoLog(LogLevel.Information, "Your empire is safe"); @@ -55,7 +58,6 @@ protected override async Task Execute() { if (interval <= 0) interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - // Display dateTime for logging DateTime newTime = time.AddMilliseconds(interval); ChangeWorkerPeriod(TimeSpan.FromMilliseconds(interval)); DoLog(LogLevel.Information, $"Next check at {newTime.ToString()}"); @@ -93,8 +95,6 @@ public override LogSender GetLogSender() { private async Task FakeActivity() { - //checking if under attack by making activity on planet/moon configured in settings (otherwise make acti on latest activated planet) - // And make activity on one more random planet to fake real player Celestial celestial; Celestial randomCelestial; @@ -124,7 +124,23 @@ private async Task FakeActivity() { return; } - private async void HandleAttack(AttackerFleet attack) { + private async Task HandleAttack(AttackerFleet attack) { + try { + var nowUtc = DateTime.UtcNow; + foreach (var kv in _handledAttackIds.ToArray()) { + if (nowUtc - kv.Value > _handledAttackTtl) + _handledAttackIds.TryRemove(kv.Key, out _); + } + if (attack != null && attack.ID != 0 && + _handledAttackIds.TryGetValue(attack.ID, out var seenAt) && + (nowUtc - seenAt) <= _handledAttackTtl) { + DoLog(LogLevel.Information, $"Attack {attack.ID} already handled recently; skipping duplicate actions."); + return; + } + if (attack != null && attack.ID != 0) { + _handledAttackIds[attack.ID] = nowUtc; + } + if (_tbotInstance.UserData.celestials.Count() == 0) { DateTime time = await _tbotOgameBridge.GetDateTime(); long interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); @@ -135,20 +151,42 @@ private async void HandleAttack(AttackerFleet attack) { return; } - Celestial attackedCelestial = _tbotInstance.UserData.celestials.Unique().SingleOrDefault(planet => planet.HasCoords(attack.Destination)); + Celestial attackedCelestial = _tbotInstance.UserData.celestials.Unique().FirstOrDefault(planet => planet.HasCoords(attack.Destination)); + if (attackedCelestial == null) { + DoLog(LogLevel.Warning, $"Unable to handle attack {attack.ID}: attacked celestial not found in account data."); + return; + } attackedCelestial = await _tbotOgameBridge.UpdatePlanet(attackedCelestial, UpdateTypes.Ships); + try { + if ((bool)_tbotInstance.InstanceSettings.Defender.IgnoreAttackIfIHave.Active) { + attackedCelestial = await _tbotOgameBridge.UpdatePlanet(attackedCelestial, UpdateTypes.Resources); + } + } catch { + } + try { - if ((_tbotInstance.InstanceSettings.Defender.WhiteList as long[]).Any()) { - foreach (int playerID in (long[]) _tbotInstance.InstanceSettings.Defender.WhiteList) { - if (attack.AttackerID == playerID) { - DoLog(LogLevel.Information, $"Attack {attack.ID.ToString()} skipped: attacker {attack.AttackerName} whitelisted."); - return; - } + var wlObj = _tbotInstance.InstanceSettings.Defender.WhiteList; + IEnumerable whiteListIds = wlObj switch { + long[] a => a, + int[] a => a.Select(x => (long)x), + IEnumerable e => e, + IEnumerable e => e.Select(x => (long)x), + _ => Enumerable.Empty() + }; + + if (!whiteListIds.Any() && wlObj != null) { + DoLog(LogLevel.Debug, $"Defender WhiteList present but unsupported type: {wlObj.GetType().FullName}"); + } + + foreach (var playerId in whiteListIds) { + if (attack.AttackerID == playerId) { + DoLog(LogLevel.Information, $"Attack {attack.ID.ToString()} skipped: attacker {attack.AttackerName} whitelisted."); + return; } } - } catch { - DoLog(LogLevel.Warning, "An error has occurred while checking Defender WhiteList"); + } catch (Exception ex) { + DoLog(LogLevel.Warning, $"An error has occurred while checking Defender WhiteList: {ex.Message}"); } try { @@ -170,13 +208,17 @@ private async void HandleAttack(AttackerFleet attack) { Type = Celestials.Planet })); } - defenderCelestial = await _tbotOgameBridge.UpdatePlanet(attackedCelestial, UpdateTypes.Facilities); + if (defenderCelestial == null) { + DoLog(LogLevel.Warning, $"Missile attack detected on {attack.Destination.ToString()} but planet celestial was not found in account data. Skipping missile defence."); + return; + } + defenderCelestial = await _tbotOgameBridge.UpdatePlanet(defenderCelestial, UpdateTypes.Facilities); if (defenderCelestial.Facilities.MissileSilo >= 2) { - defenderCelestial = await _tbotOgameBridge.UpdatePlanet(attackedCelestial, UpdateTypes.Defences); - defenderCelestial = await _tbotOgameBridge.UpdatePlanet(attackedCelestial, UpdateTypes.Productions); + defenderCelestial = await _tbotOgameBridge.UpdatePlanet(defenderCelestial, UpdateTypes.Defences); + defenderCelestial = await _tbotOgameBridge.UpdatePlanet(defenderCelestial, UpdateTypes.Productions); if (defenderCelestial.Productions.Count == 0) { var availableSpace = defenderCelestial.Facilities.MissileSilo - defenderCelestial.Defences.AntiBallisticMissiles - (2 * defenderCelestial.Defences.InterplanetaryMissiles); - defenderCelestial = await _tbotOgameBridge.UpdatePlanet(attackedCelestial, UpdateTypes.Resources); + defenderCelestial = await _tbotOgameBridge.UpdatePlanet(defenderCelestial, UpdateTypes.Resources); if (availableSpace > 0) { DoLog(LogLevel.Information, $"Building {availableSpace} AntiBallisticMissiles on {defenderCelestial.ToString()}"); await _ogameService.BuildDefences(defenderCelestial, Buildables.AntiBallisticMissiles, availableSpace); @@ -214,10 +256,14 @@ private async void HandleAttack(AttackerFleet attack) { } else { DoLog(LogLevel.Information, "Unable to detect fleet composition."); } + var ignoreAttackIfIHaveActive = (bool) _tbotInstance.InstanceSettings.Defender.IgnoreAttackIfIHave.Active; + var totalResources = attackedCelestial.Resources?.TotalResources ?? 0; + var fleetPoints = attackedCelestial.Ships?.GetFleetPoints() ?? 0; + if ( - (bool) _tbotInstance.InstanceSettings.Defender.IgnoreAttackIfIHave.Active && - attackedCelestial.Resources.TotalResources < (long) _tbotInstance.InstanceSettings.Defender.IgnoreAttackIfIHave.MinResourcesToSave && - (attackedCelestial.Ships.GetFleetPoints() *1000) < (long) _tbotInstance.InstanceSettings.Defender.IgnoreAttackIfIHave.MinFleetToSave + ignoreAttackIfIHaveActive && + totalResources < (long) _tbotInstance.InstanceSettings.Defender.IgnoreAttackIfIHave.MinResourcesToSave && + (fleetPoints * 1000) < (long) _tbotInstance.InstanceSettings.Defender.IgnoreAttackIfIHave.MinFleetToSave ) { DoLog(LogLevel.Information, $"Attack {attack.ID.ToString()} skipped: it's not worth it."); return; @@ -248,8 +294,12 @@ private async void HandleAttack(AttackerFleet attack) { Coordinate destination = attack.Origin; Ships ships = new() { EspionageProbe = (int) _tbotInstance.InstanceSettings.Defender.SpyAttacker.Probes }; int fleetId = await _fleetScheduler.SendFleet(attackedCelestial, ships, destination, Missions.Spy, Speeds.HundredPercent, new Resources(), _tbotInstance.UserData.userInfo.Class); - Fleet fleet = _tbotInstance.UserData.fleets.Single(fleet => fleet.ID == fleetId); - DoLog(LogLevel.Information, $"Spying attacker from {attackedCelestial.ToString()} to {destination.ToString()} with {_tbotInstance.InstanceSettings.Defender.SpyAttacker.Probes} probes. Arrival at {fleet.ArrivalTime.ToString()}"); + var fleet = _tbotInstance.UserData.fleets.SingleOrDefault(f => f.ID == fleetId); + if (fleet == null) { + DoLog(LogLevel.Warning, $"SpyAttacker: SendFleet returned id={fleetId}, but fleet was not found in current fleet list (send may have failed or list not updated yet)."); + } else { + DoLog(LogLevel.Information, $"Spying attacker from {attackedCelestial.ToString()} to {destination.ToString()} with {_tbotInstance.InstanceSettings.Defender.SpyAttacker.Probes} probes. Arrival at {fleet.ArrivalTime.ToString()}"); + } } catch (Exception e) { DoLog(LogLevel.Error, $"Could not spy attacker: an exception has occurred: {e.Message}"); DoLog(LogLevel.Warning, $"Stacktrace: {e.StackTrace}"); @@ -289,6 +339,10 @@ private async void HandleAttack(AttackerFleet attack) { DoLog(LogLevel.Warning, $"Stacktrace: {e.StackTrace}"); } } + } catch (Exception e) { + DoLog(LogLevel.Error, $"HandleAttack error for attack {attack?.ID}: {e.Message}"); + DoLog(LogLevel.Warning, $"Stacktrace: {e.StackTrace}"); + } } } -} +} \ No newline at end of file From 5f1a4f0b5d84f9e15e4669c87d189dc1d8766a2b Mon Sep 17 00:00:00 2001 From: Killer Date: Sat, 21 Feb 2026 00:01:36 +0100 Subject: [PATCH 110/117] Refactor and improve ExpeditionWorker logic --- TBot/Workers/ExpeditionsWorker.cs | 423 ++++++++++++++++++------------ 1 file changed, 252 insertions(+), 171 deletions(-) diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index bcfa777f..ee18ad97 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -34,7 +34,7 @@ public ExpeditionsWorker(ITBotMain parentInstance, } public override bool IsWorkerEnabledBySettings() { try { - return (bool) _tbotInstance.InstanceSettings.Expeditions.Active; + return (bool)_tbotInstance.InstanceSettings.Expeditions.Active; } catch (Exception) { return false; } @@ -49,18 +49,25 @@ public override Feature GetFeature() { public override LogSender GetLogSender() { return LogSender.Expeditions; } - - + private int CountActiveExpeditionsFromOrigin(Celestial origin) { + return _tbotInstance.UserData.fleets.Count(f => + f.Mission == Missions.Expedition && + f.Origin != null && + f.Origin.Galaxy == origin.Coordinate.Galaxy && + f.Origin.System == origin.Coordinate.System && + f.Origin.Position == origin.Coordinate.Position && + (int)f.Origin.Type == (int)origin.Coordinate.Type + ); +} protected override async Task Execute() { bool stop = false; bool delay = false; try { - // Wait for the thread semaphore to avoid the concurrency with itself long interval; DateTime time; DateTime newTime; - if ((bool) _tbotInstance.InstanceSettings.Expeditions.Active) { + if ((bool)_tbotInstance.InstanceSettings.Expeditions.Active) { _tbotInstance.UserData.researches = await _tbotOgameBridge.UpdateResearches(); if (_tbotInstance.UserData.researches.Astrophysics == 0) { DoLog(LogLevel.Information, "Skipping: Astrophysics not yet researched!"); @@ -75,44 +82,54 @@ protected override async Task Execute() { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); _tbotInstance.UserData.serverData = await _ogameService.GetServerData(); + List rankSlotsPriority = new() { new RankSlotsPriority(Feature.BrainAutoMine, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, - ((bool) _tbotInstance.InstanceSettings.Brain.Active && (bool) _tbotInstance.InstanceSettings.Brain.Transports.Active && ((bool) _tbotInstance.InstanceSettings.Brain.AutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.AutoResearch.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || (bool) _tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), - (int) _tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, - (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Brain, + ((bool)_tbotInstance.InstanceSettings.Brain.Active && (bool)_tbotInstance.InstanceSettings.Brain.Transports.Active && + ((bool)_tbotInstance.InstanceSettings.Brain.AutoMine.Active || + (bool)_tbotInstance.InstanceSettings.Brain.AutoResearch.Active || + (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoMine.Active || + (bool)_tbotInstance.InstanceSettings.Brain.LifeformAutoResearch.Active)), + (int)_tbotInstance.InstanceSettings.Brain.Transports.MaxSlots, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Transport)), new RankSlotsPriority(Feature.Expeditions, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, - (bool) _tbotInstance.InstanceSettings.Expeditions.Active, - (int) _tbotInstance.UserData.slots.ExpTotal, + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Expeditions, + (bool)_tbotInstance.InstanceSettings.Expeditions.Active, + (int)_tbotInstance.UserData.slots.ExpTotal, (int)_tbotInstance.UserData.slots.ExpInUse), new RankSlotsPriority(Feature.AutoFarm, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, - (bool) _tbotInstance.InstanceSettings.AutoFarm.Active, - (int) _tbotInstance.InstanceSettings.AutoFarm.MaxSlots, - (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoFarm, + (bool)_tbotInstance.InstanceSettings.AutoFarm.Active, + (int)_tbotInstance.InstanceSettings.AutoFarm.MaxSlots, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Attack)), new RankSlotsPriority(Feature.Colonize, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, - (bool) _tbotInstance.InstanceSettings.AutoColonize.Active, - (bool) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? - (int) _tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : - 1, - (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.Colonize, + (bool)_tbotInstance.InstanceSettings.AutoColonize.Active, + (bool)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.Active ? + (int)_tbotInstance.InstanceSettings.AutoColonize.IntensiveResearch.MaxSlots : 1, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Colonize)), new RankSlotsPriority(Feature.AutoDiscovery, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, - (bool) _tbotInstance.InstanceSettings.AutoDiscovery.Active, - (int) _tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, - (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoDiscovery, + (bool)_tbotInstance.InstanceSettings.AutoDiscovery.Active, + (int)_tbotInstance.InstanceSettings.AutoDiscovery.MaxSlots, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Discovery)), new RankSlotsPriority(Feature.Harvest, - (int) _tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, - (bool) _tbotInstance.InstanceSettings.AutoHarvest.Active, - (int) _tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, - (int) _tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) + (int)_tbotInstance.InstanceSettings.General.SlotPriorityLevel.AutoHarvest, + (bool)_tbotInstance.InstanceSettings.AutoHarvest.Active, + (int)_tbotInstance.InstanceSettings.AutoHarvest.MaxSlots, + (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; - int MaxSlots = _calculationService.CalcSlotsPriority(Feature.Expeditions, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); + + int MaxSlots = _tbotInstance.UserData.slots.Total + - (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree; + + if (MaxSlots < 0) + MaxSlots = 0; int expsToSend; - if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForAllExpeditions") && (bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForAllExpeditions") + && (bool)_tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { if (_tbotInstance.UserData.slots.ExpInUse == 0) expsToSend = _tbotInstance.UserData.slots.ExpTotal; else @@ -120,25 +137,40 @@ protected override async Task Execute() { } else { expsToSend = Math.Min(_tbotInstance.UserData.slots.ExpFree, _tbotInstance.UserData.slots.Free); } + DoLog(LogLevel.Debug, $"Expedition slot free: {expsToSend}"); - if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForMajorityOfExpeditions") && (bool) _tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions) { - if ((double) expsToSend < Math.Round((double) _tbotInstance.UserData.slots.ExpTotal / 2D, 0, MidpointRounding.ToZero) + 1D) { + + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForMajorityOfExpeditions") + && (bool)_tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions) { + if ((double)expsToSend < Math.Round((double)_tbotInstance.UserData.slots.ExpTotal / 2D, 0, MidpointRounding.ToZero) + 1D) { DoLog(LogLevel.Debug, $"Majority of expedition already in flight, Skipping..."); expsToSend = 0; } } + expsToSend = expsToSend < MaxSlots ? expsToSend : MaxSlots; + + if (expsToSend <= 0) { + var idleInterval = RandomizeHelper.CalcRandomInterval(IntervalType.AboutFiveMinutes); + var nowIdle = await _tbotOgameBridge.GetDateTime(); + DoLog(LogLevel.Information, "Expeditions idle – no free expedition slots"); + DoLog(LogLevel.Information, $"Next expedition check at {nowIdle.AddMilliseconds(idleInterval)}"); + ChangeWorkerPeriod(idleInterval); + return; + } + if (expsToSend > 0) { if (_tbotInstance.UserData.slots.ExpFree > 0) { if (_tbotInstance.UserData.slots.Free > 0) { + List origins = new(); if (_tbotInstance.InstanceSettings.Expeditions.Origin.Length > 0) { try { foreach (var origin in _tbotInstance.InstanceSettings.Expeditions.Origin) { Coordinate customOriginCoords = new( - (int) origin.Galaxy, - (int) origin.System, - (int) origin.Position, + (int)origin.Galaxy, + (int)origin.System, + (int)origin.Position, Enum.Parse(origin.Type.ToString()) ); Celestial customOrigin = _tbotInstance.UserData.celestials @@ -157,7 +189,14 @@ protected override async Task Execute() { _tbotInstance.UserData.celestials = await _tbotOgameBridge.UpdatePlanets(UpdateTypes.LFBonuses); origins.Add(_tbotInstance.UserData.celestials .OrderBy(planet => planet.Coordinate.Type == Celestials.Moon) - .ThenByDescending(planet => _calculationService.CalcFleetCapacity(planet.Ships, _tbotInstance.UserData.serverData, _tbotInstance.UserData.researches.HyperspaceTechnology, null, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)) + .ThenByDescending(planet => + _calculationService.CalcFleetCapacity( + planet.Ships, + _tbotInstance.UserData.serverData, + _tbotInstance.UserData.researches.HyperspaceTechnology, + null, + _tbotInstance.UserData.userInfo.Class, + _tbotInstance.UserData.serverData.ProbeCargo)) .First() ); } @@ -166,26 +205,84 @@ protected override async Task Execute() { _tbotInstance.UserData.celestials = await _tbotOgameBridge.UpdatePlanets(UpdateTypes.LFBonuses); origins.Add(_tbotInstance.UserData.celestials .OrderBy(planet => planet.Coordinate.Type == Celestials.Moon) - .ThenByDescending(planet => _calculationService.CalcFleetCapacity(planet.Ships, _tbotInstance.UserData.serverData, _tbotInstance.UserData.researches.HyperspaceTechnology, null, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo)) + .ThenByDescending(planet => + _calculationService.CalcFleetCapacity( + planet.Ships, + _tbotInstance.UserData.serverData, + _tbotInstance.UserData.researches.HyperspaceTechnology, + null, + _tbotInstance.UserData.userInfo.Class, + _tbotInstance.UserData.serverData.ProbeCargo)) .First() ); } - if ((bool) _tbotInstance.InstanceSettings.Expeditions.RandomizeOrder) { + + if ((bool)_tbotInstance.InstanceSettings.Expeditions.RandomizeOrder) { origins = origins.Shuffle().ToList(); } + LFBonuses lfBonuses = origins.First().LFBonuses; + + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + + var expFleets = _tbotInstance.UserData.fleets + .Where(f => f.Mission == Missions.Expedition && f.Origin != null) + .ToList(); + + DoLog(LogLevel.Warning, $"[EXP DEBUG] Active expeditions total = {expFleets.Count}"); + + foreach (var f in expFleets) { + DoLog( + LogLevel.Warning, + $"[EXP DEBUG] Fleet origin: G{f.Origin.Galaxy}:{f.Origin.System}:{f.Origin.Position} Type={f.Origin.Type}" + ); + } + int maxPerOrigin = int.MaxValue; + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "MaxExpeditionsPerOrigin")) { + maxPerOrigin = (int)_tbotInstance.InstanceSettings.Expeditions.MaxExpeditionsPerOrigin; + } + + DoLog(LogLevel.Warning, + $"[EXP DEBUG] Origins count={origins.Count}, expsToSend={expsToSend}, maxPerOrigin={maxPerOrigin}"); + + var capacity = new Dictionary(); + foreach (var o in origins) { + int active = CountActiveExpeditionsFromOrigin(o); + int cap = Math.Max(0, maxPerOrigin - active); + capacity[o] = cap; + + DoLog(LogLevel.Warning, + $"[EXP DEBUG] Origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + + $"active={active} maxPerOrigin={maxPerOrigin} cap={cap}"); + } + + var originExps = origins.ToDictionary(o => o, o => 0); + + int remaining = Math.Min(expsToSend, capacity.Values.Sum()); + + while (remaining > 0) { + bool progressed = false; + + foreach (var o in origins) { + if (remaining <= 0) break; + + if (originExps[o] < capacity[o]) { + originExps[o]++; + remaining--; + progressed = true; + } + } + + if (!progressed) break; + } + + foreach (var o in origins) { + DoLog(LogLevel.Warning, + $"[EXP DEBUG] PLAN origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + + $"willSend={originExps[o]} (cap={capacity[o]})"); + } - LFBonuses lfBonuses = origins.First().LFBonuses; - Dictionary originExps = new(); - int quot = (int) Math.Floor((float) expsToSend / (float) origins.Count()); - foreach (var origin in origins) { - originExps.Add(origin, quot); - } - int rest = (int) Math.Floor((float) expsToSend % (float) origins.Count()); - for (int i = 0; i < rest; i++) { - originExps[origins[i]]++; - } int delayExpedition = 0; - foreach (var origin in originExps.Keys) { + foreach (var origin in origins) { int expsToSendFromThisOrigin = originExps[origin]; if (expsToSendFromThisOrigin == 0) { if (delayExpedition > 0) @@ -199,28 +296,28 @@ protected override async Task Execute() { continue; } else { Ships fleet; - if ((bool) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Active) { + if ((bool)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Active) { fleet = new( - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LightFighter, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.HeavyFighter, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Cruiser, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battleship, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battlecruiser, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Bomber, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Destroyer, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Deathstar, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.SmallCargo, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LargeCargo, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.ColonyShip, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Recycler, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.EspionageProbe, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LightFighter, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.HeavyFighter, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Cruiser, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battleship, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battlecruiser, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Bomber, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Destroyer, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Deathstar, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.SmallCargo, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LargeCargo, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.ColonyShip, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Recycler, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.EspionageProbe, 0, 0, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Reaper, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Pathfinder + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Reaper, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Pathfinder ); if (!origin.Ships.HasAtLeast(fleet, expsToSendFromThisOrigin)) { - DoLog(LogLevel.Warning, $"Unable to send expeditions: not enough ships in origin {origin.ToString()}"); + DoLog(LogLevel.Warning, $"Unable to send expeditions: not enough ships in origin {origin}"); delayExpedition++; continue; } @@ -237,65 +334,34 @@ protected override async Task Execute() { } var availableShips = origin.Ships.GetMovableShips(); - if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "PrimaryToKeep") && (int) _tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep > 0) { - availableShips.SetAmount(primaryShip, Math.Max(0, availableShips.GetAmount(primaryShip) - (long) _tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep)); - } - DoLog(LogLevel.Warning, $"Available {primaryShip.ToString()} in origin {origin.ToString()}: {availableShips.GetAmount(primaryShip)} ({_tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep} must be kept at dock)"); - fleet = _calculationService.CalcFullExpeditionShips(availableShips, primaryShip, expsToSendFromThisOrigin, _tbotInstance.UserData.serverData, _tbotInstance.UserData.researches, lfBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo); - if (fleet.GetAmount(primaryShip) < (long) _tbotInstance.InstanceSettings.Expeditions.MinPrimaryToSend || availableShips.GetAmount(primaryShip) < 1) { - fleet.SetAmount(primaryShip, (long) _tbotInstance.InstanceSettings.Expeditions.MinPrimaryToSend); - if (availableShips.GetAmount(primaryShip) < 1) { - DoLog(LogLevel.Warning, $"Unable to send expeditions: no ships available in origin {origin.ToString()}"); - delayExpedition++; - continue; - } - if (!availableShips.HasAtLeast(fleet, expsToSendFromThisOrigin)) { - DoLog(LogLevel.Warning, $"Unable to send expeditions: available {primaryShip.ToString()} in origin {origin.ToString()} under set min number of {(long) _tbotInstance.InstanceSettings.Expeditions.MinPrimaryToSend}"); - delayExpedition++; - continue; - } - } - Buildables secondaryShip = Buildables.Null; - if (!Enum.TryParse(_tbotInstance.InstanceSettings.Expeditions.SecondaryShip, true, out secondaryShip)) { - DoLog(LogLevel.Warning, "Unable to parse SecondaryShip. Falling back to default Null"); - secondaryShip = Buildables.Null; - } - if (secondaryShip != Buildables.Null) { - long secondaryToSend = Math.Min( - (long) Math.Round( - availableShips.GetAmount(secondaryShip) / (float) expsToSendFromThisOrigin, - 0, - MidpointRounding.ToZero - ), - (long) Math.Round( - fleet.GetAmount(primaryShip) * (float) _tbotInstance.InstanceSettings.Expeditions.SecondaryToPrimaryRatio, - 0, - MidpointRounding.ToZero - ) - ); - if (secondaryToSend < (long) _tbotInstance.InstanceSettings.Expeditions.MinSecondaryToSend) { - DoLog(LogLevel.Warning, $"Unable to send expeditions: available {secondaryShip.ToString()} in origin {origin.ToString()} under set number of {(long) _tbotInstance.InstanceSettings.Expeditions.MinSecondaryToSend}"); - delayExpedition++; - continue; - } else { - fleet.Add(secondaryShip, secondaryToSend); - if (!availableShips.HasAtLeast(fleet, expsToSendFromThisOrigin)) { - DoLog(LogLevel.Warning, $"Unable to send expeditions: not enough ships in origin {origin.ToString()}"); - delayExpedition++; - continue; - } - } + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "PrimaryToKeep") + && (int)_tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep > 0) { + availableShips.SetAmount( + primaryShip, + Math.Max(0, availableShips.GetAmount(primaryShip) + - (long)_tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep)); } + + fleet = _calculationService.CalcFullExpeditionShips( + availableShips, + primaryShip, + expsToSendFromThisOrigin, + _tbotInstance.UserData.serverData, + _tbotInstance.UserData.researches, + lfBonuses, + _tbotInstance.UserData.userInfo.Class, + _tbotInstance.UserData.serverData.ProbeCargo + ); } - DoLog(LogLevel.Information, $"{expsToSendFromThisOrigin.ToString()} expeditions with {fleet.ToString()} will be sent from {origin.ToString()}"); + DoLog(LogLevel.Information, $"{expsToSendFromThisOrigin} expeditions with {fleet} will be sent from {origin}"); + List syslist = new(); for (int i = 0; i < expsToSendFromThisOrigin; i++) { Coordinate destination; - if ((bool) _tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Active) { + if ((bool)_tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Active) { var rand = new Random(); - - int range = (int) _tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Range; + int range = (int)_tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Range; while (expsToSendFromThisOrigin > range * 2) range += 1; @@ -317,36 +383,58 @@ protected override async Task Execute() { Type = Celestials.DeepSpace }; } + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - Resources payload = new(); - if ((long) _tbotInstance.InstanceSettings.Expeditions.FuelToCarry > 0) { - payload.Deuterium = (long) _tbotInstance.InstanceSettings.Expeditions.FuelToCarry; - } + Resources payload = new(); + if ((long)_tbotInstance.InstanceSettings.Expeditions.FuelToCarry > 0) { + payload.Deuterium = (long)_tbotInstance.InstanceSettings.Expeditions.FuelToCarry; + } if (_tbotInstance.UserData.slots.ExpFree > 0) { - var fleetId = await _fleetScheduler.SendFleet(origin, fleet, destination, Missions.Expedition, Speeds.HundredPercent, payload); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { + var originUpdated = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Ships); + + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + if (_tbotInstance.UserData.slots.ExpFree <= 0) { + DoLog(LogLevel.Information, "Unable to send expeditions: no expedition slots available."); + delay = true; + return; + } + + if (fleet == null || fleet.IsEmpty() || !originUpdated.Ships.HasAtLeast(fleet, 1)) { + DoLog(LogLevel.Warning, $"Skipping expedition: no ships available on origin {originUpdated}"); + delayExpedition++; + break; + } + + var fleetId = await _fleetScheduler.SendFleet( + originUpdated, + fleet, + destination, + Missions.Expedition, + Speeds.HundredPercent, + payload + ); + if (fleetId == (int)SendFleetCode.AfterSleepTime) { stop = true; return; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + if (fleetId == (int)SendFleetCode.NotEnoughSlots) { delay = true; return; } - - var minWaitNextFleet = (int) _tbotInstance.InstanceSettings.Expeditions.MinWaitNextFleet; - var maxWaitNextFleet = (int) _tbotInstance.InstanceSettings.Expeditions.MaxWaitNextFleet; - if (minWaitNextFleet < 0) - minWaitNextFleet = 0; - if (maxWaitNextFleet < 1) - maxWaitNextFleet = 1; + int minWait = (int)_tbotInstance.InstanceSettings.Expeditions.MinWaitNextFleet; + int maxWait = (int)_tbotInstance.InstanceSettings.Expeditions.MaxWaitNextFleet; - var rndWaitTimeMs = (int) RandomizeHelper.CalcRandomIntervalSecToMs(minWaitNextFleet, maxWaitNextFleet); + if (maxWait < minWait) { + DoLog(LogLevel.Warning, + $"Expeditions wait misconfigured (MinWaitNextFleet={minWait} > MaxWaitNextFleet={maxWait}). Swapping values."); + (minWait, maxWait) = (maxWait, minWait); + } + var rndWaitTimeMs = (int)RandomizeHelper.CalcRandomIntervalSecToMs(minWait, maxWait); - DoLog(LogLevel.Information, $"Wait {((float) rndWaitTimeMs / 1000).ToString("0.00")}s for next Expedition"); + DoLog(LogLevel.Information, $"Wait {(rndWaitTimeMs / 1000f):0.00}s for next Expedition"); await Task.Delay(rndWaitTimeMs, _ct); - } else { DoLog(LogLevel.Information, "Unable to send expeditions: no expedition slots available."); delay = true; @@ -355,11 +443,7 @@ protected override async Task Execute() { } } } - } else { - DoLog(LogLevel.Warning, "Unable to send expeditions: no fleet slots available"); } - } else { - DoLog(LogLevel.Warning, "Unable to send expeditions: no expeditions slots available"); } } @@ -367,47 +451,42 @@ protected override async Task Execute() { List orderedFleets = _tbotInstance.UserData.fleets .Where(fleet => fleet.Mission == Missions.Expedition) .ToList(); - if ((bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { - orderedFleets = orderedFleets - .OrderByDescending(fleet => fleet.BackIn) - .ToList(); + + if ((bool)_tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { + orderedFleets = orderedFleets.OrderByDescending(fleet => fleet.BackIn).ToList(); } else { - orderedFleets = orderedFleets - .OrderBy(fleet => fleet.BackIn) - .ToList(); + orderedFleets = orderedFleets.OrderBy(fleet => fleet.BackIn).ToList(); } _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - if ((orderedFleets.Count() == 0) || (_tbotInstance.UserData.slots.ExpFree > 0 && (!((bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) && !((bool) _tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions)))) { - interval = RandomizeHelper.CalcRandomInterval(IntervalType.AboutFiveMinutes); + if ((orderedFleets.Count == 0) || + (_tbotInstance.UserData.slots.ExpFree > 0 && + !((bool)_tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) && + !((bool)_tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions))) { + interval = RandomizeHelper.CalcRandomInterval(IntervalType.AboutFiveMinutes); } else { - - var minWaitNextRound = (int) _tbotInstance.InstanceSettings.Expeditions.MinWaitNextRound; - var maxWaitNextRound = (int) _tbotInstance.InstanceSettings.Expeditions.MaxWaitNextRound; - - if (minWaitNextRound < 0) minWaitNextRound = 0; - if (maxWaitNextRound < 1) maxWaitNextRound = 1; - - interval = (int) ((1000 * orderedFleets.First().BackIn) + RandomizeHelper.CalcRandomIntervalSecToMs(minWaitNextRound, maxWaitNextRound)); - + interval = (int)((1000 * orderedFleets.First().BackIn) + + RandomizeHelper.CalcRandomIntervalSecToMs( + (int)_tbotInstance.InstanceSettings.Expeditions.MinWaitNextRound, + (int)_tbotInstance.InstanceSettings.Expeditions.MaxWaitNextRound)); } + time = await _tbotOgameBridge.GetDateTime(); - if (interval <= 0) - interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); newTime = time.AddMilliseconds(interval); ChangeWorkerPeriod(interval); - DoLog(LogLevel.Information, $"Next check at {newTime.ToString()}"); + DoLog(LogLevel.Information, $"Next check at {newTime}"); await _tbotOgameBridge.CheckCelestials(); } - } catch (Exception e) { + } + catch (Exception e) { DoLog(LogLevel.Warning, $"HandleExpeditions exception: {e.Message}"); DoLog(LogLevel.Warning, $"Stacktrace: {e.StackTrace}"); - long interval = (long) (RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo)); + long interval = RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo); var time = await _tbotOgameBridge.GetDateTime(); - DateTime newTime = time.AddMilliseconds(interval); ChangeWorkerPeriod(interval); - DoLog(LogLevel.Information, $"Next check at {newTime.ToString()}"); - } finally { + DoLog(LogLevel.Information, $"Next check at {time.AddMilliseconds(interval)}"); + } + finally { if (!_tbotInstance.UserData.isSleeping) { if (stop) { DoLog(LogLevel.Information, $"Stopping feature."); @@ -419,13 +498,15 @@ protected override async Task Execute() { _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); long interval; try { - interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + interval = (_tbotInstance.UserData.fleets.OrderBy(f => f.BackIn).First().BackIn ?? 0) * 1000 + + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } catch { - interval = RandomizeHelper.CalcRandomInterval((int) _tbotInstance.InstanceSettings.Expeditions.CheckIntervalMin, (int) _tbotInstance.InstanceSettings.Expeditions.CheckIntervalMax); + interval = RandomizeHelper.CalcRandomInterval( + (int)_tbotInstance.InstanceSettings.Expeditions.CheckIntervalMin, + (int)_tbotInstance.InstanceSettings.Expeditions.CheckIntervalMax); } - var newTime = time.AddMilliseconds(interval); ChangeWorkerPeriod(interval); - DoLog(LogLevel.Information, $"Next check at {newTime.ToString()}"); + DoLog(LogLevel.Information, $"Next check at {time.AddMilliseconds(interval)}"); } await _tbotOgameBridge.CheckCelestials(); } From 4235c705cb414b68e8dc4f5aac4c77e730e104c4 Mon Sep 17 00:00:00 2001 From: Killer Date: Sat, 21 Feb 2026 00:11:38 +0100 Subject: [PATCH 111/117] Refactor and improve FleetScheduler logic --- TBot/Workers/FleetScheduler.cs | 603 +++++++++++++++++++-------------- 1 file changed, 355 insertions(+), 248 deletions(-) diff --git a/TBot/Workers/FleetScheduler.cs b/TBot/Workers/FleetScheduler.cs index 860ade9f..244f4dcb 100644 --- a/TBot/Workers/FleetScheduler.cs +++ b/TBot/Workers/FleetScheduler.cs @@ -27,7 +27,43 @@ public class FleetScheduler : IFleetScheduler { private readonly ICalculationService _calcService; - private Dictionary timers = new(); + private readonly Dictionary timers = new(); + private readonly object _timersLock = new(); + + private bool TryGetTimer(string key, out Timer timer) { + lock (_timersLock) { + return timers.TryGetValue(key, out timer); + } + } + private bool ContainsTimer(string key) { + lock (_timersLock) { + return timers.ContainsKey(key); + } + } + private void AddTimer(string key, Timer timer) { + lock (_timersLock) { + if (!timers.ContainsKey(key)) timers.Add(key, timer); + } + } + private void ReplaceTimer(string key, Timer timer) { + lock (_timersLock) { + if (timers.TryGetValue(key, out var oldTimer)) { + try { oldTimer.Dispose(); } catch { } + timers.Remove(key); + } + timers[key] = timer; + } + } + private void DisposeAndRemoveTimer(string key) { + lock (_timersLock) { + if (timers.TryGetValue(key, out var t)) { + try { t.Dispose(); } catch { } + timers.Remove(key); + } + } + } + + public FleetScheduler( ICalculationService helpService, IOgameService ogameService) { @@ -55,48 +91,65 @@ public async Task SpyCrash(Celestial fromCelestial, Coordinate target = null) { await _tbotInstance.SendTelegramMessage($"No probes or no Fuel on {fromCelestial.Coordinate.ToString()}!"); return; } - // spycrash auto part - if (target == null) { - List spycrash = new(); - int playerid = _tbotInstance.UserData.userInfo.PlayerID; - int sys = 0; - for (sys = fromCelestial.Coordinate.System - 2; sys <= fromCelestial.Coordinate.System + 2; sys++) { - sys = GeneralHelper.ClampSystem(sys); - GalaxyInfo galaxyInfo = await _ogameService.GetGalaxyInfo(fromCelestial.Coordinate.Galaxy, sys); - foreach (var planet in galaxyInfo.Planets) { - try { - if (planet != null && !planet.Administrator && !planet.Inactive && !planet.StrongPlayer && !planet.Newbie && !planet.Banned && !planet.Vacation) { - if (planet.Player.ID != playerid) { //exclude player planet - spycrash.Add(new(planet.Coordinate.Galaxy, planet.Coordinate.System, planet.Coordinate.Position, Celestials.Planet)); - } - } - } catch (NullReferenceException) { - continue; - } - } - } - - if (spycrash.Count() == 0) { - await _tbotInstance.SendTelegramMessage($"No planet to spycrash on could be found over system -2 -> +2"); - return; - } else { - target = spycrash[random.Next(spycrash.Count())]; - } - } - var attackingShips = new Ships().Add(Buildables.EspionageProbe, 1); - - int fleetId = await SendFleet(fromCelestial, attackingShips, target, Missions.Attack, speed); - - if (fleetId != (int) SendFleetCode.GenericError || - fleetId != (int) SendFleetCode.AfterSleepTime || - fleetId != (int) SendFleetCode.NotEnoughSlots) { - _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"EspionageProbe sent to crash on {target.ToString()}"); - - await _tbotInstance.SendTelegramMessage($"EspionageProbe sent to crash on {target.ToString()}"); - } - return; - } - + List spycrash = new(); + + if (target == null) { + int playerid = _tbotInstance.UserData.userInfo.PlayerID; + + for (int sys = fromCelestial.Coordinate.System - 2; sys <= fromCelestial.Coordinate.System + 2; sys++) { + int clampedSys = GeneralHelper.ClampSystem(sys); + + GalaxyInfo galaxyInfo = await _ogameService.GetGalaxyInfo(fromCelestial.Coordinate.Galaxy, clampedSys); + if (galaxyInfo?.Planets == null) continue; + + foreach (var planet in galaxyInfo.Planets) { + try { + if (planet != null + && !planet.Administrator + && !planet.Inactive + && !planet.StrongPlayer + && !planet.Newbie + && !planet.Banned + && !planet.Vacation + && planet.Player != null + && planet.Player.ID != playerid) { + + spycrash.Add(new Coordinate( + planet.Coordinate.Galaxy, + planet.Coordinate.System, + planet.Coordinate.Position, + Celestials.Planet)); + } + } catch (NullReferenceException) { + continue; + } + } + } + + if (spycrash.Count == 0) { + await _tbotInstance.SendTelegramMessage("No planet to spycrash on could be found over system -2 -> +2"); + return; + } + + target = spycrash[random.Next(spycrash.Count)]; + } + var attackingShips = new Ships().Add(Buildables.EspionageProbe, 1); + + int fleetId = await SendFleet(fromCelestial, attackingShips, target, Missions.Attack, speed); + + if (fleetId != (int)SendFleetCode.GenericError && + fleetId != (int)SendFleetCode.AfterSleepTime && + fleetId != (int)SendFleetCode.NotEnoughSlots) + { + _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, + $"EspionageProbe sent to crash on {target}"); + + await _tbotInstance.SendTelegramMessage( + $"EspionageProbe sent to crash on {target}"); + } + + return; + } public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = false, long minDuration = 0, bool WaitFleetsReturn = false, Missions TelegramMission = Missions.None, bool fromTelegram = false, bool saveall = false) { DateTime departureTime = await _tbotOgameBridge.GetDateTime(); _tbotInstance.SleepDuration = minDuration; @@ -116,8 +169,7 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = interval = 0; } - if (interval > 0 && (!timers.TryGetValue("GhostSleepTimer", out Timer value))) { - //Stop features which are sending fleets + if (interval > 0 && (!TryGetTimer("GhostSleepTimer", out Timer value))) { List features = new List { Feature.Colonize, Feature.BrainAutoRepatriate, @@ -141,15 +193,15 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = _tbotInstance.NextWakeUpTime = TimeToGhost.AddMilliseconds(minDuration * 1000); if (saveall) - timers.Add("GhostSleepTimer", new Timer(GhostandSleepAfterFleetsReturnAll, null, interval, Timeout.Infinite)); + AddTimer("GhostSleepTimer", new Timer(GhostandSleepAfterFleetsReturnAll, null, interval, Timeout.Infinite)); else - timers.Add("GhostSleepTimer", new Timer(GhostandSleepAfterFleetsReturn, null, interval, Timeout.Infinite)); + AddTimer("GhostSleepTimer", new Timer(GhostandSleepAfterFleetsReturn, null, interval, Timeout.Infinite)); _tbotInstance.log(LogLevel.Information, LogSender.SleepMode, $"Fleets active, Next check at {TimeToGhost.ToString()}"); await _tbotInstance.SendTelegramMessage($"Waiting for fleets return, delaying ghosting at {TimeToGhost.ToString()}"); return; - } else if (interval == 0 && (!timers.TryGetValue("GhostSleepTimer", out Timer value2))) { + } else if (interval == 0 && (!TryGetTimer("GhostSleepTimer", out Timer value2))) { _tbotInstance.log(LogLevel.Information, LogSender.SleepMode, $"No fleets active, Ghosting now."); _tbotInstance.NextWakeUpTime = departureTime.AddMilliseconds(minDuration * 1000); @@ -159,7 +211,7 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = GhostandSleepAfterFleetsReturn(null); return; - } else if (timers.TryGetValue("GhostSleepTimer", out Timer value3)) { + } else if (TryGetTimer("GhostSleepTimer", out Timer value3)) { await _tbotInstance.SendTelegramMessage($"GhostSleep already planned, try /cancelghostsleep"); return; } @@ -204,9 +256,8 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = FleetHypotesis possibleFleet = new(); int fleetId = (int) SendFleetCode.GenericError; - bool AlreadySent = false; //permit to swith to Harvest mission if not enough fuel to Deploy if celestial far away + bool AlreadySent = false; - //Doing DefaultMission or telegram /ghostto mission Missions mission; if (!Missions.TryParse(_tbotInstance.InstanceSettings.SleepMode.AutoFleetSave.DefaultMission, out mission)) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Error: Could not parse 'DefaultMission' from settings, value set to Harvest."); @@ -223,18 +274,17 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = if (CheckFuel(fleet, celestial)) { fleetId = await SendFleet(fleet.Origin, fleet.Ships, fleet.Destination, fleet.Mission, fleet.Speed, payload, _tbotInstance.UserData.userInfo.Class, true); - if (fleetId != (int) SendFleetCode.GenericError || - fleetId != (int) SendFleetCode.AfterSleepTime || - fleetId != (int) SendFleetCode.NotEnoughSlots) { - possibleFleet = fleet; - AlreadySent = true; - break; - } + if (fleetId != (int)SendFleetCode.GenericError && + fleetId != (int)SendFleetCode.AfterSleepTime && + fleetId != (int)SendFleetCode.NotEnoughSlots) { + possibleFleet = fleet; + AlreadySent = true; + break; +} } } } - //If /ghostto -> leaving function if failed if (fromTelegram && !AlreadySent && mission == Missions.Harvest && fleetHypotesis.Count() == 0) { await _tbotInstance.SendTelegramMessage($"No debris field found for {mission}, try to /spycrash."); return; @@ -243,7 +293,6 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = return; } - //Doing Deploy if (!AlreadySent) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Fleetsave from {celestial.ToString()} no {mission} possible, checking next mission.."); if (mission == Missions.Harvest) { mission = Missions.Deploy; } else { mission = Missions.Harvest; }; @@ -255,19 +304,18 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = if (CheckFuel(fleet, celestial)) { fleetId = await SendFleet(fleet.Origin, fleet.Ships, fleet.Destination, fleet.Mission, fleet.Speed, payload, _tbotInstance.UserData.userInfo.Class, true); - if (fleetId != (int) SendFleetCode.GenericError || - fleetId != (int) SendFleetCode.AfterSleepTime || - fleetId != (int) SendFleetCode.AfterSleepTime || - fleetId != (int) SendFleetCode.NotEnoughSlots) { - possibleFleet = fleet; - AlreadySent = true; - break; - } + if (fleetId != (int)SendFleetCode.GenericError && + fleetId != (int)SendFleetCode.AfterSleepTime && + fleetId != (int)SendFleetCode.NotEnoughSlots) +{ + possibleFleet = fleet; + AlreadySent = true; + break; +} } } } } - //Doing colonize if (!AlreadySent && celestial.Ships.ColonyShip > 0) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Fleetsave from {celestial.ToString()} no {mission} found, checking Colonize destination..."); mission = Missions.Colonize; @@ -278,19 +326,20 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = if (CheckFuel(fleet, celestial)) { fleetId = await SendFleet(fleet.Origin, fleet.Ships, fleet.Destination, fleet.Mission, fleet.Speed, payload, _tbotInstance.UserData.userInfo.Class, true); - if (fleetId != (int) SendFleetCode.GenericError || - fleetId != (int) SendFleetCode.AfterSleepTime || - fleetId != (int) SendFleetCode.NotEnoughSlots) { - possibleFleet = fleet; - AlreadySent = true; - break; - } + if (fleetId != (int)SendFleetCode.GenericError && + fleetId != (int)SendFleetCode.AfterSleepTime && + fleetId != (int)SendFleetCode.NotEnoughSlots) +{ + possibleFleet = fleet; + AlreadySent = true; + break; +} + } } } } - //Doing Spy if (!AlreadySent && celestial.Ships.EspionageProbe > 0) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Fleetsave from {celestial.ToString()} no {mission} found, checking Spy destination..."); mission = Missions.Spy; @@ -301,19 +350,20 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = if (CheckFuel(fleet, celestial)) { fleetId = await SendFleet(fleet.Origin, fleet.Ships, fleet.Destination, fleet.Mission, fleet.Speed, payload, _tbotInstance.UserData.userInfo.Class, true); - if (fleetId != (int) SendFleetCode.GenericError || - fleetId != (int) SendFleetCode.AfterSleepTime || - fleetId != (int) SendFleetCode.NotEnoughSlots) { - possibleFleet = fleet; - AlreadySent = true; - break; - } + if (fleetId != (int)SendFleetCode.GenericError && + fleetId != (int)SendFleetCode.AfterSleepTime && + fleetId != (int)SendFleetCode.NotEnoughSlots) +{ + possibleFleet = fleet; + AlreadySent = true; + break; +} + } } } } - //Doing Transport if (!AlreadySent) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Fleetsave from {celestial.ToString()} no {mission} found, checking Transport destination..."); mission = Missions.Transport; @@ -324,25 +374,23 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = if (CheckFuel(fleet, celestial)) { fleetId = await SendFleet(fleet.Origin, fleet.Ships, fleet.Destination, fleet.Mission, fleet.Speed, payload, _tbotInstance.UserData.userInfo.Class, true); - if (fleetId != (int) SendFleetCode.GenericError || - fleetId != (int) SendFleetCode.AfterSleepTime || - fleetId != (int) SendFleetCode.NotEnoughSlots) { - possibleFleet = fleet; - AlreadySent = true; - break; - } + if (fleetId != (int)SendFleetCode.GenericError && + fleetId != (int)SendFleetCode.AfterSleepTime && + fleetId != (int)SendFleetCode.NotEnoughSlots) +{ + possibleFleet = fleet; + AlreadySent = true; + break; +} + } } } } - //Doing switch bool hasMoon = _tbotInstance.UserData.celestials.Count(c => c.HasCoords(new Coordinate(celestial.Coordinate.Galaxy, celestial.Coordinate.System, celestial.Coordinate.Position, Celestials.Moon))) == 1; - if (!AlreadySent && hasMoon && !timers.TryGetValue("GhostSleepTimer", out Timer val)) { + if (!AlreadySent && hasMoon && !TryGetTimer("GhostSleepTimer", out Timer val)) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Fleetsave from {celestial.ToString()} no {mission} possible (missing fuel?), checking for switch if has Moon"); - //var validSpeeds = _tbotInstance.UserData.userInfo.Class == CharacterClass.General ? Speeds.GetGeneralSpeedsList() : Speeds.GetNonGeneralSpeedsList(); - //Random randomSpeed = new Random(); - //decimal speed = validSpeeds[randomSpeed.Next(validSpeeds.Count)]; decimal speed = 10; AlreadySent = await _tbotInstance.TelegramSwitch(speed, celestial); } @@ -354,34 +402,42 @@ public async Task AutoFleetSave(Celestial celestial, bool isSleepTimeFleetSave = } - if ((bool) _tbotInstance.InstanceSettings.SleepMode.AutoFleetSave.Recall && AlreadySent) { - if (fleetId != (int) SendFleetCode.GenericError || - fleetId != (int) SendFleetCode.AfterSleepTime || - fleetId != (int) SendFleetCode.NotEnoughSlots) { - Fleet fleet = _tbotInstance.UserData.fleets.Single(fleet => fleet.ID == fleetId); - DateTime time = await _tbotOgameBridge.GetDateTime(); - var interval = ((minDuration / 2) * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo); - if (interval <= 0) - interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); - DateTime newTime = time.AddMilliseconds(interval); - timers.Add($"RecallTimer-{fleetId.ToString()}", new Timer(RetireFleet, fleet, interval, Timeout.Infinite)); - _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"The fleet will be recalled at {newTime.ToString()}"); - if (fromTelegram) - await _tbotInstance.SendTelegramMessage($"Fleet {fleetId} send to {possibleFleet.Mission} on {possibleFleet.Destination.ToString()}, fuel consumed: {possibleFleet.Fuel.ToString("#,#", CultureInfo.InvariantCulture)}, recalled at {newTime.ToString()}"); - } - } else { - if (fleetId != (int) SendFleetCode.GenericError || - fleetId != (int) SendFleetCode.AfterSleepTime || - fleetId != (int) SendFleetCode.NotEnoughSlots) { - Fleet fleet = _tbotInstance.UserData.fleets.Single(fleet => fleet.ID == fleetId); - DateTime returntime = (DateTime) fleet.BackTime; - _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Fleet {fleetId} send to {possibleFleet.Mission} on {possibleFleet.Destination.ToString()}, arrive at {possibleFleet.Duration} fuel consumed: {possibleFleet.Fuel.ToString("#,#", CultureInfo.InvariantCulture)}"); - if (fromTelegram) - await _tbotInstance.SendTelegramMessage($"Fleet {fleetId} send to {possibleFleet.Mission} on {possibleFleet.Destination.ToString()}, arrive at {possibleFleet.Duration.ToString()}, returned at {returntime.ToString()} fuel consumed: {possibleFleet.Fuel.ToString("#,#", CultureInfo.InvariantCulture)}"); - } - } - } + if ((bool)_tbotInstance.InstanceSettings.SleepMode.AutoFleetSave.Recall && AlreadySent) +{ + if (fleetId > 0) + { + Fleet fleet = _tbotInstance.UserData.fleets.SingleOrDefault(f => f.ID == fleetId); +if (fleet == null) return; + DateTime time = await _tbotOgameBridge.GetDateTime(); + var interval = ((minDuration / 2) * 1000) + RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo); + + if (interval <= 0) + interval = RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); + DateTime newTime = time.AddMilliseconds(interval); + AddTimer($"RecallTimer-{fleetId}", new Timer(RetireFleet, fleet, interval, Timeout.Infinite)); + + _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, + $"The fleet will be recalled at {newTime}"); + } +} + + else +{ + if (fleetId > 0) + { + Fleet fleet = _tbotInstance.UserData.fleets.Single(f => f.ID == fleetId); + DateTime returntime = (DateTime)fleet.BackTime; + + _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, + $"Fleet {fleetId} send to {possibleFleet.Mission} on {possibleFleet.Destination}, arrive at {possibleFleet.Duration} fuel consumed: {possibleFleet.Fuel.ToString("#,#", CultureInfo.InvariantCulture)}"); + + if (fromTelegram) + await _tbotInstance.SendTelegramMessage( + $"Fleet {fleetId} send to {possibleFleet.Mission} on {possibleFleet.Destination}, arrive at {possibleFleet.Duration}, returned at {returntime} fuel consumed: {possibleFleet.Fuel.ToString("#,#", CultureInfo.InvariantCulture)}"); + } +} + } public async Task SendFleet(Celestial origin, Ships ships, Coordinate destination, Missions mission, decimal speed, Resources payload = null, CharacterClass playerClass = CharacterClass.NoClass, bool force = false) { _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Sending fleet from {origin.Coordinate.ToString()} to {destination.ToString()}. Mission: {mission.ToString()}. Speed: {(speed * 10).ToString()}% Ships: {ships.ToString()}"); @@ -417,83 +473,94 @@ public async Task SendFleet(Celestial origin, Ships ships, Coordinate desti } } - /* - if ( - playerClass != CharacterClass.General && ( - speed == Speeds.FivePercent || - speed == Speeds.FifteenPercent || - speed == Speeds.TwentyfivePercent || - speed == Speeds.ThirtyfivePercent || - speed == Speeds.FourtyfivePercent || - speed == Speeds.FiftyfivePercent || - speed == Speeds.SixtyfivePercent || - speed == Speeds.SeventyfivePercent || - speed == Speeds.EightyfivePercent || - speed == Speeds.NinetyfivePercent - ) - ) {*/ - - if (!_calcService.GetValidSpeedsForClass(playerClass).Any(s => s == speed)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to send fleet: speed not available for your class"); - return (int) SendFleetCode.GenericError; - } - origin = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.LFBonuses); - FleetPrediction fleetPrediction = _calcService.CalcFleetPrediction(origin.Coordinate, destination, ships, mission, speed, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData, origin.LFBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.allianceClass); - _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"Calculated flight time (one-way): {TimeSpan.FromSeconds(fleetPrediction.Time).ToString()}"); - - var flightTime = mission switch { - Missions.Deploy => fleetPrediction.Time, +if (!_calcService.GetValidSpeedsForClass(playerClass).Any(s => s == speed)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, + "Unable to send fleet: speed not available for your class"); + return (int)SendFleetCode.GenericError; +} - // Use a ternary operator to conditionally handle IgnoreSleep setting - Missions.Expedition => (bool) _tbotInstance.InstanceSettings.Expeditions.IgnoreSleep - ? 1 - : (long) Math.Round((double) (2 * fleetPrediction.Time) + 3600, 0, MidpointRounding.ToPositiveInfinity), +origin = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.LFBonuses); + +FleetPrediction fleetPrediction = _calcService.CalcFleetPrediction( + origin.Coordinate, + destination, + ships, + mission, + speed, + _tbotInstance.UserData.researches, + _tbotInstance.UserData.serverData, + origin.LFBonuses, + _tbotInstance.UserData.userInfo.Class, + _tbotInstance.UserData.allianceClass +); + +_tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, + $"Calculated flight time (one-way): {TimeSpan.FromSeconds(fleetPrediction.Time)}"); + +var flightTime = mission switch +{ + Missions.Deploy => fleetPrediction.Time, + Missions.Expedition => (long)Math.Round((double)(2 * fleetPrediction.Time) + 3600, 0, MidpointRounding.ToPositiveInfinity), + _ => (long)Math.Round((double)(2 * fleetPrediction.Time), 0, MidpointRounding.ToPositiveInfinity) +}; +_tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, + $"Calculated flight time (full trip): {TimeSpan.FromSeconds(flightTime)}"); +_tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, + $"Calculated flight fuel: {fleetPrediction.Fuel}"); + +origin = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Resources); + +if (origin.Resources.Deuterium < fleetPrediction.Fuel) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, + "Unable to send fleet: not enough deuterium!"); + return (int)SendFleetCode.GenericError; +} - // Default case for other missions - _ => (long) Math.Round((double) (2 * fleetPrediction.Time), 0, MidpointRounding.ToPositiveInfinity) - }; - _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"Calculated flight time (full trip): {TimeSpan.FromSeconds(flightTime).ToString()}"); - _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"Calculated flight fuel: {fleetPrediction.Fuel.ToString()}"); +long fuelCapacity = _calcService.CalcFleetFuelCapacity( + ships, + _tbotInstance.UserData.serverData, + _tbotInstance.UserData.researches.HyperspaceTechnology, + _tbotInstance.UserData.userInfo.Class, + _tbotInstance.UserData.serverData.ProbeCargo +); + +if (fuelCapacity != 0 && fuelCapacity < fleetPrediction.Fuel) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, + "Unable to send fleet: ships don't have enough fuel capacity!"); + return (int)SendFleetCode.GenericError; +} - origin = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Resources); - if (origin.Resources.Deuterium < fleetPrediction.Fuel) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to send fleet: not enough deuterium!"); - return (int) SendFleetCode.GenericError; - } - if (_calcService.CalcFleetFuelCapacity(ships, _tbotInstance.UserData.serverData, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo) != 0 && _calcService.CalcFleetFuelCapacity(ships, _tbotInstance.UserData.serverData, _tbotInstance.UserData.researches.HyperspaceTechnology, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.serverData.ProbeCargo) < fleetPrediction.Fuel) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to send fleet: ships don't have enough fuel capacity!"); - return (int) SendFleetCode.GenericError; - } - if ( - (bool) _tbotInstance.InstanceSettings.SleepMode.Active && - DateTime.TryParse((string) _tbotInstance.InstanceSettings.SleepMode.GoToSleep, out DateTime goToSleep) && - DateTime.TryParse((string) _tbotInstance.InstanceSettings.SleepMode.WakeUp, out DateTime wakeUp) && - !force - ) { - DateTime time = await _tbotOgameBridge.GetDateTime(); - if (GeneralHelper.ShouldSleep(time, goToSleep, wakeUp)) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to send fleet: bed time has passed"); - return (int) SendFleetCode.AfterSleepTime; - } - if (goToSleep >= wakeUp) { - wakeUp = wakeUp.AddDays(1); - } - if (goToSleep < time) { - goToSleep = goToSleep.AddDays(1); - } - if (wakeUp < time) { - wakeUp = wakeUp.AddDays(1); - } - _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"goToSleep : {goToSleep.ToString()}"); - _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"wakeUp : {wakeUp.ToString()}"); - DateTime returnTime = time.AddSeconds(flightTime); - _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"returnTime : {returnTime.ToString()}"); - - if (returnTime >= goToSleep && returnTime <= wakeUp) { - _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, "Unable to send fleet: it would come back during sleep time"); - return (int) SendFleetCode.AfterSleepTime; - } - } +bool ignoreSleepForExpeditions = + mission == Missions.Expedition && + (bool)_tbotInstance.InstanceSettings.Expeditions.IgnoreSleep; + +if ( + (bool)_tbotInstance.InstanceSettings.SleepMode.Active && + DateTime.TryParse((string)_tbotInstance.InstanceSettings.SleepMode.GoToSleep, out DateTime goToSleep) && + DateTime.TryParse((string)_tbotInstance.InstanceSettings.SleepMode.WakeUp, out DateTime wakeUp) && + !force +) +{ + DateTime time = await _tbotOgameBridge.GetDateTime(); + + if (GeneralHelper.ShouldSleep(time, goToSleep, wakeUp)) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, + "Unable to send fleet: bed time has passed"); + return (int)SendFleetCode.AfterSleepTime; + } + + if (goToSleep >= wakeUp) wakeUp = wakeUp.AddDays(1); + if (goToSleep < time) goToSleep = goToSleep.AddDays(1); + if (wakeUp < time) wakeUp = wakeUp.AddDays(1); + + DateTime returnTime = time.AddSeconds(flightTime); + + if (returnTime >= goToSleep && returnTime <= wakeUp && !ignoreSleepForExpeditions) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, + "Unable to send fleet: it would come back during sleep time"); + return (int)SendFleetCode.AfterSleepTime; + } +} _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); int slotsToLeaveFree = (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree; if (_tbotInstance.UserData.slots.Free == 0) { @@ -532,14 +599,58 @@ public async Task SendFleet(Celestial origin, Ships ships, Coordinate desti } public async Task CancelFleet(Fleet fleet) { - //_tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"Recalling fleet id {fleet.ID} originally from {fleet.Origin.ToString()} to {fleet.Destination.ToString()} with mission: {fleet.Mission.ToString()}. Start time: {fleet.StartTime.ToString()} - Arrival time: {fleet.ArrivalTime.ToString()} - Ships: {fleet.Ships.ToString()}"); - _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + try { + bool isUnderAttack = await _ogameService.IsUnderAttack(); + if (isUnderAttack) { + var attacks = await _ogameService.GetAttacks(); + var attacksOnOrigin = attacks + .Where(a => a.Destination.IsSame(fleet.Origin)) + .OrderByDescending(a => a.ArriveIn) + .ToList(); + + if (attacksOnOrigin.Any()) { + var lastAttack = attacksOnOrigin.First(); + var currentTime = await _tbotOgameBridge.GetDateTime(); + var currentFleet = _tbotInstance.UserData.fleets.SingleOrDefault(f => f.ID == fleet.ID); + if (currentFleet != null && currentFleet.ArriveIn > 0) { + long estimatedReturnSeconds = currentFleet.ArriveIn * 2; + + _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"[RECALL-CHECK] Fleet {fleet.ID} would return in ~{estimatedReturnSeconds}s if recalled now"); + _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"[RECALL-CHECK] Last attack on {fleet.Origin} arrives in {lastAttack.ArriveIn}s"); + if (estimatedReturnSeconds < lastAttack.ArriveIn) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"[RECALL-BLOCKED] Fleet {fleet.ID} would return in {estimatedReturnSeconds}s but attack arrives in {lastAttack.ArriveIn}s - DELAYING RECALL!"); + + var newRecallDelay = (lastAttack.ArriveIn - estimatedReturnSeconds + (lastAttack.ArriveIn / 100 * 30)) * 1000; + if (newRecallDelay < 60000) newRecallDelay = 60000; + + _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"[RECALL-RESCHEDULED] New recall in {newRecallDelay/1000}s"); + + DisposeAndRemoveTimer($"RecallTimer-{fleet.ID.ToString()}"); + AddTimer($"RecallTimer-{fleet.ID.ToString()}", new Timer(RetireFleet, fleet, (int)newRecallDelay, Timeout.Infinite)); + + if ((bool) _tbotInstance.InstanceSettings.Defender.TelegramMessenger.Active) { + await _tbotInstance.SendTelegramMessage($"⚠️ Recall delayed! Attack still incoming on {fleet.Origin}. New recall in {newRecallDelay/1000}s"); + } + return; + } else { + _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"[RECALL-OK] Fleet {fleet.ID} return time ({estimatedReturnSeconds}s) is AFTER last attack ({lastAttack.ArriveIn}s) - proceeding with recall"); + } + } + } + } + } catch (Exception e) { + _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"[RECALL-CHECK] Error checking attacks before recall: {e.Message}"); + } + try { await Task.Delay((int) RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds)); _tbotInstance.log(LogLevel.Debug, LogSender.FleetScheduler, $"Recall Fleet with ID: {fleet.ID}"); await _ogameService.CancelFleet(fleet); await Task.Delay((int) RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds)); - _tbotInstance.UserData.fleets = await UpdateFleets(); + var updatedFleets = await UpdateFleets(); + lock (_fleetLock) { + _tbotInstance.UserData.fleets = updatedFleets; + } Fleet recalledFleet = _tbotInstance.UserData.fleets.SingleOrDefault(f => f.ID == fleet.ID) ?? new() { ID = (int) SendFleetCode.GenericError }; if (recalledFleet.ID == (int) SendFleetCode.GenericError) { _tbotInstance.log(LogLevel.Error, LogSender.FleetScheduler, "Unable to recall fleet: an unknon error has occurred, already recalled ?."); @@ -555,12 +666,8 @@ public async Task CancelFleet(Fleet fleet) { _tbotInstance.log(LogLevel.Warning, LogSender.FleetScheduler, $"Stacktrace: {e.StackTrace}"); return; } finally { - if (timers.TryGetValue($"RecallTimer-{fleet.ID.ToString()}", out Timer value)) { - value.Dispose(); - timers.Remove($"RecallTimer-{fleet.ID.ToString()}"); - } - - } + DisposeAndRemoveTimer($"RecallTimer-{fleet.ID.ToString()}"); +} } public async Task> UpdateFleets() { try { @@ -574,35 +681,40 @@ public async Task> UpdateFleets() { } public async void RetireFleet(object fleet) { - await CancelFleet((Fleet)fleet); + try { + await CancelFleet((Fleet)fleet); + } catch (Exception ex) { + _tbotInstance?.log(LogLevel.Error, LogSender.FleetScheduler, $"RetireFleet callback failed: {ex.Message}"); + } } private async void GhostandSleepAfterFleetsReturnAll(object state) { - if (timers.TryGetValue("GhostSleepTimer", out Timer value)) - value.Dispose(); - timers.Remove("GhostSleepTimer"); - + try { + DisposeAndRemoveTimer("GhostSleepTimer"); - var celestialsToFleetsave = await _tbotOgameBridge.UpdateCelestials(); - celestialsToFleetsave = celestialsToFleetsave.Where(c => c.Coordinate.Type == Celestials.Moon).ToList(); - if (celestialsToFleetsave.Count == 0) - celestialsToFleetsave = celestialsToFleetsave.Where(c => c.Coordinate.Type == Celestials.Planet).ToList(); + var celestialsToFleetsave = await _tbotOgameBridge.UpdateCelestials(); + var moons = celestialsToFleetsave.Where(c => c.Coordinate.Type == Celestials.Moon).ToList(); + var targets = moons.Count > 0 ? moons : celestialsToFleetsave.Where(c => c.Coordinate.Type == Celestials.Planet).ToList(); - foreach (Celestial celestial in celestialsToFleetsave) - await AutoFleetSave(celestial, false, _tbotInstance.SleepDuration, false, _tbotInstance.TelegramUserData.Mission, true); + foreach (Celestial celestial in targets) + await AutoFleetSave(celestial, false, _tbotInstance.SleepDuration, false, _tbotInstance.TelegramUserData.Mission, true); - await _tbotInstance.SleepNow(_tbotInstance.NextWakeUpTime); + await _tbotInstance.SleepNow(_tbotInstance.NextWakeUpTime); + } catch (Exception ex) { + _tbotInstance?.log(LogLevel.Error, LogSender.SleepMode, $"GhostSleep(all) timer callback failed: {ex.Message}"); + } } private async void GhostandSleepAfterFleetsReturn(object state) { - if (timers.TryGetValue("GhostSleepTimer", out Timer value)) - value.Dispose(); - timers.Remove("GhostSleepTimer"); - - await AutoFleetSave(_tbotInstance.TelegramUserData.CurrentCelestialToSave, false, _tbotInstance.SleepDuration, false, _tbotInstance.TelegramUserData.Mission, true); + try { + DisposeAndRemoveTimer("GhostSleepTimer"); - await _tbotInstance.SleepNow(_tbotInstance.NextWakeUpTime); + await AutoFleetSave(_tbotInstance.TelegramUserData.CurrentCelestialToSave, false, _tbotInstance.SleepDuration, false, _tbotInstance.TelegramUserData.Mission, true); + await _tbotInstance.SleepNow(_tbotInstance.NextWakeUpTime); + } catch (Exception ex) { + _tbotInstance?.log(LogLevel.Error, LogSender.SleepMode, $"GhostSleep timer callback failed: {ex.Message}"); + } } private bool CheckFuel(FleetHypotesis fleetHypotesis, Celestial celestial) { @@ -631,26 +743,20 @@ private async Task> GetFleetSaveDestination(List switch (mission) { case Missions.Transport: - //if (origin.Ships.Recycler == 0) { - // _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"No recycler available, skipping to next mission..."); - // break; - //} - //int playerid = _tbotInstance.UserData.userInfo.PlayerID; for (sys = origin.Coordinate.System - 5; sys <= origin.Coordinate.System + 5; sys++) { if (possibleDestinations.Count() == 10) { break; } sys = GeneralHelper.ClampSystem(sys); - galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); - foreach (var planet in galaxyInfo.Planets) { - //if (planet != null && planet.Inactive && !planet.Vacation && !planet.Administrator && !planet.Banned && !planet.StrongPlayer) { - if (planet != null && !planet.Vacation && !planet.Administrator && !planet.Banned && !planet.StrongPlayer) { - possibleDestinations.Add(new(planet.Coordinate.Galaxy, planet.Coordinate.System, planet.Coordinate.Position, Celestials.Planet)); - //if (planet.Moon != null) { - // possibleDestinations.Add(new(planet.Coordinate.Galaxy, planet.Coordinate.System, planet.Coordinate.Position, Celestials.Moon)); - //} - } - } + + var gi = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); + if (gi?.Planets == null) continue; + + foreach (var planet in gi.Planets) { + if (planet != null && !planet.Vacation && !planet.Administrator && !planet.Banned && !planet.StrongPlayer) { + possibleDestinations.Add(new(planet.Coordinate.Galaxy, planet.Coordinate.System, planet.Coordinate.Position, Celestials.Planet)); + } + } } if (possibleDestinations.Count() > 0) { @@ -716,11 +822,11 @@ private async Task> GetFleetSaveDestination(List sys = GeneralHelper.ClampSystem(sys); galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); foreach (var planet in galaxyInfo.Planets) { - pos++; - if (_calcService.IsAstrophysicsPositionValid((int) pos, (int)_tbotInstance.UserData.researches.Astrophysics) && planet != null) { - possibleDestinations.Add(new(origin.Coordinate.Galaxy, sys, pos)); - } - } + pos++; + if (pos >= 1 && pos <= 15 && planet == null) { + possibleDestinations.Add(new(origin.Coordinate.Galaxy, sys, pos)); + } + } } if (possibleDestinations.Count() > 0) { @@ -751,7 +857,6 @@ private async Task> GetFleetSaveDestination(List _tbotInstance.log(LogLevel.Information, LogSender.FleetScheduler, $"No recycler available, skipping to next mission..."); break; } - //int playerid = _tbotInstance.UserData.userInfo.PlayerID; for (sys = origin.Coordinate.System - 5; sys <= origin.Coordinate.System + 5; sys++) { sys = GeneralHelper.ClampSystem(sys); galaxyInfo = await _ogameService.GetGalaxyInfo(origin.Coordinate.Galaxy, sys); @@ -1352,7 +1457,6 @@ public async Task CollectImpl(bool fromTelegram, bool noLimit = newCelestials.Add(tempCelestial); } _tbotInstance.UserData.celestials = newCelestials; - //send notif only if sent via telegram if (fromTelegram) { if ((TotalMet > 0) || (TotalCri > 0) || (TotalDeut > 0)) { await _tbotInstance.SendTelegramMessage($"Resources sent!:\n{TotalMet} Metal\n{TotalCri} Crystal\n{TotalDeut} Deuterium"); @@ -1371,5 +1475,8 @@ public async Task CollectImpl(bool fromTelegram, bool noLimit = return RepatriateCode.Failure; } } - } + + + } +} \ No newline at end of file From 96c050a225868c269696b24376814b95937c2502 Mon Sep 17 00:00:00 2001 From: Killer Date: Sat, 21 Feb 2026 01:29:43 +0100 Subject: [PATCH 112/117] AutoFarmWorker update --- TBot/Workers/AutoFarmWorker.cs | 405 ++++++++++++++++++++++++++++----- 1 file changed, 342 insertions(+), 63 deletions(-) diff --git a/TBot/Workers/AutoFarmWorker.cs b/TBot/Workers/AutoFarmWorker.cs index 85393598..1f544e0c 100644 --- a/TBot/Workers/AutoFarmWorker.cs +++ b/TBot/Workers/AutoFarmWorker.cs @@ -21,6 +21,8 @@ public class AutoFarmWorker : WorkerBase { private readonly IFleetScheduler _fleetScheduler; private readonly ICalculationService _calculationService; private readonly ITBotOgamedBridge _tbotOgameBridge; + private readonly AutoFarmBlacklist _blacklist; + private readonly AutoFarmSuccessfulTargets _successfulTargets; public AutoFarmWorker(ITBotMain parentInstance, IOgameService ogameService, IFleetScheduler fleetScheduler, @@ -31,6 +33,10 @@ public AutoFarmWorker(ITBotMain parentInstance, _fleetScheduler = fleetScheduler; _calculationService = calculationService; _tbotOgameBridge = tbotOgameBridge; + string blacklistPath = $"autofarm_blacklist_{_tbotInstance.InstanceAlias}.json"; + _blacklist = new AutoFarmBlacklist(blacklistPath); + string successfulPath = $"autofarm_successful_{_tbotInstance.InstanceAlias}.json"; + _successfulTargets = new AutoFarmSuccessfulTargets(successfulPath); } public override bool IsWorkerEnabledBySettings() { try { @@ -90,11 +96,61 @@ private bool ShouldExcludeSystem(int galaxy, int system) { } private async Task> GetScannedTargetsFromGalaxy(int galaxy, int system) { - var galaxyInfo = await _ogameService.GetGalaxyInfo(galaxy, system); + GalaxyInfo galaxyInfo = null; + int retryCount = 0; + int maxRetries = 5; + + while (retryCount < maxRetries) { + try { + galaxyInfo = await _ogameService.GetGalaxyInfo(galaxy, system); + break; + } catch (Exception e) when (e.Message.Contains("system must be within") || e.Message.Contains("503") || e.Message.Contains("Service Unavailable")) { + retryCount++; + int waitSeconds = retryCount * 3; + + _tbotInstance.log(LogLevel.Debug, LogSender.AutoFarm, $"Exception details: {e.Message}"); + _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"Galaxy scan failed. Retry {retryCount}/{maxRetries} in {waitSeconds}s..."); + + if (retryCount < maxRetries) { + await Task.Delay(waitSeconds * 1000); + + try { + _tbotInstance.UserData.serverData = await _ogameService.GetServerData(); + _tbotInstance.log(LogLevel.Debug, LogSender.AutoFarm, $"ServerData after refresh: Systems={_tbotInstance.UserData.serverData.Systems}"); + } catch (Exception serverDataEx) { + _tbotInstance.log(LogLevel.Error, LogSender.AutoFarm, $"Failed to refresh ServerData: {serverDataEx.Message}"); + } + + if (retryCount == 4 && _tbotInstance.UserData.serverData.Systems == 0) { + _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"ServerData broken. Root cause: {e.Message}. Restarting ogamed..."); + + try { + _ogameService.KillOgamedExecutable(); + await Task.Delay(5000); + _ogameService.RerunOgamed(); + await Task.Delay(10000); + + try { + _tbotInstance.UserData.serverData = await _ogameService.GetServerData(); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"ServerData after restart: Systems={_tbotInstance.UserData.serverData.Systems}"); + } catch (Exception restartEx) { + _tbotInstance.log(LogLevel.Error, LogSender.AutoFarm, $"Failed to get ServerData after ogamed restart: {restartEx.Message}"); + } + } catch (Exception ogamedEx) { + _tbotInstance.log(LogLevel.Error, LogSender.AutoFarm, $"Failed to restart ogamed: {ogamedEx.Message}"); + _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"Stacktrace: {ogamedEx.StackTrace}"); + } + } + } else { + _tbotInstance.log(LogLevel.Error, LogSender.AutoFarm, $"Galaxy scan failed after {maxRetries} retries."); + throw; + } + } + } + var planets = galaxyInfo.Planets.Where(p => p != null && p.Inactive && !p.Administrator && !p.Banned && !p.Vacation); List scannedTargets = planets.Cast().ToList(); await _fleetScheduler.UpdateFleets(); - //Remove all targets that are currently under attack (necessary if bot or instance is restarted) scannedTargets.RemoveAll(t => _tbotInstance.UserData.fleets.Any(f => f.Destination.IsSame(t.Coordinate) && f.Mission == Missions.Attack)); return scannedTargets; } @@ -151,8 +207,6 @@ private void AddMoons(List scannedTargets) { private FarmTarget CheckDuplicatesAndGetExisting(Celestial planet) { var exists = _tbotInstance.UserData.farmTargets.Where(t => t != null && t.Celestial.HasCoords(planet.Coordinate)).ToList(); if (exists.Count() > 1) { - // It can exist if was processed in a previous execution - //Remove all except the first to be able to continue var firstExisting = exists.First(); _tbotInstance.UserData.farmTargets.RemoveAll(c => c.Celestial.HasCoords(planet.Coordinate)); _tbotInstance.UserData.farmTargets.Add(firstExisting); @@ -165,27 +219,32 @@ private FarmTarget CheckDuplicatesAndGetExisting(Celestial planet) { } private FarmTarget GetFarmTarget(Celestial planet) { - // Check if planet with coordinates exists already in _tbotInstance.UserData.farmTargets list. + bool blacklistActive = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "Blacklist") && + SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "Active") && + (bool) _tbotInstance.InstanceSettings.AutoFarm.Blacklist.Active; + + if (blacklistActive && _blacklist.IsBlacklisted(planet.Coordinate)) { + var blacklistedTarget = _blacklist.GetBlacklistedTarget(planet.Coordinate); + _tbotInstance.log(LogLevel.Debug, LogSender.AutoFarm, $"Target {planet.ToString()} is blacklisted (Reason: {blacklistedTarget.Reason}). Skipping..."); + return null; + } + var target = CheckDuplicatesAndGetExisting(planet); if (target == null) { - // Does not exist, add to _tbotInstance.UserData.farmTargets list, set state to probes pending. target = new(planet, FarmState.ProbesPending); _tbotInstance.UserData.farmTargets.Add(target); } else { - // Already exists, update _tbotInstance.UserData.farmTargets list with updated planet. target.Celestial = planet; if (target.State == FarmState.Idle) target.State = FarmState.ProbesPending; - // If target marked not suitable based on a non-expired espionage report, skip probing. if (target.State == FarmState.NotSuitable && target.Report != null) { _tbotInstance.log(LogLevel.Debug, LogSender.AutoFarm, $"Target {planet.ToString()} marked as Not Suitable. Skipping..."); return null; } - // If probes are already sent or if an attack is pending, skip probing. if (target.State == FarmState.ProbesSent || target.State == FarmState.AttackPending) { _tbotInstance.log(LogLevel.Debug, LogSender.AutoFarm, $"Target {planet.ToString()} marked as {target.State.ToString()}. Skipping..."); return null; @@ -226,25 +285,19 @@ private async Task GetBestOrigin(List closestCelesti int neededProbes, int slotsToLeaveFree, int freeSlots) { - //Set first celestial as default best Origin SpyOriginResult bestOrigin = new SpyOriginResult(closestCelestials.First(), int.MaxValue, freeSlots); foreach (var closest in closestCelestials) { - // Update ships of the current planet var tempCelestial = await _tbotOgameBridge.UpdatePlanet(closest, UpdateTypes.Ships); celestialProbes.Remove(closest.ID); celestialProbes.Add(closest.ID, tempCelestial.Ships.EspionageProbe); if (celestialProbes[closest.ID] >= neededProbes) { - //There are enough probes so it's the best origin and we can stop searching bestOrigin = new SpyOriginResult(closest, freeSlots); break; } - // No probes available in this celestial _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - // If there are no free slots, update the minimum time to wait for current missions return. - // If there are no free slots, wait for probes to come back to current celestial. if (freeSlots <= slotsToLeaveFree) { var espionageMissions = _calculationService.GetMissionsInProgress(closest.Coordinate, Missions.Spy, _tbotInstance.UserData.fleets); if (espionageMissions.Any()) { @@ -263,12 +316,10 @@ private async Task GetBestOrigin(List closestCelesti } } } else { - //If no bestOrigin detected, the total number of probes is not enough but there are free slots, then calculate if can be built from this celestial _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"Cannot spy {target.Celestial.Coordinate.ToString()} from {closest.Coordinate.ToString()}, insufficient probes ({celestialProbes[closest.ID]}/{neededProbes})."); if (bestOrigin.BackIn < int.MaxValue) continue; - //If there is no bestOrigin, check if can be a good origin (it has enough resources to build probes) tempCelestial = await _tbotOgameBridge.UpdatePlanet(closest, UpdateTypes.Constructions); if (tempCelestial.Constructions.BuildingID == (int) Buildables.Shipyard || tempCelestial.Constructions.BuildingID == (int) Buildables.NaniteFactory) { Buildables buildingInProgress = (Buildables) tempCelestial.Constructions.BuildingID; @@ -315,7 +366,6 @@ private async Task WaitForFreeSlots(int freeSlots, int slotsToLeaveFree) { _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); while (freeSlots <= slotsToLeaveFree) { - // No slots available, wait for first fleet of any mission type to return. _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); if (_tbotInstance.UserData.fleets.Any()) { int interval = (int) ((1000 * _tbotInstance.UserData.fleets.OrderBy(fleet => fleet.BackIn).First().BackIn) + RandomizeHelper.CalcRandomInterval(IntervalType.LessThanASecond)); @@ -325,7 +375,7 @@ private async Task WaitForFreeSlots(int freeSlots, int slotsToLeaveFree) { freeSlots = _tbotInstance.UserData.slots.Free; } else { _tbotInstance.log(LogLevel.Error, LogSender.AutoFarm, "Error: No fleet slots available and no fleets returning!"); - throw new Exception("No fleet slots available and no fleets returning!"); //TODO: Create custom exception + throw new Exception("No fleet slots available and no fleets returning!"); } } return freeSlots; @@ -333,10 +383,13 @@ private async Task WaitForFreeSlots(int freeSlots, int slotsToLeaveFree) { protected override async Task Execute() { bool stop = false; + bool stopAfterFullScan = false; + bool finishedFullScan = false; try { _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, "Running autofarm..."); - if ((bool) _tbotInstance.InstanceSettings.AutoFarm.Active) { - // If not enough slots are free, the farmer cannot run. + stopAfterFullScan = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "StopAfterFullScan") + && (bool)_tbotInstance.InstanceSettings.AutoFarm.StopAfterFullScan; + if ((bool) _tbotInstance.InstanceSettings.AutoFarm.Active) { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); int freeSlots = _tbotInstance.UserData.slots.Free; @@ -347,47 +400,141 @@ protected override async Task Execute() { } try { - // Prune all reports older than KeepReportFor and all reports of state AttackSent: information no longer actual. await PruneOldReports(); - // Keep local record of _tbotInstance.UserData.celestials, to be updated by autofarmer itself, to reduce ogamed calls. var celestialProbes = await GetCelestialProbes(); - // Keep track of number of targets probed. int numProbed = 0; - /// Galaxy scanning + target probing. _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, "Detecting farm targets..."); bool stopAutoFarm = false; - foreach (var range in _tbotInstance.InstanceSettings.AutoFarm.ScanRange) { + var scanRanges = ((IEnumerable)_tbotInstance.InstanceSettings.AutoFarm.ScanRange).ToList(); + + var allScanRanges = ((IEnumerable)_tbotInstance.InstanceSettings.AutoFarm.ScanRange).ToList(); + int totalSystemsAcrossAllGalaxies = allScanRanges.Sum(r => (int)r.EndSystem - (int)r.StartSystem + 1); + int instanceHash = Math.Abs(_tbotInstance.InstanceAlias.GetHashCode()); + int minSpacing = 499; + int numSlotsGlobal = Math.Max(1, totalSystemsAcrossAllGalaxies / minSpacing); + int globalSlotIndex = instanceHash % numSlotsGlobal; + int globalOffset = globalSlotIndex * minSpacing; + + int targetGalaxy = 1; + int targetSystem = 1; + int remainingOffset = globalOffset; + foreach (var r in allScanRanges) { + int systemsInRange = (int)r.EndSystem - (int)r.StartSystem + 1; + if (remainingOffset < systemsInRange) { + targetGalaxy = (int)r.Galaxy; + targetSystem = (int)r.StartSystem + remainingOffset; + break; + } + remainingOffset -= systemsInRange; + } + + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"[GLOBAL SPACING] Instance: {_tbotInstance.InstanceAlias}"); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"[GLOBAL SPACING] Total systems across all galaxies: {totalSystemsAcrossAllGalaxies}"); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"[GLOBAL SPACING] Num slots globally: {numSlotsGlobal}"); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"[GLOBAL SPACING] Global slot index: {globalSlotIndex}"); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"[GLOBAL SPACING] Global offset: {globalOffset} systems"); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"[GLOBAL SPACING] Target Galaxy: {targetGalaxy}, Target System: {targetSystem}"); + + var orderedRanges = scanRanges + .OrderBy(r => (int)r.Galaxy) + .ThenBy(r => (int)r.StartSystem) + .ToList(); + + if (!orderedRanges.Any()) { + _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, "No scan ranges match galaxies with planets. Skipping AutoFarm."); + stopAutoFarm = true; + } + + int startRangeIndex = _tbotInstance.UserData.autoFarmLastRangeIndex; + if (startRangeIndex < 0 || startRangeIndex >= orderedRanges.Count) { + startRangeIndex = 0; + } + if (_tbotInstance.UserData.autoFarmLastGalaxy == 0 && _tbotInstance.UserData.autoFarmLastSystem == 0) { + int idx = orderedRanges.FindIndex(r => (int)r.Galaxy == targetGalaxy); + if (idx >= 0) startRangeIndex = idx; + _tbotInstance.UserData.autoFarmLastRangeIndex = startRangeIndex; + } + + bool globalOffsetUsed = false; + + for (int rangeIndex = startRangeIndex; rangeIndex < orderedRanges.Count; rangeIndex++) { if (stopAutoFarm) break; - if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "TargetsProbedBeforeAttack") && ((int) _tbotInstance.InstanceSettings.AutoFarm.TargetsProbedBeforeAttack != 0) && numProbed >= (int) _tbotInstance.InstanceSettings.AutoFarm.TargetsProbedBeforeAttack) { + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "TargetsProbedBeforeAttack") && ((int)_tbotInstance.InstanceSettings.AutoFarm.TargetsProbedBeforeAttack != 0) && numProbed >= (int)_tbotInstance.InstanceSettings.AutoFarm.TargetsProbedBeforeAttack) { break; } + var range = orderedRanges[rangeIndex]; + int galaxy = (int) range.Galaxy; - int startSystem = (int) range.StartSystem; + int originalStartSystem = (int) range.StartSystem; int endSystem = (int) range.EndSystem; - - // Loop from start to end system. - for (var system = startSystem; system <= endSystem; system++) { + int startSystem = originalStartSystem; + bool isRandomStart = false; + + if (_tbotInstance.UserData.autoFarmLastGalaxy == galaxy && + _tbotInstance.UserData.autoFarmLastSystem >= originalStartSystem && + _tbotInstance.UserData.autoFarmLastSystem <= endSystem) { + + startSystem = _tbotInstance.UserData.autoFarmLastSystem; + isRandomStart = false; + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, + $"Resuming scan from Galaxy {galaxy} System {startSystem}"); + } + else { + startSystem = originalStartSystem; + isRandomStart = false; + + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, + $"[START] Galaxy {galaxy} - Ordered start at system {startSystem}"); + } + + int systemsToScan = endSystem - originalStartSystem + 1; + int scannedCount = 0; + + for (var offset = 0; offset < systemsToScan && scannedCount < systemsToScan; offset++) { + int system = startSystem + offset; + if (system > endSystem) { + break; + } + scannedCount++; if (stopAutoFarm) break; if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "TargetsProbedBeforeAttack") && ((int) _tbotInstance.InstanceSettings.AutoFarm.TargetsProbedBeforeAttack != 0) && numProbed >= (int) _tbotInstance.InstanceSettings.AutoFarm.TargetsProbedBeforeAttack) { _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, "Maximum number of targets to probe reached, proceeding to attack."); + int nextSystem = system + 1; + if (nextSystem <= endSystem) { + _tbotInstance.UserData.autoFarmLastRangeIndex = rangeIndex; + _tbotInstance.UserData.autoFarmLastGalaxy = galaxy; + _tbotInstance.UserData.autoFarmLastSystem = nextSystem; + } else { + int nextRangeIndex = rangeIndex + 1; + if (nextRangeIndex < orderedRanges.Count) { + var nextRange = orderedRanges[nextRangeIndex]; + _tbotInstance.UserData.autoFarmLastRangeIndex = nextRangeIndex; + _tbotInstance.UserData.autoFarmLastGalaxy = (int)nextRange.Galaxy; + _tbotInstance.UserData.autoFarmLastSystem = (int)nextRange.StartSystem; + } else { + _tbotInstance.UserData.autoFarmLastRangeIndex = 0; + _tbotInstance.UserData.autoFarmLastGalaxy = 0; + _tbotInstance.UserData.autoFarmLastSystem = 0; + finishedFullScan = true; + } + } + stopAutoFarm = true; break; } - // Check excluded system. bool excludeSystem = ShouldExcludeSystem(galaxy, system); if (excludeSystem) continue; var scannedTargets = await GetScannedTargetsFromGalaxy(galaxy, system); - _tbotInstance.log(LogLevel.Debug, LogSender.AutoFarm, $"Found {scannedTargets.Count} targets on System {galaxy}:{system}"); if (!scannedTargets.Any()) @@ -397,11 +544,9 @@ protected override async Task Execute() { AddMoons(scannedTargets); } - // Add each planet that has inactive status to _tbotInstance.UserData.farmTargets. foreach (Celestial planet in scannedTargets) { if (stopAutoFarm) break; - // Check if target is below set minimum rank. if (!IsTargetInMinimumRank(planet, scannedTargets)) { continue; } @@ -412,21 +557,24 @@ protected override async Task Execute() { break; } - // Check excluded planet. if (ShouldExcludePlanet(planet)) continue; - // Manage existing Target or generate a new one. If should not be processed returns null var target = GetFarmTarget(planet); if (target == null) continue; - // Send spy probe from closest celestial with available probes to the target. List tempCelestials = (_tbotInstance.InstanceSettings.AutoFarm.Origin.Length > 0) ? _calculationService.ParseCelestialsList(_tbotInstance.InstanceSettings.AutoFarm.Origin, _tbotInstance.UserData.celestials) : _tbotInstance.UserData.celestials; + List closestCelestials = tempCelestials .OrderByDescending(planet => planet.Coordinate.Type == Celestials.Moon) .OrderBy(c => _calculationService.CalcDistance(c.Coordinate, target.Celestial.Coordinate, _tbotInstance.UserData.serverData)).ToList(); + if (!closestCelestials.Any()) { + _tbotInstance.log(LogLevel.Debug, LogSender.AutoFarm, $"No origin celestials available. Skipping target {target.Celestial.ToString()}"); + continue; + } + int neededProbes = GetNeededProbes(target); @@ -435,7 +583,6 @@ protected override async Task Execute() { _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); var probesInMission = _tbotInstance.UserData.fleets.Select(c => c.Ships).Sum(c => c.EspionageProbe); - //Calculate best origin var bestOrigin = await GetBestOrigin(closestCelestials, celestialProbes, target, @@ -456,7 +603,6 @@ protected override async Task Execute() { continue; } - // If local record indicate not enough espionage probes are available, update record to make sure this is correct. if (celestialProbes[bestOrigin.Origin.ID] < neededProbes) { var tempCelestial = await _tbotOgameBridge.UpdatePlanet(bestOrigin.Origin, UpdateTypes.Ships); celestialProbes.Remove(bestOrigin.Origin.ID); @@ -466,7 +612,7 @@ protected override async Task Execute() { if (celestialProbes[bestOrigin.Origin.ID] < neededProbes) { _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"Insufficient probes ({celestialProbes[bestOrigin.Origin.ID]}/{neededProbes})."); if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "BuildProbes") && _tbotInstance.InstanceSettings.AutoFarm.BuildProbes == true) { - //Check if probes can be built + var tempCelestial = await _tbotOgameBridge.UpdatePlanet(bestOrigin.Origin, UpdateTypes.Constructions); if (tempCelestial.Constructions.BuildingID == (int) Buildables.Shipyard || tempCelestial.Constructions.BuildingID == (int) Buildables.NaniteFactory) { Buildables buildingInProgress = (Buildables) tempCelestial.Constructions.BuildingID; @@ -527,6 +673,17 @@ protected override async Task Execute() { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); freeSlots = _tbotInstance.UserData.slots.Free; freeSlots = await WaitForFreeSlots(freeSlots, slotsToLeaveFree); + + bestOrigin.Origin = await _tbotOgameBridge.UpdatePlanet(bestOrigin.Origin, UpdateTypes.Ships); + var availableProbes = bestOrigin.Origin.Ships.EspionageProbe; + + if (availableProbes < neededProbes) { + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, + $"Insufficient probes on {bestOrigin.Origin.ToString()} ({availableProbes}/{neededProbes}). Skipping {target.ToString()}."); + fleetId = (int) SendFleetCode.GenericError; + break; + } + fleetId = await _fleetScheduler.SendFleet(bestOrigin.Origin, ships, target.Celestial.Coordinate, Missions.Spy, Speeds.HundredPercent); if (fleetId == (int)SendFleetCode.NotEnoughSlots) { _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Another worker took the slot, waiting again for a free slot... Retry count: {retryCount}/{maxRetryCount}"); @@ -560,13 +717,36 @@ protected override async Task Execute() { } } } + if (!stopAutoFarm && ( + !SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "TargetsProbedBeforeAttack") || + (int)_tbotInstance.InstanceSettings.AutoFarm.TargetsProbedBeforeAttack == 0 || + numProbed <= (int)_tbotInstance.InstanceSettings.AutoFarm.TargetsProbedBeforeAttack) + ) { + _tbotInstance.UserData.autoFarmLastGalaxy = 0; + _tbotInstance.UserData.autoFarmLastSystem = 0; + + _tbotInstance.UserData.autoFarmLastRangeIndex = 0; + + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, + "Full scan cycle completed, resetting scan position for next cycle"); + + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "StopAfterFullScan") && + (bool)_tbotInstance.InstanceSettings.AutoFarm.StopAfterFullScan) { + + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, + "StopAfterFullScan=true -> Full scan completed. Stopping AutoFarm and waiting for /startautofarm."); + + stop = true; + return; + } + } + } catch (Exception e) { _tbotInstance.log(LogLevel.Debug, LogSender.AutoFarm, $"Exception: {e.Message}"); _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"Stacktrace: {e.StackTrace}"); _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, "Unable to parse scan range"); } - // Wait for all espionage fleets to return. _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); Fleet firstReturning = _calculationService.GetLastReturningEspionage(_tbotInstance.UserData.fleets); if (firstReturning != null) { @@ -577,7 +757,6 @@ protected override async Task Execute() { _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, "Processing espionage reports of found inactives..."); - /// Process reports. await AutoFarmProcessReports(); _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); @@ -618,7 +797,6 @@ protected override async Task Execute() { }; int MaxSlots = _calculationService.CalcSlotsPriority(Feature.AutoFarm, rankSlotsPriority, _tbotInstance.UserData.slots, _tbotInstance.UserData.fleets, (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree); - /// Send attacks. List attackTargets; if (_tbotInstance.InstanceSettings.AutoFarm.PreferedResource == "Metal") attackTargets = _tbotInstance.UserData.farmTargets.Where(t => t.State == FarmState.AttackPending).OrderByDescending(t => t.Report.Loot(_tbotInstance.UserData.userInfo.Class).Metal).ToList(); @@ -682,9 +860,8 @@ protected override async Task Execute() { tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.Resources); tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.LFBonuses); if (tempCelestial.Ships != null && tempCelestial.Ships.GetAmount(cargoShip) >= (numCargo + _tbotInstance.InstanceSettings.AutoFarm.MinCargosToKeep)) { - // TODO Future: If fleet composition is changed, update ships passed to CalcFlightTime. speed = 0; - if (/*cargoShip == Buildables.EspionageProbe &&*/ SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MinLootFuelRatio") && _tbotInstance.InstanceSettings.AutoFarm.MinLootFuelRatio != 0) { + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MinLootFuelRatio") && _tbotInstance.InstanceSettings.AutoFarm.MinLootFuelRatio != 0) { long maxFlightTime = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MaxFlightTime") ? (long) _tbotInstance.InstanceSettings.AutoFarm.MaxFlightTime : 86400; var optimalSpeed = _calculationService.CalcOptimalFarmSpeed(tempCelestial.Coordinate, target.Celestial.Coordinate, attackingShips, target.Report.Loot(_tbotInstance.UserData.userInfo.Class), lootFuelRatio, maxFlightTime, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData, tempCelestial.LFBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.allianceClass); if (optimalSpeed == 0) { @@ -724,13 +901,11 @@ protected override async Task Execute() { if (fromCelestial == null) { _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"No origin celestial available near destination {target.Celestial.ToString()} with enough cargo ships."); - // TODO Future: If prefered cargo ship is not available or not sufficient capacity, combine with other cargo type. foreach (var closest in closestCelestials) { tempCelestial = closest; tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.Ships); tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.Resources); tempCelestial = await _tbotOgameBridge.UpdatePlanet(tempCelestial, UpdateTypes.LFBonuses); - // TODO Future: If fleet composition is changed, update ships passed to CalcFlightTime. speed = 0; if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "FleetSpeed") && _tbotInstance.InstanceSettings.AutoFarm.FleetSpeed > 0) { speed = (int) _tbotInstance.InstanceSettings.AutoFarm.FleetSpeed / 10; @@ -740,7 +915,7 @@ protected override async Task Execute() { } } else { speed = 0; - if (/*cargoShip == Buildables.EspionageProbe &&*/ SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MinLootFuelRatio") && _tbotInstance.InstanceSettings.AutoFarm.MinLootFuelRatio != 0) { + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MinLootFuelRatio") && _tbotInstance.InstanceSettings.AutoFarm.MinLootFuelRatio != 0) { long maxFlightTime = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MaxFlightTime") ? (long) _tbotInstance.InstanceSettings.AutoFarm.MaxFlightTime : 86400; var optimalSpeed = _calculationService.CalcOptimalFarmSpeed(tempCelestial.Coordinate, target.Celestial.Coordinate, attackingShips, target.Report.Loot(_tbotInstance.UserData.userInfo.Class), lootFuelRatio, maxFlightTime, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData, tempCelestial.LFBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.allianceClass); if (optimalSpeed == 0) { @@ -813,7 +988,6 @@ protected override async Task Execute() { continue; } - // Only execute update slots if our local copy indicates we have run out. if (freeSlots <= slotsToLeaveFree) { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); freeSlots = _tbotInstance.UserData.slots.Free; @@ -821,7 +995,6 @@ protected override async Task Execute() { while (freeSlots <= slotsToLeaveFree) { _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - // No slots free, wait for first fleet to come back. if (_tbotInstance.UserData.fleets.Any()) { int interval = (int) ((1000 * _tbotInstance.UserData.fleets.OrderBy(fleet => fleet.BackIn).First().BackIn) + RandomizeHelper.CalcRandomInterval(IntervalType.AFewSeconds)); if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MaxWaitTime") && (int) _tbotInstance.InstanceSettings.AutoFarm.MaxWaitTime != 0 && interval > (int) _tbotInstance.InstanceSettings.AutoFarm.MaxWaitTime * 1000) { @@ -845,12 +1018,36 @@ protected override async Task Execute() { .ToList(); if (_tbotInstance.UserData.slots.Free > slotsToLeaveFree && slotUsed.Count() < MaxSlots) { + fromCelestial = await _tbotOgameBridge.UpdatePlanet(fromCelestial, UpdateTypes.Ships); + var availableShips = fromCelestial.Ships.GetAmount(cargoShip) - (long) _tbotInstance.InstanceSettings.AutoFarm.MinCargosToKeep; + if (availableShips <= 0) { + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"No {cargoShip.ToString()} available on {fromCelestial.ToString()} (all ships already in use). Skipping target."); + continue; + } + if (availableShips < numCargo) { + _tbotInstance.log(LogLevel.Debug, LogSender.AutoFarm, $"Only {availableShips} {cargoShip.ToString()} available (needed {numCargo}). Adjusting fleet size."); + numCargo = availableShips; + attackingShips = new Ships(); + attackingShips.Add(cargoShip, numCargo); + + var cargoCapacity = _calculationService.CalcFleetCapacity( + attackingShips, _tbotInstance.UserData.serverData, _tbotInstance.UserData.researches.HyperspaceTechnology, + fromCelestial.LFBonuses, _tbotInstance.UserData.userInfo.Class); + var totalLoot = target.Report.Loot(_tbotInstance.UserData.userInfo.Class).TotalResources; + + if (cargoCapacity < totalLoot) { + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, + $"Insufficient cargo space after adjustment. {numCargo} {cargoShip.ToString()} can carry {cargoCapacity:N0} but need {totalLoot:N0}. Skipping target."); + continue; + } + } + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Attacking {target.ToString()} from {fromCelestial} with {numCargo} {cargoShip.ToString()}."); Ships ships = new(); fromCelestial = await _tbotOgameBridge.UpdatePlanet(fromCelestial, UpdateTypes.LFBonuses); speed = 0; - if (/*cargoShip == Buildables.EspionageProbe &&*/ SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MinLootFuelRatio") && _tbotInstance.InstanceSettings.AutoFarm.MinLootFuelRatio != 0) { + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MinLootFuelRatio") && _tbotInstance.InstanceSettings.AutoFarm.MinLootFuelRatio != 0) { long maxFlightTime = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "MaxFlightTime") ? (long) _tbotInstance.InstanceSettings.AutoFarm.MaxFlightTime : 86400; var optimalSpeed = _calculationService.CalcOptimalFarmSpeed(fromCelestial.Coordinate, target.Celestial.Coordinate, attackingShips, target.Report.Loot(_tbotInstance.UserData.userInfo.Class), lootFuelRatio, maxFlightTime, _tbotInstance.UserData.researches, _tbotInstance.UserData.serverData, fromCelestial.LFBonuses, _tbotInstance.UserData.userInfo.Class, _tbotInstance.UserData.allianceClass); if (optimalSpeed == 0) { @@ -877,6 +1074,8 @@ protected override async Task Execute() { if (fleetId > (int) SendFleetCode.GenericError) { freeSlots--; + + _successfulTargets.RecordAttack(target.Celestial.Coordinate, loot); } else if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; return; @@ -895,8 +1094,12 @@ protected override async Task Execute() { _tbotInstance.log(LogLevel.Error, LogSender.AutoFarm, $"AutoFarm Exception: {e.Message}"); _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"Stacktrace: {e.StackTrace}"); } finally { + if (stopAfterFullScan && finishedFullScan) { + stop = true; + } + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Attacked targets: {_tbotInstance.UserData.farmTargets.Where(t => t.State == FarmState.AttackSent).Count()}"); - _tbotInstance.UserData.farmTargets.RemoveAll(t => t.State == FarmState.ProbesSent); //At this point no ProbesSent should remain in farmTargets + _tbotInstance.UserData.farmTargets.RemoveAll(t => t.State == FarmState.ProbesSent); if (!_tbotInstance.UserData.isSleeping) { if (stop) { _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Stopping feature."); @@ -927,12 +1130,7 @@ protected override async Task Execute() { } } - /// - /// Checks all received espionage reports and updates _tbotInstance.UserData.farmTargets to reflect latest data retrieved from reports. - /// private async Task AutoFarmProcessReports() { - // TODO Future: Read espionage reports in separate thread (concurently with probing itself). - // TODO Future: Check if probes were destroyed, blacklist target if so to avoid additional kills. List summaryReports = await _ogameService.GetEspionageReports(); foreach (var summary in summaryReports) { if (summary.Type == EspionageReportType.Action) @@ -949,10 +1147,8 @@ private async Task AutoFarmProcessReports() { FarmTarget target; var matchingTarget = _tbotInstance.UserData.farmTargets.Where(t => t.HasCoords(report.Coordinate)); if (matchingTarget.Count() == 0) { - // Report received of planet not in _tbotInstance.UserData.farmTargets. If inactive: add, otherwise: ignore. if (!report.IsInactive) continue; - //Get corresponding planet. Add to target list. var galaxyInfo = await _ogameService.GetGalaxyInfo(report.Coordinate.Galaxy, report.Coordinate.System); var planet = galaxyInfo.Planets.FirstOrDefault(p => p != null && p.Inactive && !p.Administrator && !p.Banned && !p.Vacation && p.HasCoords(report.Coordinate)); if (planet != null) { @@ -968,7 +1164,6 @@ private async Task AutoFarmProcessReports() { var newFarmTarget = target; if (target.Report != null && DateTime.Compare(report.Date, target.Report.Date) < 0) { - // Target has a more recent report. Delete report. await _ogameService.DeleteReport(report.ID); continue; } @@ -996,17 +1191,88 @@ private async Task AutoFarmProcessReports() { } else { newFarmTarget.State = FarmState.NotSuitable; _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Target {report.Coordinate} not suitable - defences present."); + bool blacklistActive = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "Blacklist") && + SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "Active") && + (bool) _tbotInstance.InstanceSettings.AutoFarm.Blacklist.Active; + if (blacklistActive) { + int hoursUntilReset = SettingsService.GetSetting(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "ResetAfterHours", 48); + _blacklist.AddTarget(report.Coordinate, BlacklistReason.HasDefense, hoursUntilReset); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Target {report.Coordinate} blacklisted for {hoursUntilReset}h (defenses present)."); + } } } else { newFarmTarget.State = FarmState.NotSuitable; _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Target {report.Coordinate} not suitable - insufficient loot ({report.Loot(_tbotInstance.UserData.userInfo.Class)})"); + bool blacklistActiveLowRes = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "Blacklist") && + SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "Active") && + (bool) _tbotInstance.InstanceSettings.AutoFarm.Blacklist.Active; + if (blacklistActiveLowRes) { + long minResources = SettingsService.GetSetting(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "MinimumResourcesToNotBlacklist", (long)500000); + if (report.Loot(_tbotInstance.UserData.userInfo.Class).TotalResources < minResources) { + int hoursUntilReset = SettingsService.GetSetting(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "ResetAfterHours", 48); + _blacklist.AddTarget(report.Coordinate, BlacklistReason.LowResources, hoursUntilReset); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Target {report.Coordinate} blacklisted for {hoursUntilReset}h (low resources: {report.Loot(_tbotInstance.UserData.userInfo.Class)})."); + } + } } _tbotInstance.UserData.farmTargets.Remove(target); _tbotInstance.UserData.farmTargets.Add(newFarmTarget); + } else { + bool processAllReports = (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "ProcessAllReports") && + (bool) _tbotInstance.InstanceSettings.AutoFarm.ProcessAllReports) || + (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "Blacklist") && + SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "ProcessAllReports") && + (bool) _tbotInstance.InstanceSettings.AutoFarm.Blacklist.ProcessAllReports); + if (processAllReports && report.IsInactive) { + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Processing report for {report.Coordinate} not scanned by TBot (ProcessAllReports enabled)..."); + var galaxyInfo = await _ogameService.GetGalaxyInfo(report.Coordinate.Galaxy, report.Coordinate.System); + var planet = galaxyInfo.Planets.FirstOrDefault(p => p != null && p.Inactive && !p.Administrator && !p.Banned && !p.Vacation && p.HasCoords(report.Coordinate)); + if (planet != null) { + var target = GetFarmTarget(planet); + if (target != null) { + var newFarmTarget = target; + Buildables cargoShip; + Enum.TryParse((string) _tbotInstance.InstanceSettings.AutoFarm.CargoType, true, out cargoShip); + bool isUsingProbes = cargoShip == Buildables.EspionageProbe && _tbotInstance.UserData.serverData.ProbeCargo == 1 ? true : false; + newFarmTarget.Report = report; + if (report.Loot(_tbotInstance.UserData.userInfo.Class).TotalResources > _tbotInstance.InstanceSettings.AutoFarm.MinimumResources) { + if (report.HasFleetInformation && report.HasDefensesInformation) { + if (report.IsDefenceless(isUsingProbes)) { + newFarmTarget.State = FarmState.AttackPending; + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Attack pending on {report.Coordinate}. Loot: {report.Loot(_tbotInstance.UserData.userInfo.Class)}"); + } else { + newFarmTarget.State = FarmState.NotSuitable; + bool blacklistActiveDefense2 = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "Blacklist") && + (bool) _tbotInstance.InstanceSettings.AutoFarm.Blacklist.Active; + if (blacklistActiveDefense2) { + int hoursUntilReset = SettingsService.GetSetting(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "ResetAfterHours", 48); + _blacklist.AddTarget(report.Coordinate, BlacklistReason.HasDefense, hoursUntilReset); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Target {report.Coordinate} blacklisted for {hoursUntilReset}h (defenses present)."); + } + } + } + } else { + newFarmTarget.State = FarmState.NotSuitable; + bool blacklistActiveLowRes2 = SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.AutoFarm, "Blacklist") && + (bool) _tbotInstance.InstanceSettings.AutoFarm.Blacklist.Active; + if (blacklistActiveLowRes2) { + long minResources = SettingsService.GetSetting(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "MinimumResourcesToNotBlacklist", (long)500000); + if (report.Loot(_tbotInstance.UserData.userInfo.Class).TotalResources < minResources) { + int hoursUntilReset = SettingsService.GetSetting(_tbotInstance.InstanceSettings.AutoFarm.Blacklist, "ResetAfterHours", 48); + _blacklist.AddTarget(report.Coordinate, BlacklistReason.LowResources, hoursUntilReset); + _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Target {report.Coordinate} blacklisted for {hoursUntilReset}h (low resources: {report.Loot(_tbotInstance.UserData.userInfo.Class)})."); + } + } + } + _tbotInstance.UserData.farmTargets.Remove(target); + _tbotInstance.UserData.farmTargets.Add(newFarmTarget); + } + } } else { _tbotInstance.log(LogLevel.Information, LogSender.AutoFarm, $"Target {report.Coordinate} not scanned by TBot, ignoring..."); } + } } catch (Exception e) { _tbotInstance.log(LogLevel.Error, LogSender.AutoFarm, $"AutoFarmProcessReports Exception: {e.Message}"); _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"Stacktrace: {e.StackTrace}"); @@ -1014,8 +1280,21 @@ private async Task AutoFarmProcessReports() { } } - await _ogameService.DeleteAllEspionageReports(); + int deleteRetries = 3; + for (int i = 0; i < deleteRetries; i++) { + try { + await _ogameService.DeleteAllEspionageReports(); + break; + } catch (Exception e) when (e.Message.Contains("503") || e.Message.Contains("Service Unavailable") || e.Message.Contains("Unable to delete")) { + if (i < deleteRetries - 1) { + _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"Failed to delete espionage reports (503 error), retry {i + 1}/{deleteRetries}..."); + await Task.Delay(3000); + } else { + _tbotInstance.log(LogLevel.Warning, LogSender.AutoFarm, $"Could not delete espionage reports after {deleteRetries} attempts. Will try next cycle."); + } + } + } } } -} +} \ No newline at end of file From e4ff387fc314c2db63d43a1cd4541d2ffa914c28 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Fri, 13 Mar 2026 19:06:33 +0100 Subject: [PATCH 113/117] # v3.3.8 ## Add multi-origin cyclic discovery rotation to AutoDiscoveryWorker - Enabled sending AutoDiscovery missions from multiple configured coordinates (origins) - Implemented nearest-system-first traversal logic per origin - Added system-by-system rotation mechanism to cover multiple systems sequentially - Implemented cyclic loop (after finishing the configured/available systems, starts again from the beginning) - Preserved existing configuration compatibility ### Behaviour Instead of sending AutoDiscovery only from a single coordinate, the worker now iterates through multiple origins and dispatches AutoDiscovery missions to nearby systems sequentially in a rotating cycle. This improves discovery coverage and reduces repetitive targeting of the same systems. ### Notes Existing configurations remain functional. If only one origin is defined, behaviour remains unchanged. ## Introduce AutoFarm Model layer and update UserData integration This PR introduces a new Model layer for AutoFarm state handling. ### Changes: * Added TBot/Model folder * Implemented AutoFarmBlacklist * Implemented AutoFarmSuccessfulTargets * Implemented SharedFarmState * Updated UserData service to support new model integration * Structure remains clean and separated from existing Models namespace. ## Improve concurrency handling and async processing in DefenderWorker This PR refactors DefenderWorker to improve concurrency safety and async handling. ### Changes: * Introduced ConcurrentDictionary to prevent duplicate attack processing * Added TTL-based tracking for handled attacks * Replaced Task.Factory.StartNew with Task.Run * Updated attack handling to use proper async/await flow * Cleaned up obsolete comments and streamlined logic ### Impact: * Prevents duplicate or parallel processing of the same attack * Improves thread safety * Ensures controlled and sequential attack handling * Modernizes async usage to current best practices No other components were modified. ## Add multi-origin expedition support in ExpeditionWorker Refactored ExpeditionWorker to support multi-origin expedition dispatching. ### The worker now: * Accepts an arbitrary number of configured origin coordinates * Iterates through all origins during execution * Dispatches one expedition per origin * Maintains compatibility with existing configuration structure * This enables scalable expedition sending without manual per-origin configuration duplication. ## Improve FleetScheduler logic and enhance colonization handling ### Refactored and extended FleetScheduler to improve colonization logic and fleet scheduling behavior. * Enhanced colonization fleet dispatch strategy * Improved execution flow and scheduling control * Reduced potential edge-case misfires * Structural cleanup for maintainability * This change increases reliability of automated colonization operations. ## AutoFarmWorker update * Added configurable blacklist mechanism * Automatic blacklist reset after defined time window * Resource threshold filtering to avoid low-value farming * Optional full report processing for better coverage * Controlled stop after complete scan cycle * Structural cleanup for improved maintainability * Targets below the defined resource threshold are temporarily excluded * Blacklisted targets are automatically re-evaluated after reset period * Report scanning logic is more predictable and controlled * Reduced redundant farming attempts on low-profit targets * Improved execution flow stability * This update improves farming efficiency, reduces unnecessary attacks, and enhances the overall reliability of AutoFarmWorker operations. --- TBot/TBot.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index 8519e699..df949434 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.3.7 + 3.3.8 Tbot.Program AnyCPU;x64;x86 - 2025 © TBot + 2026 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.3.7 - 3.3.6 + 3.3.8 + 3.3.8 OGame Bot False ELK-Lab.pfx From bd0179b6799428af297409be78be21e62904a51b Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 15 Mar 2026 09:09:30 +0100 Subject: [PATCH 114/117] * fix overflow --- TBot/Workers/ExpeditionsWorker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index ee18ad97..9d72900b 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -257,7 +257,7 @@ protected override async Task Execute() { var originExps = origins.ToDictionary(o => o, o => 0); - int remaining = Math.Min(expsToSend, capacity.Values.Sum()); + Int64 remaining = Math.Min(expsToSend, capacity.Values.Sum()); while (remaining > 0) { bool progressed = false; From 20f7ee7d10d3834bdfb9c1f7bae8fc513cb7f784 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Sun, 15 Mar 2026 09:10:15 +0100 Subject: [PATCH 115/117] v3.3.9 * fix overflow --- TBot/TBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TBot/TBot.csproj b/TBot/TBot.csproj index df949434..3418f260 100644 --- a/TBot/TBot.csproj +++ b/TBot/TBot.csproj @@ -5,15 +5,15 @@ net9.0 disable TBot - 3.3.8 + 3.3.9 Tbot.Program AnyCPU;x64;x86 2026 © TBot https://licenses.nuget.org/MIT https://www.ogame-tbot.net https://github.com/ogame-tbot/TBot - 3.3.8 - 3.3.8 + 3.3.9 + 3.3.9 OGame Bot False ELK-Lab.pfx From a50dfa08111964bc3bda49c6372980b6b3956366 Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Mon, 16 Mar 2026 12:14:21 +0100 Subject: [PATCH 116/117] * fix overflow --- TBot/Workers/ExpeditionsWorker.cs | 309 +++++++++++++++--------------- 1 file changed, 155 insertions(+), 154 deletions(-) diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index 9d72900b..a990d6c0 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -34,7 +34,7 @@ public ExpeditionsWorker(ITBotMain parentInstance, } public override bool IsWorkerEnabledBySettings() { try { - return (bool)_tbotInstance.InstanceSettings.Expeditions.Active; + return (bool) _tbotInstance.InstanceSettings.Expeditions.Active; } catch (Exception) { return false; } @@ -49,16 +49,16 @@ public override Feature GetFeature() { public override LogSender GetLogSender() { return LogSender.Expeditions; } - private int CountActiveExpeditionsFromOrigin(Celestial origin) { - return _tbotInstance.UserData.fleets.Count(f => - f.Mission == Missions.Expedition && - f.Origin != null && - f.Origin.Galaxy == origin.Coordinate.Galaxy && - f.Origin.System == origin.Coordinate.System && - f.Origin.Position == origin.Coordinate.Position && - (int)f.Origin.Type == (int)origin.Coordinate.Type - ); -} + private int CountActiveExpeditionsFromOrigin(Celestial origin) { + return _tbotInstance.UserData.fleets.Count(f => + f.Mission == Missions.Expedition && + f.Origin != null && + f.Origin.Galaxy == origin.Coordinate.Galaxy && + f.Origin.System == origin.Coordinate.System && + f.Origin.Position == origin.Coordinate.Position && + (int) f.Origin.Type == (int) origin.Coordinate.Type + ); + } protected override async Task Execute() { bool stop = false; bool delay = false; @@ -67,7 +67,7 @@ protected override async Task Execute() { DateTime time; DateTime newTime; - if ((bool)_tbotInstance.InstanceSettings.Expeditions.Active) { + if ((bool) _tbotInstance.InstanceSettings.Expeditions.Active) { _tbotInstance.UserData.researches = await _tbotOgameBridge.UpdateResearches(); if (_tbotInstance.UserData.researches.Astrophysics == 0) { DoLog(LogLevel.Information, "Skipping: Astrophysics not yet researched!"); @@ -121,15 +121,15 @@ protected override async Task Execute() { (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; - int MaxSlots = _tbotInstance.UserData.slots.Total - - (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree; + int MaxSlots = _tbotInstance.UserData.slots.Total + - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree; - if (MaxSlots < 0) - MaxSlots = 0; + if (MaxSlots < 0) + MaxSlots = 0; int expsToSend; if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForAllExpeditions") - && (bool)_tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { + && (bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { if (_tbotInstance.UserData.slots.ExpInUse == 0) expsToSend = _tbotInstance.UserData.slots.ExpTotal; else @@ -141,8 +141,8 @@ protected override async Task Execute() { DoLog(LogLevel.Debug, $"Expedition slot free: {expsToSend}"); if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForMajorityOfExpeditions") - && (bool)_tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions) { - if ((double)expsToSend < Math.Round((double)_tbotInstance.UserData.slots.ExpTotal / 2D, 0, MidpointRounding.ToZero) + 1D) { + && (bool) _tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions) { + if ((double) expsToSend < Math.Round((double) _tbotInstance.UserData.slots.ExpTotal / 2D, 0, MidpointRounding.ToZero) + 1D) { DoLog(LogLevel.Debug, $"Majority of expedition already in flight, Skipping..."); expsToSend = 0; } @@ -168,9 +168,9 @@ protected override async Task Execute() { try { foreach (var origin in _tbotInstance.InstanceSettings.Expeditions.Origin) { Coordinate customOriginCoords = new( - (int)origin.Galaxy, - (int)origin.System, - (int)origin.Position, + (int) origin.Galaxy, + (int) origin.System, + (int) origin.Position, Enum.Parse(origin.Type.ToString()) ); Celestial customOrigin = _tbotInstance.UserData.celestials @@ -217,69 +217,73 @@ protected override async Task Execute() { ); } - if ((bool)_tbotInstance.InstanceSettings.Expeditions.RandomizeOrder) { + if ((bool) _tbotInstance.InstanceSettings.Expeditions.RandomizeOrder) { origins = origins.Shuffle().ToList(); } - LFBonuses lfBonuses = origins.First().LFBonuses; - - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - - var expFleets = _tbotInstance.UserData.fleets - .Where(f => f.Mission == Missions.Expedition && f.Origin != null) - .ToList(); - - DoLog(LogLevel.Warning, $"[EXP DEBUG] Active expeditions total = {expFleets.Count}"); - - foreach (var f in expFleets) { - DoLog( - LogLevel.Warning, - $"[EXP DEBUG] Fleet origin: G{f.Origin.Galaxy}:{f.Origin.System}:{f.Origin.Position} Type={f.Origin.Type}" - ); - } - int maxPerOrigin = int.MaxValue; - if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "MaxExpeditionsPerOrigin")) { - maxPerOrigin = (int)_tbotInstance.InstanceSettings.Expeditions.MaxExpeditionsPerOrigin; - } - - DoLog(LogLevel.Warning, - $"[EXP DEBUG] Origins count={origins.Count}, expsToSend={expsToSend}, maxPerOrigin={maxPerOrigin}"); - - var capacity = new Dictionary(); - foreach (var o in origins) { - int active = CountActiveExpeditionsFromOrigin(o); - int cap = Math.Max(0, maxPerOrigin - active); - capacity[o] = cap; - - DoLog(LogLevel.Warning, - $"[EXP DEBUG] Origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + - $"active={active} maxPerOrigin={maxPerOrigin} cap={cap}"); - } - - var originExps = origins.ToDictionary(o => o, o => 0); - - Int64 remaining = Math.Min(expsToSend, capacity.Values.Sum()); - - while (remaining > 0) { - bool progressed = false; - - foreach (var o in origins) { - if (remaining <= 0) break; - - if (originExps[o] < capacity[o]) { - originExps[o]++; - remaining--; - progressed = true; - } - } - - if (!progressed) break; - } - - foreach (var o in origins) { - DoLog(LogLevel.Warning, - $"[EXP DEBUG] PLAN origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + - $"willSend={originExps[o]} (cap={capacity[o]})"); - } + LFBonuses lfBonuses = origins.First().LFBonuses; + + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + + var expFleets = _tbotInstance.UserData.fleets + .Where(f => f.Mission == Missions.Expedition && f.Origin != null) + .ToList(); + + DoLog(LogLevel.Warning, $"[EXP DEBUG] Active expeditions total = {expFleets.Count}"); + + foreach (var f in expFleets) { + DoLog( + LogLevel.Warning, + $"[EXP DEBUG] Fleet origin: G{f.Origin.Galaxy}:{f.Origin.System}:{f.Origin.Position} Type={f.Origin.Type}" + ); + } + int maxPerOrigin = int.MaxValue; + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "MaxExpeditionsPerOrigin")) { + maxPerOrigin = (int) _tbotInstance.InstanceSettings.Expeditions.MaxExpeditionsPerOrigin; + } + + DoLog(LogLevel.Warning, + $"[EXP DEBUG] Origins count={origins.Count}, expsToSend={expsToSend}, maxPerOrigin={maxPerOrigin}"); + + var capacity = new Dictionary(); + foreach (var o in origins) { + int active = CountActiveExpeditionsFromOrigin(o); + int cap = Math.Max(0, maxPerOrigin - active); + capacity[o] = cap; + + DoLog(LogLevel.Warning, + $"[EXP DEBUG] Origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + + $"active={active} maxPerOrigin={maxPerOrigin} cap={cap}"); + } + + var originExps = origins.ToDictionary(o => o, o => 0); + + // Use .Sum(x => (long)x) to ensure the addition happens in 64-bit space + //int remaining = Math.Min(expsToSend, capacity.Values.Sum()); + int remaining = (int) Math.Min((long) expsToSend, capacity.Values.Sum(x => (long) x)); + + while (remaining > 0) { + bool progressed = false; + + foreach (var o in origins) { + if (remaining <= 0) + break; + + if (originExps[o] < capacity[o]) { + originExps[o]++; + remaining--; + progressed = true; + } + } + + if (!progressed) + break; + } + + foreach (var o in origins) { + DoLog(LogLevel.Warning, + $"[EXP DEBUG] PLAN origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + + $"willSend={originExps[o]} (cap={capacity[o]})"); + } int delayExpedition = 0; foreach (var origin in origins) { @@ -289,32 +293,31 @@ protected override async Task Execute() { delayExpedition--; else continue; - } - else if (origin.Ships.IsEmpty()) { + } else if (origin.Ships.IsEmpty()) { DoLog(LogLevel.Warning, "Unable to send expeditions: no ships available"); delayExpedition++; continue; } else { Ships fleet; - if ((bool)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Active) { + if ((bool) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Active) { fleet = new( - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LightFighter, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.HeavyFighter, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Cruiser, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battleship, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battlecruiser, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Bomber, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Destroyer, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Deathstar, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.SmallCargo, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LargeCargo, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.ColonyShip, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Recycler, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.EspionageProbe, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LightFighter, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.HeavyFighter, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Cruiser, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battleship, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battlecruiser, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Bomber, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Destroyer, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Deathstar, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.SmallCargo, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LargeCargo, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.ColonyShip, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Recycler, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.EspionageProbe, 0, 0, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Reaper, - (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Pathfinder + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Reaper, + (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Pathfinder ); if (!origin.Ships.HasAtLeast(fleet, expsToSendFromThisOrigin)) { DoLog(LogLevel.Warning, $"Unable to send expeditions: not enough ships in origin {origin}"); @@ -335,11 +338,11 @@ protected override async Task Execute() { var availableShips = origin.Ships.GetMovableShips(); if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "PrimaryToKeep") - && (int)_tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep > 0) { + && (int) _tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep > 0) { availableShips.SetAmount( primaryShip, Math.Max(0, availableShips.GetAmount(primaryShip) - - (long)_tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep)); + - (long) _tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep)); } fleet = _calculationService.CalcFullExpeditionShips( @@ -359,9 +362,9 @@ protected override async Task Execute() { List syslist = new(); for (int i = 0; i < expsToSendFromThisOrigin; i++) { Coordinate destination; - if ((bool)_tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Active) { + if ((bool) _tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Active) { var rand = new Random(); - int range = (int)_tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Range; + int range = (int) _tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Range; while (expsToSendFromThisOrigin > range * 2) range += 1; @@ -385,53 +388,53 @@ protected override async Task Execute() { } _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - Resources payload = new(); - if ((long)_tbotInstance.InstanceSettings.Expeditions.FuelToCarry > 0) { - payload.Deuterium = (long)_tbotInstance.InstanceSettings.Expeditions.FuelToCarry; - } + Resources payload = new(); + if ((long) _tbotInstance.InstanceSettings.Expeditions.FuelToCarry > 0) { + payload.Deuterium = (long) _tbotInstance.InstanceSettings.Expeditions.FuelToCarry; + } if (_tbotInstance.UserData.slots.ExpFree > 0) { - var originUpdated = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Ships); - - _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - if (_tbotInstance.UserData.slots.ExpFree <= 0) { - DoLog(LogLevel.Information, "Unable to send expeditions: no expedition slots available."); - delay = true; - return; - } - - if (fleet == null || fleet.IsEmpty() || !originUpdated.Ships.HasAtLeast(fleet, 1)) { - DoLog(LogLevel.Warning, $"Skipping expedition: no ships available on origin {originUpdated}"); - delayExpedition++; - break; - } - - var fleetId = await _fleetScheduler.SendFleet( - originUpdated, - fleet, - destination, - Missions.Expedition, - Speeds.HundredPercent, - payload - ); - if (fleetId == (int)SendFleetCode.AfterSleepTime) { + var originUpdated = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Ships); + + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + if (_tbotInstance.UserData.slots.ExpFree <= 0) { + DoLog(LogLevel.Information, "Unable to send expeditions: no expedition slots available."); + delay = true; + return; + } + + if (fleet == null || fleet.IsEmpty() || !originUpdated.Ships.HasAtLeast(fleet, 1)) { + DoLog(LogLevel.Warning, $"Skipping expedition: no ships available on origin {originUpdated}"); + delayExpedition++; + break; + } + + var fleetId = await _fleetScheduler.SendFleet( + originUpdated, + fleet, + destination, + Missions.Expedition, + Speeds.HundredPercent, + payload + ); + if (fleetId == (int) SendFleetCode.AfterSleepTime) { stop = true; return; } - if (fleetId == (int)SendFleetCode.NotEnoughSlots) { + if (fleetId == (int) SendFleetCode.NotEnoughSlots) { delay = true; return; } - int minWait = (int)_tbotInstance.InstanceSettings.Expeditions.MinWaitNextFleet; - int maxWait = (int)_tbotInstance.InstanceSettings.Expeditions.MaxWaitNextFleet; + int minWait = (int) _tbotInstance.InstanceSettings.Expeditions.MinWaitNextFleet; + int maxWait = (int) _tbotInstance.InstanceSettings.Expeditions.MaxWaitNextFleet; - if (maxWait < minWait) { - DoLog(LogLevel.Warning, - $"Expeditions wait misconfigured (MinWaitNextFleet={minWait} > MaxWaitNextFleet={maxWait}). Swapping values."); - (minWait, maxWait) = (maxWait, minWait); - } - var rndWaitTimeMs = (int)RandomizeHelper.CalcRandomIntervalSecToMs(minWait, maxWait); + if (maxWait < minWait) { + DoLog(LogLevel.Warning, + $"Expeditions wait misconfigured (MinWaitNextFleet={minWait} > MaxWaitNextFleet={maxWait}). Swapping values."); + (minWait, maxWait) = (maxWait, minWait); + } + var rndWaitTimeMs = (int) RandomizeHelper.CalcRandomIntervalSecToMs(minWait, maxWait); DoLog(LogLevel.Information, $"Wait {(rndWaitTimeMs / 1000f):0.00}s for next Expedition"); await Task.Delay(rndWaitTimeMs, _ct); @@ -452,7 +455,7 @@ protected override async Task Execute() { .Where(fleet => fleet.Mission == Missions.Expedition) .ToList(); - if ((bool)_tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { + if ((bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { orderedFleets = orderedFleets.OrderByDescending(fleet => fleet.BackIn).ToList(); } else { orderedFleets = orderedFleets.OrderBy(fleet => fleet.BackIn).ToList(); @@ -461,14 +464,14 @@ protected override async Task Execute() { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); if ((orderedFleets.Count == 0) || (_tbotInstance.UserData.slots.ExpFree > 0 && - !((bool)_tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) && - !((bool)_tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions))) { + !((bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) && + !((bool) _tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions))) { interval = RandomizeHelper.CalcRandomInterval(IntervalType.AboutFiveMinutes); } else { - interval = (int)((1000 * orderedFleets.First().BackIn) + + interval = (int) ((1000 * orderedFleets.First().BackIn) + RandomizeHelper.CalcRandomIntervalSecToMs( - (int)_tbotInstance.InstanceSettings.Expeditions.MinWaitNextRound, - (int)_tbotInstance.InstanceSettings.Expeditions.MaxWaitNextRound)); + (int) _tbotInstance.InstanceSettings.Expeditions.MinWaitNextRound, + (int) _tbotInstance.InstanceSettings.Expeditions.MaxWaitNextRound)); } time = await _tbotOgameBridge.GetDateTime(); @@ -477,16 +480,14 @@ protected override async Task Execute() { DoLog(LogLevel.Information, $"Next check at {newTime}"); await _tbotOgameBridge.CheckCelestials(); } - } - catch (Exception e) { + } catch (Exception e) { DoLog(LogLevel.Warning, $"HandleExpeditions exception: {e.Message}"); DoLog(LogLevel.Warning, $"Stacktrace: {e.StackTrace}"); long interval = RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo); var time = await _tbotOgameBridge.GetDateTime(); ChangeWorkerPeriod(interval); DoLog(LogLevel.Information, $"Next check at {time.AddMilliseconds(interval)}"); - } - finally { + } finally { if (!_tbotInstance.UserData.isSleeping) { if (stop) { DoLog(LogLevel.Information, $"Stopping feature."); @@ -502,8 +503,8 @@ protected override async Task Execute() { + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } catch { interval = RandomizeHelper.CalcRandomInterval( - (int)_tbotInstance.InstanceSettings.Expeditions.CheckIntervalMin, - (int)_tbotInstance.InstanceSettings.Expeditions.CheckIntervalMax); + (int) _tbotInstance.InstanceSettings.Expeditions.CheckIntervalMin, + (int) _tbotInstance.InstanceSettings.Expeditions.CheckIntervalMax); } ChangeWorkerPeriod(interval); DoLog(LogLevel.Information, $"Next check at {time.AddMilliseconds(interval)}"); From 5ce357ffa51fd7c35fc154e6843812479e29bdab Mon Sep 17 00:00:00 2001 From: CrynogarTM Date: Mon, 16 Mar 2026 12:18:15 +0100 Subject: [PATCH 117/117] * fix overflow --- TBot/Workers/ExpeditionsWorker.cs | 294 +++++++++++++++--------------- 1 file changed, 147 insertions(+), 147 deletions(-) diff --git a/TBot/Workers/ExpeditionsWorker.cs b/TBot/Workers/ExpeditionsWorker.cs index a990d6c0..197ab4bd 100644 --- a/TBot/Workers/ExpeditionsWorker.cs +++ b/TBot/Workers/ExpeditionsWorker.cs @@ -34,7 +34,7 @@ public ExpeditionsWorker(ITBotMain parentInstance, } public override bool IsWorkerEnabledBySettings() { try { - return (bool) _tbotInstance.InstanceSettings.Expeditions.Active; + return (bool)_tbotInstance.InstanceSettings.Expeditions.Active; } catch (Exception) { return false; } @@ -49,16 +49,16 @@ public override Feature GetFeature() { public override LogSender GetLogSender() { return LogSender.Expeditions; } - private int CountActiveExpeditionsFromOrigin(Celestial origin) { - return _tbotInstance.UserData.fleets.Count(f => - f.Mission == Missions.Expedition && - f.Origin != null && - f.Origin.Galaxy == origin.Coordinate.Galaxy && - f.Origin.System == origin.Coordinate.System && - f.Origin.Position == origin.Coordinate.Position && - (int) f.Origin.Type == (int) origin.Coordinate.Type - ); - } + private int CountActiveExpeditionsFromOrigin(Celestial origin) { + return _tbotInstance.UserData.fleets.Count(f => + f.Mission == Missions.Expedition && + f.Origin != null && + f.Origin.Galaxy == origin.Coordinate.Galaxy && + f.Origin.System == origin.Coordinate.System && + f.Origin.Position == origin.Coordinate.Position && + (int)f.Origin.Type == (int)origin.Coordinate.Type + ); +} protected override async Task Execute() { bool stop = false; bool delay = false; @@ -67,7 +67,7 @@ protected override async Task Execute() { DateTime time; DateTime newTime; - if ((bool) _tbotInstance.InstanceSettings.Expeditions.Active) { + if ((bool)_tbotInstance.InstanceSettings.Expeditions.Active) { _tbotInstance.UserData.researches = await _tbotOgameBridge.UpdateResearches(); if (_tbotInstance.UserData.researches.Astrophysics == 0) { DoLog(LogLevel.Information, "Skipping: Astrophysics not yet researched!"); @@ -121,15 +121,15 @@ protected override async Task Execute() { (int)_tbotInstance.UserData.fleets.Count(f => f.Mission == Missions.Harvest)) }; - int MaxSlots = _tbotInstance.UserData.slots.Total - - (int) _tbotInstance.InstanceSettings.General.SlotsToLeaveFree; + int MaxSlots = _tbotInstance.UserData.slots.Total + - (int)_tbotInstance.InstanceSettings.General.SlotsToLeaveFree; - if (MaxSlots < 0) - MaxSlots = 0; + if (MaxSlots < 0) + MaxSlots = 0; int expsToSend; if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForAllExpeditions") - && (bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { + && (bool)_tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { if (_tbotInstance.UserData.slots.ExpInUse == 0) expsToSend = _tbotInstance.UserData.slots.ExpTotal; else @@ -141,8 +141,8 @@ protected override async Task Execute() { DoLog(LogLevel.Debug, $"Expedition slot free: {expsToSend}"); if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "WaitForMajorityOfExpeditions") - && (bool) _tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions) { - if ((double) expsToSend < Math.Round((double) _tbotInstance.UserData.slots.ExpTotal / 2D, 0, MidpointRounding.ToZero) + 1D) { + && (bool)_tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions) { + if ((double)expsToSend < Math.Round((double)_tbotInstance.UserData.slots.ExpTotal / 2D, 0, MidpointRounding.ToZero) + 1D) { DoLog(LogLevel.Debug, $"Majority of expedition already in flight, Skipping..."); expsToSend = 0; } @@ -168,9 +168,9 @@ protected override async Task Execute() { try { foreach (var origin in _tbotInstance.InstanceSettings.Expeditions.Origin) { Coordinate customOriginCoords = new( - (int) origin.Galaxy, - (int) origin.System, - (int) origin.Position, + (int)origin.Galaxy, + (int)origin.System, + (int)origin.Position, Enum.Parse(origin.Type.ToString()) ); Celestial customOrigin = _tbotInstance.UserData.celestials @@ -217,73 +217,70 @@ protected override async Task Execute() { ); } - if ((bool) _tbotInstance.InstanceSettings.Expeditions.RandomizeOrder) { + if ((bool)_tbotInstance.InstanceSettings.Expeditions.RandomizeOrder) { origins = origins.Shuffle().ToList(); } - LFBonuses lfBonuses = origins.First().LFBonuses; - - _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); - - var expFleets = _tbotInstance.UserData.fleets - .Where(f => f.Mission == Missions.Expedition && f.Origin != null) - .ToList(); - - DoLog(LogLevel.Warning, $"[EXP DEBUG] Active expeditions total = {expFleets.Count}"); - - foreach (var f in expFleets) { - DoLog( - LogLevel.Warning, - $"[EXP DEBUG] Fleet origin: G{f.Origin.Galaxy}:{f.Origin.System}:{f.Origin.Position} Type={f.Origin.Type}" - ); - } - int maxPerOrigin = int.MaxValue; - if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "MaxExpeditionsPerOrigin")) { - maxPerOrigin = (int) _tbotInstance.InstanceSettings.Expeditions.MaxExpeditionsPerOrigin; - } - - DoLog(LogLevel.Warning, - $"[EXP DEBUG] Origins count={origins.Count}, expsToSend={expsToSend}, maxPerOrigin={maxPerOrigin}"); - - var capacity = new Dictionary(); - foreach (var o in origins) { - int active = CountActiveExpeditionsFromOrigin(o); - int cap = Math.Max(0, maxPerOrigin - active); - capacity[o] = cap; - - DoLog(LogLevel.Warning, - $"[EXP DEBUG] Origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + - $"active={active} maxPerOrigin={maxPerOrigin} cap={cap}"); - } - - var originExps = origins.ToDictionary(o => o, o => 0); + LFBonuses lfBonuses = origins.First().LFBonuses; + + _tbotInstance.UserData.fleets = await _fleetScheduler.UpdateFleets(); + + var expFleets = _tbotInstance.UserData.fleets + .Where(f => f.Mission == Missions.Expedition && f.Origin != null) + .ToList(); + + DoLog(LogLevel.Warning, $"[EXP DEBUG] Active expeditions total = {expFleets.Count}"); + + foreach (var f in expFleets) { + DoLog( + LogLevel.Warning, + $"[EXP DEBUG] Fleet origin: G{f.Origin.Galaxy}:{f.Origin.System}:{f.Origin.Position} Type={f.Origin.Type}" + ); + } + int maxPerOrigin = int.MaxValue; + if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "MaxExpeditionsPerOrigin")) { + maxPerOrigin = (int)_tbotInstance.InstanceSettings.Expeditions.MaxExpeditionsPerOrigin; + } + + DoLog(LogLevel.Warning, + $"[EXP DEBUG] Origins count={origins.Count}, expsToSend={expsToSend}, maxPerOrigin={maxPerOrigin}"); + + var capacity = new Dictionary(); + foreach (var o in origins) { + int active = CountActiveExpeditionsFromOrigin(o); + int cap = Math.Max(0, maxPerOrigin - active); + capacity[o] = cap; + + DoLog(LogLevel.Warning, + $"[EXP DEBUG] Origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + + $"active={active} maxPerOrigin={maxPerOrigin} cap={cap}"); + } + + var originExps = origins.ToDictionary(o => o, o => 0); // Use .Sum(x => (long)x) to ensure the addition happens in 64-bit space - //int remaining = Math.Min(expsToSend, capacity.Values.Sum()); - int remaining = (int) Math.Min((long) expsToSend, capacity.Values.Sum(x => (long) x)); + long remaining = (long) Math.Min((long) expsToSend, capacity.Values.Sum(x => (long) x)); while (remaining > 0) { - bool progressed = false; + bool progressed = false; - foreach (var o in origins) { - if (remaining <= 0) - break; + foreach (var o in origins) { + if (remaining <= 0) break; - if (originExps[o] < capacity[o]) { - originExps[o]++; - remaining--; - progressed = true; - } - } + if (originExps[o] < capacity[o]) { + originExps[o]++; + remaining--; + progressed = true; + } + } - if (!progressed) - break; - } + if (!progressed) break; + } - foreach (var o in origins) { - DoLog(LogLevel.Warning, - $"[EXP DEBUG] PLAN origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + - $"willSend={originExps[o]} (cap={capacity[o]})"); - } + foreach (var o in origins) { + DoLog(LogLevel.Warning, + $"[EXP DEBUG] PLAN origin {o.Coordinate.Galaxy}:{o.Coordinate.System}:{o.Coordinate.Position} Type={o.Coordinate.Type} " + + $"willSend={originExps[o]} (cap={capacity[o]})"); + } int delayExpedition = 0; foreach (var origin in origins) { @@ -293,31 +290,32 @@ protected override async Task Execute() { delayExpedition--; else continue; - } else if (origin.Ships.IsEmpty()) { + } + else if (origin.Ships.IsEmpty()) { DoLog(LogLevel.Warning, "Unable to send expeditions: no ships available"); delayExpedition++; continue; } else { Ships fleet; - if ((bool) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Active) { + if ((bool)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Active) { fleet = new( - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LightFighter, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.HeavyFighter, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Cruiser, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battleship, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battlecruiser, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Bomber, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Destroyer, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Deathstar, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.SmallCargo, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LargeCargo, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.ColonyShip, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Recycler, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.EspionageProbe, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LightFighter, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.HeavyFighter, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Cruiser, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battleship, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Battlecruiser, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Bomber, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Destroyer, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Deathstar, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.SmallCargo, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.LargeCargo, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.ColonyShip, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Recycler, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.EspionageProbe, 0, 0, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Reaper, - (long) _tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Pathfinder + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Reaper, + (long)_tbotInstance.InstanceSettings.Expeditions.ManualShips.Ships.Pathfinder ); if (!origin.Ships.HasAtLeast(fleet, expsToSendFromThisOrigin)) { DoLog(LogLevel.Warning, $"Unable to send expeditions: not enough ships in origin {origin}"); @@ -338,11 +336,11 @@ protected override async Task Execute() { var availableShips = origin.Ships.GetMovableShips(); if (SettingsService.IsSettingSet(_tbotInstance.InstanceSettings.Expeditions, "PrimaryToKeep") - && (int) _tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep > 0) { + && (int)_tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep > 0) { availableShips.SetAmount( primaryShip, Math.Max(0, availableShips.GetAmount(primaryShip) - - (long) _tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep)); + - (long)_tbotInstance.InstanceSettings.Expeditions.PrimaryToKeep)); } fleet = _calculationService.CalcFullExpeditionShips( @@ -362,9 +360,9 @@ protected override async Task Execute() { List syslist = new(); for (int i = 0; i < expsToSendFromThisOrigin; i++) { Coordinate destination; - if ((bool) _tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Active) { + if ((bool)_tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Active) { var rand = new Random(); - int range = (int) _tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Range; + int range = (int)_tbotInstance.InstanceSettings.Expeditions.SplitExpeditionsBetweenSystems.Range; while (expsToSendFromThisOrigin > range * 2) range += 1; @@ -388,53 +386,53 @@ protected override async Task Execute() { } _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - Resources payload = new(); - if ((long) _tbotInstance.InstanceSettings.Expeditions.FuelToCarry > 0) { - payload.Deuterium = (long) _tbotInstance.InstanceSettings.Expeditions.FuelToCarry; - } + Resources payload = new(); + if ((long)_tbotInstance.InstanceSettings.Expeditions.FuelToCarry > 0) { + payload.Deuterium = (long)_tbotInstance.InstanceSettings.Expeditions.FuelToCarry; + } if (_tbotInstance.UserData.slots.ExpFree > 0) { - var originUpdated = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Ships); - - _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); - if (_tbotInstance.UserData.slots.ExpFree <= 0) { - DoLog(LogLevel.Information, "Unable to send expeditions: no expedition slots available."); - delay = true; - return; - } - - if (fleet == null || fleet.IsEmpty() || !originUpdated.Ships.HasAtLeast(fleet, 1)) { - DoLog(LogLevel.Warning, $"Skipping expedition: no ships available on origin {originUpdated}"); - delayExpedition++; - break; - } - - var fleetId = await _fleetScheduler.SendFleet( - originUpdated, - fleet, - destination, - Missions.Expedition, - Speeds.HundredPercent, - payload - ); - if (fleetId == (int) SendFleetCode.AfterSleepTime) { + var originUpdated = await _tbotOgameBridge.UpdatePlanet(origin, UpdateTypes.Ships); + + _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); + if (_tbotInstance.UserData.slots.ExpFree <= 0) { + DoLog(LogLevel.Information, "Unable to send expeditions: no expedition slots available."); + delay = true; + return; + } + + if (fleet == null || fleet.IsEmpty() || !originUpdated.Ships.HasAtLeast(fleet, 1)) { + DoLog(LogLevel.Warning, $"Skipping expedition: no ships available on origin {originUpdated}"); + delayExpedition++; + break; + } + + var fleetId = await _fleetScheduler.SendFleet( + originUpdated, + fleet, + destination, + Missions.Expedition, + Speeds.HundredPercent, + payload + ); + if (fleetId == (int)SendFleetCode.AfterSleepTime) { stop = true; return; } - if (fleetId == (int) SendFleetCode.NotEnoughSlots) { + if (fleetId == (int)SendFleetCode.NotEnoughSlots) { delay = true; return; } - int minWait = (int) _tbotInstance.InstanceSettings.Expeditions.MinWaitNextFleet; - int maxWait = (int) _tbotInstance.InstanceSettings.Expeditions.MaxWaitNextFleet; + int minWait = (int)_tbotInstance.InstanceSettings.Expeditions.MinWaitNextFleet; + int maxWait = (int)_tbotInstance.InstanceSettings.Expeditions.MaxWaitNextFleet; - if (maxWait < minWait) { - DoLog(LogLevel.Warning, - $"Expeditions wait misconfigured (MinWaitNextFleet={minWait} > MaxWaitNextFleet={maxWait}). Swapping values."); - (minWait, maxWait) = (maxWait, minWait); - } - var rndWaitTimeMs = (int) RandomizeHelper.CalcRandomIntervalSecToMs(minWait, maxWait); + if (maxWait < minWait) { + DoLog(LogLevel.Warning, + $"Expeditions wait misconfigured (MinWaitNextFleet={minWait} > MaxWaitNextFleet={maxWait}). Swapping values."); + (minWait, maxWait) = (maxWait, minWait); + } + var rndWaitTimeMs = (int)RandomizeHelper.CalcRandomIntervalSecToMs(minWait, maxWait); DoLog(LogLevel.Information, $"Wait {(rndWaitTimeMs / 1000f):0.00}s for next Expedition"); await Task.Delay(rndWaitTimeMs, _ct); @@ -455,7 +453,7 @@ protected override async Task Execute() { .Where(fleet => fleet.Mission == Missions.Expedition) .ToList(); - if ((bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { + if ((bool)_tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) { orderedFleets = orderedFleets.OrderByDescending(fleet => fleet.BackIn).ToList(); } else { orderedFleets = orderedFleets.OrderBy(fleet => fleet.BackIn).ToList(); @@ -464,14 +462,14 @@ protected override async Task Execute() { _tbotInstance.UserData.slots = await _tbotOgameBridge.UpdateSlots(); if ((orderedFleets.Count == 0) || (_tbotInstance.UserData.slots.ExpFree > 0 && - !((bool) _tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) && - !((bool) _tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions))) { + !((bool)_tbotInstance.InstanceSettings.Expeditions.WaitForAllExpeditions) && + !((bool)_tbotInstance.InstanceSettings.Expeditions.WaitForMajorityOfExpeditions))) { interval = RandomizeHelper.CalcRandomInterval(IntervalType.AboutFiveMinutes); } else { - interval = (int) ((1000 * orderedFleets.First().BackIn) + + interval = (int)((1000 * orderedFleets.First().BackIn) + RandomizeHelper.CalcRandomIntervalSecToMs( - (int) _tbotInstance.InstanceSettings.Expeditions.MinWaitNextRound, - (int) _tbotInstance.InstanceSettings.Expeditions.MaxWaitNextRound)); + (int)_tbotInstance.InstanceSettings.Expeditions.MinWaitNextRound, + (int)_tbotInstance.InstanceSettings.Expeditions.MaxWaitNextRound)); } time = await _tbotOgameBridge.GetDateTime(); @@ -480,14 +478,16 @@ protected override async Task Execute() { DoLog(LogLevel.Information, $"Next check at {newTime}"); await _tbotOgameBridge.CheckCelestials(); } - } catch (Exception e) { + } + catch (Exception e) { DoLog(LogLevel.Warning, $"HandleExpeditions exception: {e.Message}"); DoLog(LogLevel.Warning, $"Stacktrace: {e.StackTrace}"); long interval = RandomizeHelper.CalcRandomInterval(IntervalType.AMinuteOrTwo); var time = await _tbotOgameBridge.GetDateTime(); ChangeWorkerPeriod(interval); DoLog(LogLevel.Information, $"Next check at {time.AddMilliseconds(interval)}"); - } finally { + } + finally { if (!_tbotInstance.UserData.isSleeping) { if (stop) { DoLog(LogLevel.Information, $"Stopping feature."); @@ -503,8 +503,8 @@ protected override async Task Execute() { + RandomizeHelper.CalcRandomInterval(IntervalType.SomeSeconds); } catch { interval = RandomizeHelper.CalcRandomInterval( - (int) _tbotInstance.InstanceSettings.Expeditions.CheckIntervalMin, - (int) _tbotInstance.InstanceSettings.Expeditions.CheckIntervalMax); + (int)_tbotInstance.InstanceSettings.Expeditions.CheckIntervalMin, + (int)_tbotInstance.InstanceSettings.Expeditions.CheckIntervalMax); } ChangeWorkerPeriod(interval); DoLog(LogLevel.Information, $"Next check at {time.AddMilliseconds(interval)}");