Files
space-game/apps/backend/Industry/Planning/ProductionGraphBuilder.cs
Jonathan Bourdon 766fef1c8f chore: add .editorconfig and consistent formatting for backend projects
Adds an `.editorconfig` file with C# and project-specific conventions. Applies consistent indentation and formatting across backend handlers, runtime models, and AI services.
2026-03-24 02:55:15 -04:00

106 lines
4.1 KiB
C#

namespace SpaceGame.Api.Industry.Planning;
internal static class ProductionGraphBuilder
{
internal static ProductionGraph Build(
IReadOnlyCollection<ItemDefinition> items,
IReadOnlyCollection<RecipeDefinition> recipes,
IReadOnlyCollection<ModuleDefinition> modules)
{
var commodities = items.ToDictionary(
item => item.Id,
item => new ProductionCommodityNode
{
ItemId = item.Id,
Name = item.Name,
Group = item.Group,
CargoKind = item.CargoKind,
},
StringComparer.Ordinal);
var processes = new Dictionary<string, ProductionProcessNode>(StringComparer.Ordinal);
var processesByOutputId = new Dictionary<string, List<ProductionProcessNode>>(StringComparer.Ordinal);
var processesByInputId = new Dictionary<string, List<ProductionProcessNode>>(StringComparer.Ordinal);
var outputsByModuleId = new Dictionary<string, HashSet<string>>(StringComparer.Ordinal);
foreach (var recipe in recipes)
{
var outputs = recipe.Outputs
.GroupBy(output => output.ItemId, StringComparer.Ordinal)
.ToDictionary(group => group.Key, group => group.Sum(output => output.Amount), StringComparer.Ordinal);
var inputs = recipe.Inputs
.GroupBy(input => input.ItemId, StringComparer.Ordinal)
.ToDictionary(group => group.Key, group => group.Sum(input => input.Amount), StringComparer.Ordinal);
var process = new ProductionProcessNode
{
Id = recipe.Id,
Label = recipe.Label,
FacilityCategory = recipe.FacilityCategory,
RequiredModuleIds = recipe.RequiredModules.ToList(),
Inputs = inputs,
Outputs = outputs,
ProducesShip = recipe.ShipOutputId is not null,
};
processes[process.Id] = process;
foreach (var output in outputs.Keys)
{
if (!commodities.ContainsKey(output))
{
continue;
}
commodities[output].ProducerProcessIds.Add(process.Id);
if (!processesByOutputId.TryGetValue(output, out var outputProcesses))
{
outputProcesses = [];
processesByOutputId[output] = outputProcesses;
}
outputProcesses.Add(process);
}
foreach (var input in inputs.Keys)
{
if (!commodities.ContainsKey(input))
{
continue;
}
commodities[input].ConsumerProcessIds.Add(process.Id);
if (!processesByInputId.TryGetValue(input, out var inputProcesses))
{
inputProcesses = [];
processesByInputId[input] = inputProcesses;
}
inputProcesses.Add(process);
}
}
foreach (var module in modules)
{
if (!outputsByModuleId.TryGetValue(module.Id, out var outputs))
{
outputs = new HashSet<string>(StringComparer.Ordinal);
outputsByModuleId[module.Id] = outputs;
}
foreach (var product in module.Products)
{
outputs.Add(product);
}
}
return new ProductionGraph
{
Commodities = commodities,
Processes = processes,
ProcessesByOutputId = processesByOutputId.ToDictionary(entry => entry.Key, entry => (IReadOnlyList<ProductionProcessNode>)entry.Value, StringComparer.Ordinal),
ProcessesByInputId = processesByInputId.ToDictionary(entry => entry.Key, entry => (IReadOnlyList<ProductionProcessNode>)entry.Value, StringComparer.Ordinal),
OutputsByModuleId = outputsByModuleId.ToDictionary(entry => entry.Key, entry => (IReadOnlyList<string>)entry.Value.OrderBy(value => value, StringComparer.Ordinal).ToList(), StringComparer.Ordinal),
};
}
}