feat: simplify station production
This commit is contained in:
@@ -98,6 +98,7 @@ public sealed class ModuleDefinition
|
|||||||
public string Description { get; set; } = string.Empty;
|
public string Description { get; set; } = string.Empty;
|
||||||
public required string Type { get; set; }
|
public required string Type { get; set; }
|
||||||
public string? Product { get; set; }
|
public string? Product { get; set; }
|
||||||
|
public string ProductionMode { get; set; } = "passive";
|
||||||
public float Radius { get; set; } = 12f;
|
public float Radius { get; set; } = 12f;
|
||||||
public float Hull { get; set; } = 100f;
|
public float Hull { get; set; } = 100f;
|
||||||
public float WorkforceNeeded { get; set; }
|
public float WorkforceNeeded { get; set; }
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ public sealed partial class SimulationEngine
|
|||||||
station.MarketOrderIds.OrderBy(orderId => orderId, StringComparer.Ordinal).ToList());
|
station.MarketOrderIds.OrderBy(orderId => orderId, StringComparer.Ordinal).ToList());
|
||||||
|
|
||||||
private static IReadOnlyList<StationActionProgressSnapshot> ToStationActionProgressSnapshots(SimulationWorld world, StationRuntime station) =>
|
private static IReadOnlyList<StationActionProgressSnapshot> ToStationActionProgressSnapshots(SimulationWorld world, StationRuntime station) =>
|
||||||
GetStationProductionLanes(station)
|
GetStationProductionLanes(world, station)
|
||||||
.Select(laneKey =>
|
.Select(laneKey =>
|
||||||
{
|
{
|
||||||
var recipe = SelectProductionRecipe(world, station, laneKey);
|
var recipe = SelectProductionRecipe(world, station, laneKey);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public sealed partial class SimulationEngine
|
|||||||
private void RunStationProduction(SimulationWorld world, StationRuntime station, float deltaSeconds, ICollection<SimulationEventRecord> events)
|
private void RunStationProduction(SimulationWorld world, StationRuntime station, float deltaSeconds, ICollection<SimulationEventRecord> events)
|
||||||
{
|
{
|
||||||
var faction = world.Factions.FirstOrDefault(candidate => candidate.Id == station.FactionId);
|
var faction = world.Factions.FirstOrDefault(candidate => candidate.Id == station.FactionId);
|
||||||
foreach (var laneKey in GetStationProductionLanes(station))
|
foreach (var laneKey in GetStationProductionLanes(world, station))
|
||||||
{
|
{
|
||||||
var recipe = SelectProductionRecipe(world, station, laneKey);
|
var recipe = SelectProductionRecipe(world, station, laneKey);
|
||||||
if (recipe is null)
|
if (recipe is null)
|
||||||
@@ -95,7 +95,7 @@ public sealed partial class SimulationEngine
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var throughput = GetStationProductionThroughput(station, recipe);
|
var throughput = GetStationProductionThroughput(world, station, recipe);
|
||||||
|
|
||||||
var produced = 0f;
|
var produced = 0f;
|
||||||
station.ProductionLaneTimers[laneKey] = GetStationProductionTimer(station, laneKey) + (deltaSeconds * station.WorkforceEffectiveRatio * throughput);
|
station.ProductionLaneTimers[laneKey] = GetStationProductionTimer(station, laneKey) + (deltaSeconds * station.WorkforceEffectiveRatio * throughput);
|
||||||
@@ -132,26 +132,21 @@ public sealed partial class SimulationEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<string> GetStationProductionLanes(StationRuntime station)
|
private static IEnumerable<string> GetStationProductionLanes(SimulationWorld world, StationRuntime station)
|
||||||
{
|
{
|
||||||
if (CountModules(station.InstalledModules, "refinery-stack") > 0)
|
foreach (var moduleId in station.InstalledModules.Distinct(StringComparer.Ordinal))
|
||||||
{
|
{
|
||||||
yield return "refinery";
|
if (!world.ModuleDefinitions.TryGetValue(moduleId, out var def) || string.IsNullOrEmpty(def.ProductionMode))
|
||||||
}
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (CountModules(station.InstalledModules, "fabricator-array") > 0)
|
if (string.Equals(def.ProductionMode, "commanded", StringComparison.Ordinal) && station.CommanderId is null)
|
||||||
{
|
{
|
||||||
yield return "fabrication";
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CountModules(station.InstalledModules, "component-factory") > 0)
|
yield return moduleId;
|
||||||
{
|
|
||||||
yield return "components";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CountModules(station.InstalledModules, "ship-factory") > 0)
|
|
||||||
{
|
|
||||||
yield return "shipyard";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,34 +155,13 @@ public sealed partial class SimulationEngine
|
|||||||
|
|
||||||
private static RecipeDefinition? SelectProductionRecipe(SimulationWorld world, StationRuntime station, string laneKey) =>
|
private static RecipeDefinition? SelectProductionRecipe(SimulationWorld world, StationRuntime station, string laneKey) =>
|
||||||
world.Recipes.Values
|
world.Recipes.Values
|
||||||
.Where(recipe => RecipeAppliesToStation(station, recipe) && string.Equals(GetStationProductionLaneKey(recipe), laneKey, StringComparison.Ordinal))
|
.Where(recipe => RecipeAppliesToStation(station, recipe) && string.Equals(GetStationProductionLaneKey(world, recipe), laneKey, StringComparison.Ordinal))
|
||||||
.OrderByDescending(recipe => GetStationRecipePriority(world, station, recipe))
|
.OrderByDescending(recipe => GetStationRecipePriority(world, station, recipe))
|
||||||
.FirstOrDefault(recipe => CanRunRecipe(world, station, recipe));
|
.FirstOrDefault(recipe => CanRunRecipe(world, station, recipe));
|
||||||
|
|
||||||
private static string? GetStationProductionLaneKey(RecipeDefinition recipe)
|
private static string? GetStationProductionLaneKey(SimulationWorld world, RecipeDefinition recipe) =>
|
||||||
{
|
recipe.RequiredModules.FirstOrDefault(moduleId =>
|
||||||
if (recipe.RequiredModules.Contains("refinery-stack", StringComparer.Ordinal))
|
world.ModuleDefinitions.TryGetValue(moduleId, out var def) && !string.IsNullOrEmpty(def.ProductionMode));
|
||||||
{
|
|
||||||
return "refinery";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipe.RequiredModules.Contains("fabricator-array", StringComparer.Ordinal))
|
|
||||||
{
|
|
||||||
return "fabrication";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipe.RequiredModules.Contains("component-factory", StringComparer.Ordinal))
|
|
||||||
{
|
|
||||||
return "components";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipe.RequiredModules.Contains("ship-factory", StringComparer.Ordinal))
|
|
||||||
{
|
|
||||||
return "shipyard";
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float GetStationRecipePriority(SimulationWorld world, StationRuntime station, RecipeDefinition recipe)
|
private static float GetStationRecipePriority(SimulationWorld world, StationRuntime station, RecipeDefinition recipe)
|
||||||
{
|
{
|
||||||
@@ -467,29 +441,15 @@ public sealed partial class SimulationEngine
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float GetStationProductionThroughput(StationRuntime station, RecipeDefinition recipe)
|
private static float GetStationProductionThroughput(SimulationWorld world, StationRuntime station, RecipeDefinition recipe)
|
||||||
{
|
{
|
||||||
if (recipe.RequiredModules.Contains("refinery-stack", StringComparer.Ordinal))
|
var laneModuleId = GetStationProductionLaneKey(world, recipe);
|
||||||
|
if (laneModuleId is null)
|
||||||
{
|
{
|
||||||
return Math.Max(1, CountModules(station.InstalledModules, "refinery-stack"));
|
return 1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recipe.RequiredModules.Contains("fabricator-array", StringComparer.Ordinal))
|
return Math.Max(1, CountModules(station.InstalledModules, laneModuleId));
|
||||||
{
|
|
||||||
return Math.Max(1, CountModules(station.InstalledModules, "fabricator-array"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipe.RequiredModules.Contains("component-factory", StringComparer.Ordinal))
|
|
||||||
{
|
|
||||||
return Math.Max(1, CountModules(station.InstalledModules, "component-factory"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipe.RequiredModules.Contains("ship-factory", StringComparer.Ordinal))
|
|
||||||
{
|
|
||||||
return Math.Max(1, CountModules(station.InstalledModules, "ship-factory"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed record DesiredMarketOrder(string Kind, string ItemId, float Amount, float Valuation, float? ReserveThreshold);
|
private sealed record DesiredMarketOrder(string Kind, string ItemId, float Amount, float Valuation, float? ReserveThreshold);
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
"name": "Refinery Stack",
|
"name": "Refinery Stack",
|
||||||
"description": "Heavy refining line for ore to refined metals.",
|
"description": "Heavy refining line for ore to refined metals.",
|
||||||
"type": "Production",
|
"type": "Production",
|
||||||
|
"productionMode": "passive",
|
||||||
"product": "refined-metals",
|
"product": "refined-metals",
|
||||||
"hull": 180,
|
"hull": 180,
|
||||||
"workforceNeeded": 18,
|
"workforceNeeded": 18,
|
||||||
@@ -81,6 +82,7 @@
|
|||||||
"name": "Solar Array",
|
"name": "Solar Array",
|
||||||
"description": "Orbital solar generation and utility frame.",
|
"description": "Orbital solar generation and utility frame.",
|
||||||
"type": "Production",
|
"type": "Production",
|
||||||
|
"productionMode": "passive",
|
||||||
"hull": 110,
|
"hull": 110,
|
||||||
"workforceNeeded": 6,
|
"workforceNeeded": 6,
|
||||||
"construction": {
|
"construction": {
|
||||||
@@ -98,6 +100,7 @@
|
|||||||
"name": "Fabricator Array",
|
"name": "Fabricator Array",
|
||||||
"description": "General fabrication line for industrial goods and prefab kits.",
|
"description": "General fabrication line for industrial goods and prefab kits.",
|
||||||
"type": "Build Module",
|
"type": "Build Module",
|
||||||
|
"productionMode": "commanded",
|
||||||
"hull": 200,
|
"hull": 200,
|
||||||
"workforceNeeded": 20,
|
"workforceNeeded": 20,
|
||||||
"construction": {
|
"construction": {
|
||||||
@@ -115,6 +118,7 @@
|
|||||||
"name": "Component Factory",
|
"name": "Component Factory",
|
||||||
"description": "Assembly line for ship-grade modules and integrated components.",
|
"description": "Assembly line for ship-grade modules and integrated components.",
|
||||||
"type": "Build Module",
|
"type": "Build Module",
|
||||||
|
"productionMode": "commanded",
|
||||||
"hull": 220,
|
"hull": 220,
|
||||||
"workforceNeeded": 24,
|
"workforceNeeded": 24,
|
||||||
"construction": {
|
"construction": {
|
||||||
@@ -136,6 +140,7 @@
|
|||||||
"name": "Ship Factory",
|
"name": "Ship Factory",
|
||||||
"description": "Slip-line and integration yard for final ship assembly.",
|
"description": "Slip-line and integration yard for final ship assembly.",
|
||||||
"type": "Build Module",
|
"type": "Build Module",
|
||||||
|
"productionMode": "commanded",
|
||||||
"hull": 260,
|
"hull": 260,
|
||||||
"workforceNeeded": 28,
|
"workforceNeeded": 28,
|
||||||
"construction": {
|
"construction": {
|
||||||
|
|||||||
Reference in New Issue
Block a user