From ea775ab824b38271669494490c9884b376641050 Mon Sep 17 00:00:00 2001 From: dnqbob Date: Wed, 15 Oct 2025 23:19:18 +0800 Subject: [PATCH] Correct and add comments for expansion related --- .../BotModuleLogic/BaseBuilderQueueManager.cs | 34 +++++++++++++------ .../Traits/BotModules/HarvesterBotModule.cs | 4 ++- .../McvExpansionManagerBotModule.cs | 10 +++--- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/BaseBuilderQueueManager.cs b/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/BaseBuilderQueueManager.cs index 93267dabdd..17d10d065d 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/BaseBuilderQueueManager.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/BaseBuilderQueueManager.cs @@ -58,8 +58,7 @@ namespace OpenRA.Mods.Common.Traits public void Tick(IBot bot, ILookup queuesByCategory) { - // If failed to place something N consecutive times, we will try move the MCV - // If it is possible. + // If we can't place any structures, give a nudge to BaseExpansionModules and hope it gets fixed. if (failCount >= baseBuilder.Info.MaximumFailedPlacementAttempts) { if (baseBuilder.BaseExpansionModules != null && baseCenterKeepsFailing != null) @@ -77,7 +76,8 @@ namespace OpenRA.Mods.Common.Traits failCount = 0; } - // Otherwise, only bother resetting failCount if either a) the number of buildings has decreased since last failure M ticks ago, + // No BaseExpansionModules exist. Only bother resetting failCount when either + // a) the number of buildings has decreased since last failure M ticks ago, // or b) number of BaseProviders (construction yard or similar) has increased since then. // Otherwise reset failRetryTicks instead to wait again. else if (baseBuilder.BaseExpansionModules == null && --failRetryTicks <= 0) @@ -232,6 +232,8 @@ namespace OpenRA.Mods.Common.Traits SuppressVisualFeedback = true }); + // After succesfuly placing a building, nudge BaseExpansionModules to expand. + // We want to avoid expanding too often, so we make a judgement by counting buildings. if (baseBuilder.Info.ProductionTypes.Contains(currentBuilding.Item) || baseBuilder.Info.TechTypes.Contains(currentBuilding.Item) || baseBuilder.Info.RefineryTypes.Contains(currentBuilding.Item)) { @@ -541,25 +543,35 @@ namespace OpenRA.Mods.Common.Traits // Try and place the refinery near a resource field if (resourceLayer != null) { - // If we have failed to place to the best refinery point, try and place it near the base center - var resourceBaseCenter = failCount > 0 ? baseCenter : (requestRef != null ? - baseBuilder.RequestedRefineries[requestRef].ConyardLoc : (baseBuilder.ResourceConyardCenter ?? baseCenter)); + // If we have failed to place to the requested refinery point, try and place it near the base center + var resourceBaseCenter = failCount > 0 ? baseCenter : + (requestRef != null ? baseBuilder.RequestedRefineries[requestRef].ConyardLoc : (baseBuilder.ResourceConyardCenter ?? baseCenter)); + // If we have a ResourceMapModule, only consider the resource types it considers valuable + // Otherwise consider any resource type var nearbyResources = world.Map .FindTilesInAnnulus(resourceBaseCenter, baseBuilder.Info.MinBaseRadius, baseBuilder.Info.MaxBaseRadius) .Where(c => baseBuilder.ResourceMapModule != null ? baseBuilder.ResourceMapModule.Info.ValuableResourceTypes.Contains(resourceLayer.GetResource(c).Type) : resourceLayer.GetResource(c).Type != null); + // Find the closest refinery we have if we have any when not failing to place for the first time var closestRefinery = failCount <= 0 ? baseBuilder.RefineryBuildings.Actors.Where(a => !a.IsDead)?.ClosestToIgnoringPath(world.Map.CenterOfCell(resourceBaseCenter)) : null; - var resourcesShouldCheck = closestRefinery == null ? - nearbyResources.Shuffle(world.LocalRandom) : - (requestRef != null ? nearbyResources.OrderBy(c => (c - baseBuilder.RequestedRefineries[requestRef].ResourceLoc).LengthSquared) - : nearbyResources.OrderByDescending(c => (c - closestRefinery.Location).LengthSquared)) - .Take(baseBuilder.Info.MaxResourceCellsToCheck); + IEnumerable resourcesShouldCheck = null; + + if (closestRefinery == null) + resourcesShouldCheck = nearbyResources.Shuffle(world.LocalRandom).Take(baseBuilder.Info.MaxResourceCellsToCheck); + else if (requestRef != null) + { + resourcesShouldCheck = nearbyResources.OrderBy(c => (c - baseBuilder.RequestedRefineries[requestRef].ResourceLoc).LengthSquared) + .Take(baseBuilder.Info.MaxResourceCellsToCheck); + } + else + resourcesShouldCheck = nearbyResources.OrderByDescending(c => (c - closestRefinery.Location).LengthSquared) + .Take(baseBuilder.Info.MaxResourceCellsToCheck); foreach (var r in resourcesShouldCheck) { diff --git a/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs b/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs index c5afa9a385..aa2bfd332c 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs @@ -193,9 +193,11 @@ namespace OpenRA.Mods.Common.Traits var worstEffectHarvesterCount = int.MaxValue; var lackHarvesterIndices = new List<(int Attraction, int LackHarvs, CPos ResoueceCenter)>(); + /* * indiceSideLengthSquare (which is equal to indiceSideLength * indiceSideLength) is used as the basic unit to calculate the attraction of a candidate, - * we compare the attraction on the same scale on different factors, such as candidate's distance to current MCV and ally construction yard & refinery within range, etc: + * we compare the attraction on the same scale on different factors, such as ally refinery within range or threats nearby. + * Note: this function requires an enabled resourceMapModule. */ var indiceSideLengthSquare = resourceMapModule.GetIndiceSideLength() * resourceMapModule.GetIndiceSideLength(); diff --git a/OpenRA.Mods.Common/Traits/BotModules/McvExpansionManagerBotModule.cs b/OpenRA.Mods.Common/Traits/BotModules/McvExpansionManagerBotModule.cs index fd6ded285c..a44f146d1e 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/McvExpansionManagerBotModule.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/McvExpansionManagerBotModule.cs @@ -290,7 +290,7 @@ namespace OpenRA.Mods.Common.Traits * * 2). the weight of friendly construction yard within range: -indiceSideLengthSquare. If it belongs to an ally, -indiceSideLengthSquare/2. * - * 3). the weight of enemy high threat within range: -indiceSideLengthSquare*8, otherwise -indiceSideLengthSquare/64 + * 3). the weight of enemy within range: -indiceSideLengthSquare*8 for base building, otherwise -indiceSideLengthSquare/64 * * 4). the weight of friendly refinery within range (not for CheckBase mode): -indiceSideLengthSquare. If it belongs to an ally, -indiceSideLengthSquare/2. * @@ -312,7 +312,7 @@ namespace OpenRA.Mods.Common.Traits { /* * CheckBase mode only considers the distance to current MCV, ally construction yard within range and enemy buildings within range. - * Attaction has a base value of indiceSideLengthSquare >> 3 (1/8 of the maximum distance weight, 1/(2*sqrt(2))≈ 1/2.8 of the maximum distance in map) + * Attaction has a base value of indiceSideLengthSquare >> 1 (1/2 of the maximum distance weight, 1/ sqrt(2) ≈ 1/1.4 of maximum euclid distance in map) */ case BotMcvExpansionMode.CheckBase: var cb_conyardlocs = world.ActorsHavingTrait() @@ -374,8 +374,8 @@ namespace OpenRA.Mods.Common.Traits /* * CheckResource mode considers the distance to current MCV, ally construction yard & refinery within range, * Attaction has a base value of: - * 1. if not Mobile: indiceSideLengthSquare >> 4 (1/16 of the maximum distance weight, = 0.25 of the maximum euclid distance in map) - * 2. if Mobile: indiceSideLengthSquare >> 3 (1/8 of the maximum distance weight, ≈ 0.35 of the maximum euclid distance in map) + * 1. if not Mobile: indiceSideLengthSquare >> 2 (1/4 of the maximum distance weight, = 0.5 of the maximum euclid distance in map) + * 2. if Mobile: indiceSideLengthSquare >> 1 (1/2 of the maximum distance weight, ≈ 0.71 of the maximum euclid distance in map) */ case BotMcvExpansionMode.CheckResource: @@ -389,7 +389,7 @@ namespace OpenRA.Mods.Common.Traits .Select(a => (a.Location, a.Owner != player)) .ToArray(); - // We only take indice has more than half of average indice value (in weight calculation), to skip the indice with very poor resource + // We only take indice has more than the half of average indice value (in weight calculation), to skip the indice with very poor resource // when failedAttempts is acceptable. var thresholdRes = 0; for (var i = 0; i < resourceMapModule.GetIndicesLength(); i++)