feat(ai): improving agents planning and memory

This commit is contained in:
2026-03-20 02:12:29 -04:00
parent f5bf7d8e3f
commit a2f66b0dca
11 changed files with 2012 additions and 445 deletions

View File

@@ -4,6 +4,9 @@ namespace SpaceGame.Api.Stations.Simulation;
internal sealed class InfrastructureSimulationService
{
private const float CommodityTargetLevelSeconds = 240f;
private const float EnergyTargetLevelSeconds = 240f;
internal void UpdateClaims(SimulationWorld world, ICollection<SimulationEventRecord> events)
{
foreach (var claim in world.Claims)
@@ -259,16 +262,19 @@ internal sealed class InfrastructureSimulationService
var currentCount = CountModules(station.InstalledModules, objectiveModuleId);
var marginalOutputRate = EstimateMarginalOutputRate(world, station, objectiveModuleId, objectiveCommodityId);
var constructionImpact = EstimateConstructionBottleneckImpact(world, objectiveModuleId, constructionDemandByItem);
var score = 90f + commodity.ProjectedPressureScore + (marginalOutputRate * 900f) + constructionImpact;
var score = 90f
+ CommodityOperationalSignal.ComputeNeedScore(commodity, GetTargetLevelSeconds(objectiveCommodityId))
+ (marginalOutputRate * 900f)
+ constructionImpact;
if (currentCount == 0)
{
score += 80f;
}
if (!float.IsPositiveInfinity(commodity.ProjectedShortageHorizonSeconds))
if (commodity.LevelSeconds < GetTargetLevelSeconds(objectiveCommodityId))
{
score += MathF.Max(0f, 300f - commodity.ProjectedShortageHorizonSeconds) * 0.3f;
score += MathF.Max(0f, GetTargetLevelSeconds(objectiveCommodityId) - commodity.LevelSeconds) * 0.3f;
}
score *= EstimateObjectiveExpansionFeasibility(world, station, economy, objectiveModuleId, objectiveCommodityId);
@@ -287,16 +293,19 @@ internal sealed class InfrastructureSimulationService
var currentCount = CountModules(station.InstalledModules, "module_gen_prod_energycells_01");
var constructionImpact = EstimateConstructionBottleneckImpact(world, "module_gen_prod_energycells_01", constructionDemandByItem);
var readinessUnlock = EstimateSupportUnlockScore(world, station, economy, "module_gen_prod_energycells_01");
var score = 40f + energy.ProjectedPressureScore * 0.5f + constructionImpact + readinessUnlock;
var score = 40f
+ CommodityOperationalSignal.ComputeNeedScore(energy, EnergyTargetLevelSeconds) * 0.5f
+ constructionImpact
+ readinessUnlock;
if (currentCount == 0)
{
score += 70f;
}
if (!float.IsPositiveInfinity(energy.ProjectedShortageHorizonSeconds))
if (energy.LevelSeconds < EnergyTargetLevelSeconds)
{
score += MathF.Max(0f, 240f - energy.ProjectedShortageHorizonSeconds) * 0.2f;
score += MathF.Max(0f, EnergyTargetLevelSeconds - energy.LevelSeconds) * 0.2f;
}
return score - (currentCount * 40f);
@@ -433,17 +442,9 @@ internal sealed class InfrastructureSimulationService
foreach (var input in recipe.Inputs)
{
var inputCommodity = economy.GetCommodity(input.ItemId);
if (inputCommodity.AvailableStock <= 0.01f && inputCommodity.ProjectedProductionRatePerSecond <= 0.01f)
{
feasibility *= 0.65f;
continue;
}
if (!float.IsPositiveInfinity(inputCommodity.ProjectedShortageHorizonSeconds)
&& inputCommodity.ProjectedShortageHorizonSeconds < 180f)
{
feasibility *= 0.82f;
}
feasibility *= CommodityOperationalSignal.ComputeFeasibilityFactor(
inputCommodity,
GetTargetLevelSeconds(input.ItemId));
}
}
@@ -505,7 +506,8 @@ internal sealed class InfrastructureSimulationService
{
inputFactor *= 0.95f + (availableStockRatio * 0.05f);
}
else if (commodity.ProjectedProductionRatePerSecond > 0.01f)
else if (commodity.ProjectedProductionRatePerSecond > 0.01f
&& commodity.Level is not CommodityLevelKind.Critical)
{
inputFactor *= 0.82f + (availableStockRatio * 0.08f);
}
@@ -719,6 +721,11 @@ internal sealed class InfrastructureSimulationService
private static bool ObjectiveNeedsEnergy(SimulationWorld world, string objectiveCommodityId) =>
world.ProductionGraph.GetImmediateInputs(objectiveCommodityId).Contains("energycells", StringComparer.Ordinal);
private static float GetTargetLevelSeconds(string commodityId) =>
string.Equals(commodityId, "energycells", StringComparison.Ordinal) ? EnergyTargetLevelSeconds :
string.Equals(commodityId, "water", StringComparison.Ordinal) ? 300f :
CommodityTargetLevelSeconds;
internal static void PrepareNextConstructionSiteStep(SimulationWorld world, StationRuntime station, ConstructionSiteRuntime site)
{
var nextModuleId = GetNextStationModuleToBuild(station, world);