feat: production chain
This commit is contained in:
@@ -6,7 +6,7 @@ namespace SpaceGame.Simulation.Api.Simulation;
|
||||
public sealed partial class ScenarioLoader
|
||||
{
|
||||
private const string DefaultFactionId = "sol-dominion";
|
||||
private const int TargetSystemCount = 160;
|
||||
private const string UnclaimedFactionId = "unclaimed";
|
||||
private const int WorldSeed = 1;
|
||||
private const float MinimumFactionCredits = 0f;
|
||||
private const float MinimumRefineryOre = 0f;
|
||||
@@ -76,20 +76,27 @@ public sealed partial class ScenarioLoader
|
||||
];
|
||||
|
||||
private readonly string _dataRoot;
|
||||
private readonly WorldGenerationOptions _worldGeneration;
|
||||
private readonly JsonSerializerOptions _jsonOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
};
|
||||
|
||||
public ScenarioLoader(string contentRootPath)
|
||||
public ScenarioLoader(string contentRootPath, WorldGenerationOptions? worldGeneration = null)
|
||||
{
|
||||
_dataRoot = Path.GetFullPath(Path.Combine(contentRootPath, "..", "..", "shared", "data"));
|
||||
_worldGeneration = worldGeneration ?? new WorldGenerationOptions();
|
||||
}
|
||||
|
||||
public SimulationWorld Load()
|
||||
{
|
||||
var systems = ExpandSystems(InjectSpecialSystems(Read<List<SolarSystemDefinition>>("systems.json")));
|
||||
var scenario = Read<ScenarioDefinition>("scenario.json");
|
||||
var authoredSystems = Read<List<SolarSystemDefinition>>("systems.json");
|
||||
var systems = ExpandSystems(
|
||||
InjectSpecialSystems(authoredSystems, _worldGeneration.IncludeSolSystem),
|
||||
_worldGeneration.TargetSystemCount);
|
||||
var scenario = NormalizeScenarioToAvailableSystems(
|
||||
Read<ScenarioDefinition>("scenario.json"),
|
||||
systems.Select((system) => system.Id).ToList());
|
||||
var ships = Read<List<ShipDefinition>>("ships.json");
|
||||
var constructibles = Read<List<ConstructibleDefinition>>("constructibles.json");
|
||||
var items = Read<List<ItemDefinition>>("items.json");
|
||||
@@ -127,18 +134,21 @@ public sealed partial class ScenarioLoader
|
||||
|
||||
foreach (var system in systemRuntimes)
|
||||
{
|
||||
var systemGraph = systemGraphs[system.Definition.Id];
|
||||
foreach (var node in system.Definition.ResourceNodes)
|
||||
{
|
||||
var anchorNode = ResolveResourceNodeAnchor(systemGraph, node);
|
||||
var resourceNode = new ResourceNodeRuntime
|
||||
{
|
||||
Id = $"node-{++nodeIdCounter}",
|
||||
SystemId = system.Definition.Id,
|
||||
Position = new Vector3(
|
||||
MathF.Cos(node.Angle) * node.RadiusOffset,
|
||||
balance.YPlane,
|
||||
MathF.Sin(node.Angle) * node.RadiusOffset),
|
||||
Position = ComputeResourceNodePosition(anchorNode, node, balance.YPlane),
|
||||
SourceKind = node.SourceKind,
|
||||
ItemId = node.ItemId,
|
||||
AnchorNodeId = anchorNode?.Id,
|
||||
OrbitRadius = node.RadiusOffset,
|
||||
OrbitPhase = node.Angle,
|
||||
OrbitInclination = DegreesToRadians(node.InclinationDegrees),
|
||||
OreRemaining = node.OreAmount,
|
||||
MaxOre = node.OreAmount,
|
||||
};
|
||||
@@ -152,6 +162,7 @@ public sealed partial class ScenarioLoader
|
||||
Kind = SpatialNodeKind.ResourceSite,
|
||||
Position = resourceNode.Position,
|
||||
BubbleId = bubbleId,
|
||||
ParentNodeId = anchorNode?.Id,
|
||||
});
|
||||
localBubbles.Add(new LocalBubbleRuntime
|
||||
{
|
||||
@@ -230,10 +241,15 @@ public sealed partial class ScenarioLoader
|
||||
station.SystemId == scenario.MiningDefaults.RefinerySystemId)
|
||||
?? stations.FirstOrDefault((station) => HasInstalledModules(station, "power-core", "liquid-tank"));
|
||||
|
||||
var patrolRoutes = scenario.PatrolRoutes.ToDictionary(
|
||||
(route) => route.SystemId,
|
||||
(route) => route.Points.Select((point) => NormalizeScenarioPoint(systemsById[route.SystemId], point)).ToList(),
|
||||
StringComparer.Ordinal);
|
||||
var patrolRoutes = scenario.PatrolRoutes
|
||||
.GroupBy((route) => route.SystemId, StringComparer.Ordinal)
|
||||
.ToDictionary(
|
||||
(group) => group.Key,
|
||||
(group) => group
|
||||
.SelectMany((route) => route.Points)
|
||||
.Select((point) => NormalizeScenarioPoint(systemsById[group.Key], point))
|
||||
.ToList(),
|
||||
StringComparer.Ordinal);
|
||||
|
||||
var shipsRuntime = new List<ShipRuntime>();
|
||||
var shipIdCounter = 0;
|
||||
@@ -258,7 +274,7 @@ public sealed partial class ScenarioLoader
|
||||
TargetPosition = position,
|
||||
SpatialState = CreateInitialShipSpatialState(formation.SystemId, position, spatialNodes),
|
||||
DefaultBehavior = CreateBehavior(definition, formation.SystemId, scenario, patrolRoutes, refinery),
|
||||
ControllerTask = new ControllerTaskRuntime { Kind = "idle", Threshold = balance.ArrivalThreshold, Status = WorkStatus.Pending },
|
||||
ControllerTask = new ControllerTaskRuntime { Kind = ControllerTaskKind.Idle, Threshold = balance.ArrivalThreshold, Status = WorkStatus.Pending },
|
||||
Health = definition.MaxHealth,
|
||||
});
|
||||
|
||||
@@ -306,6 +322,7 @@ public sealed partial class ScenarioLoader
|
||||
ItemDefinitions = itemDefinitions,
|
||||
ModuleRecipes = moduleRecipeDefinitions,
|
||||
Recipes = recipeDefinitions,
|
||||
OrbitalTimeSeconds = WorldSeed * 97d,
|
||||
GeneratedAtUtc = DateTimeOffset.UtcNow,
|
||||
};
|
||||
}
|
||||
@@ -318,6 +335,60 @@ public sealed partial class ScenarioLoader
|
||||
?? throw new InvalidOperationException($"Unable to read {fileName}.");
|
||||
}
|
||||
|
||||
private static ScenarioDefinition NormalizeScenarioToAvailableSystems(
|
||||
ScenarioDefinition scenario,
|
||||
IReadOnlyList<string> availableSystemIds)
|
||||
{
|
||||
if (availableSystemIds.Count == 0)
|
||||
{
|
||||
return scenario;
|
||||
}
|
||||
|
||||
var fallbackSystemId = availableSystemIds.Contains("sol", StringComparer.Ordinal)
|
||||
? "sol"
|
||||
: availableSystemIds[0];
|
||||
|
||||
string ResolveSystemId(string systemId) =>
|
||||
availableSystemIds.Contains(systemId, StringComparer.Ordinal) ? systemId : fallbackSystemId;
|
||||
|
||||
return new ScenarioDefinition
|
||||
{
|
||||
InitialStations = scenario.InitialStations
|
||||
.Select((station) => new InitialStationDefinition
|
||||
{
|
||||
ConstructibleId = station.ConstructibleId,
|
||||
SystemId = ResolveSystemId(station.SystemId),
|
||||
FactionId = station.FactionId,
|
||||
PlanetIndex = station.PlanetIndex,
|
||||
LagrangeSide = station.LagrangeSide,
|
||||
Position = station.Position?.ToArray(),
|
||||
})
|
||||
.ToList(),
|
||||
ShipFormations = scenario.ShipFormations
|
||||
.Select((formation) => new ShipFormationDefinition
|
||||
{
|
||||
ShipId = formation.ShipId,
|
||||
Count = formation.Count,
|
||||
Center = formation.Center.ToArray(),
|
||||
SystemId = ResolveSystemId(formation.SystemId),
|
||||
FactionId = formation.FactionId,
|
||||
})
|
||||
.ToList(),
|
||||
PatrolRoutes = scenario.PatrolRoutes
|
||||
.Select((route) => new PatrolRouteDefinition
|
||||
{
|
||||
SystemId = ResolveSystemId(route.SystemId),
|
||||
Points = route.Points.Select((point) => point.ToArray()).ToList(),
|
||||
})
|
||||
.ToList(),
|
||||
MiningDefaults = new MiningDefaultsDefinition
|
||||
{
|
||||
NodeSystemId = ResolveSystemId(scenario.MiningDefaults.NodeSystemId),
|
||||
RefinerySystemId = ResolveSystemId(scenario.MiningDefaults.RefinerySystemId),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static Vector3 ToVector(float[] values) => new(values[0], values[1], values[2]);
|
||||
|
||||
private static Vector3 NormalizeScenarioPoint(SystemRuntime system, float[] values)
|
||||
|
||||
Reference in New Issue
Block a user