Refactor runtime bootstrap and ship control flows

This commit is contained in:
2026-04-03 01:12:26 -04:00
parent 0bb72bee35
commit 706e1cda8f
129 changed files with 9588 additions and 3548 deletions

View File

@@ -89,9 +89,6 @@ internal static class LoaderSupport
internal static bool HasInstalledModules(StationRuntime station, params string[] modules) =>
modules.All(moduleId => station.Modules.Any(candidate => string.Equals(candidate.ModuleId, moduleId, StringComparison.Ordinal)));
internal static bool HasCapabilities(ShipDefinition definition, params string[] capabilities) =>
capabilities.All(capability => definition.Capabilities.Contains(capability, StringComparer.Ordinal));
internal static void AddStationModule(StationRuntime station, IReadOnlyDictionary<string, ModuleDefinition> moduleDefinitions, string moduleId)
{
if (!moduleDefinitions.TryGetValue(moduleId, out var definition))

View File

@@ -1,5 +1,7 @@
using SpaceGame.Api.Universe.Bootstrap;
using SpaceGame.Api.Ships.Simulation;
using SpaceGame.Api.Ships.AI;
using static SpaceGame.Api.Shared.Runtime.ShipBehaviorKinds;
using static SpaceGame.Api.Shared.Runtime.SimulationRuntimeSupport;
using static SpaceGame.Api.Universe.Scenario.LoaderSupport;
namespace SpaceGame.Api.Universe.Scenario;
@@ -194,7 +196,7 @@ public sealed class ScenarioContentBuilder(
patrolRoutes,
stations),
Skills = ShipBootstrapPolicy.CreateSkills(definition),
Health = definition.MaxHealth,
Health = definition.Hull,
});
foreach (var (itemId, amount) in formation.StartingInventory)
@@ -232,45 +234,45 @@ public sealed class ScenarioContentBuilder(
&& string.Equals(station.SystemId, systemId, StringComparison.Ordinal))
?? stations.FirstOrDefault(station => string.Equals(station.FactionId, factionId, StringComparison.Ordinal));
if (string.Equals(definition.Kind, "construction", StringComparison.Ordinal) && homeStation is not null)
if (IsConstructionShip(definition) && homeStation is not null)
{
return new DefaultBehaviorRuntime
{
Kind = "construct-station",
Kind = ConstructStation,
HomeSystemId = homeStation.SystemId,
HomeStationId = homeStation.Id,
PreferredConstructionSiteId = null,
};
}
if (LoaderSupport.HasCapabilities(definition, "mining") && homeStation is not null)
if (IsMiningShip(definition) && homeStation is not null)
{
return new DefaultBehaviorRuntime
{
Kind = definition.CargoCapacity >= 120f ? "expert-auto-mine" : "advanced-auto-mine",
Kind = definition.GetTotalCargoCapacity() >= 120f ? ExpertAutoMine : AdvancedAutoMine,
HomeSystemId = homeStation.SystemId,
HomeStationId = homeStation.Id,
AreaSystemId = homeStation.SystemId,
MaxSystemRange = definition.CargoCapacity >= 120f ? 3 : 1,
MaxSystemRange = definition.GetTotalCargoCapacity() >= 120f ? 3 : 1,
};
}
if (string.Equals(definition.Kind, "transport", StringComparison.Ordinal))
if (IsTransportShip(definition))
{
return new DefaultBehaviorRuntime
{
Kind = "advanced-auto-trade",
Kind = AdvancedAutoTrade,
HomeSystemId = homeStation?.SystemId ?? systemId,
HomeStationId = homeStation?.Id,
MaxSystemRange = 2,
};
}
if (string.Equals(definition.Kind, "military", StringComparison.Ordinal) && patrolRoutes.TryGetValue(systemId, out var route))
if (IsMilitaryShip(definition) && patrolRoutes.TryGetValue(systemId, out var route))
{
return new DefaultBehaviorRuntime
{
Kind = "patrol",
Kind = Patrol,
HomeSystemId = homeStation?.SystemId ?? systemId,
HomeStationId = homeStation?.Id,
AreaSystemId = systemId,
@@ -281,9 +283,10 @@ public sealed class ScenarioContentBuilder(
return new DefaultBehaviorRuntime
{
Kind = "idle",
Kind = HoldPosition,
HomeSystemId = homeStation?.SystemId ?? systemId,
HomeStationId = homeStation?.Id,
AreaSystemId = homeStation?.SystemId ?? systemId,
};
}
}

View File

@@ -520,6 +520,8 @@ public sealed class SystemGenerationService
private static float Jitter(int index, int salt, float amplitude) =>
(Hash01(index, salt) * 2f - 1f) * amplitude;
// Cheap deterministic pseudo-random helper: same (index, salt) pair always maps to the same 0..1 value.
// Generation code uses it instead of a mutable RNG so each procedural choice stays stable for a given seed.
private static float Hash01(int index, int salt)
{
uint value = (uint)(index + 1);

View File

@@ -18,9 +18,6 @@ public sealed class WorldRuntimeAssembler(
var policies = seedingService.CreatePolicies(factions);
var commanders = seedingService.CreateCommanders(factions, content.Stations, content.Ships);
var nowUtc = DateTimeOffset.UtcNow;
var playerFaction = worldGenerationOptions.GeneratePlayerFaction
? seedingService.CreatePlayerFaction(factions, content.Stations, content.Ships, commanders, policies, nowUtc)
: null;
var claims = seedingService.CreateClaims(content.Stations, topology.SpatialLayout.Celestials, nowUtc);
var world = new SimulationWorld
@@ -34,7 +31,6 @@ public sealed class WorldRuntimeAssembler(
Stations = content.Stations.ToList(),
Ships = content.Ships.ToList(),
Factions = factions,
PlayerFaction = playerFaction,
Geopolitics = null,
Commanders = commanders,
Claims = claims,

View File

@@ -1,4 +1,5 @@
using SpaceGame.Api.Universe.Bootstrap;
using static SpaceGame.Api.Shared.Runtime.ShipBehaviorKinds;
using static SpaceGame.Api.Universe.Scenario.LoaderSupport;
namespace SpaceGame.Api.Universe.Scenario;
@@ -379,7 +380,7 @@ public sealed class WorldSeedingService(IStaticDataProvider staticData)
Label = "Core Automation",
ScopeKind = "player-faction",
ScopeId = player.Id,
BehaviorKind = "idle",
BehaviorKind = Idle,
UpdatedAtUtc = nowUtc,
});
@@ -395,7 +396,7 @@ public sealed class WorldSeedingService(IStaticDataProvider staticData)
return player;
}
private FactionRuntime CreateFaction(string factionId)
internal FactionRuntime CreateFaction(string factionId)
{
if (!staticData.FactionDefinitions.TryGetValue(factionId, out var definition))
{