Refactor runtime bootstrap and ship control flows
This commit is contained in:
@@ -3,6 +3,7 @@ namespace SpaceGame.Api.Simulation.Core;
|
||||
internal sealed class SimulationEngine
|
||||
{
|
||||
private readonly IBalanceService _balance;
|
||||
private readonly IPlayerStateStore _playerStateStore;
|
||||
private readonly OrbitalSimulationOptions _orbitalSimulation;
|
||||
private readonly OrbitalStateUpdater _orbitalStateUpdater;
|
||||
private readonly InfrastructureSimulationService _infrastructureSimulation;
|
||||
@@ -14,9 +15,10 @@ internal sealed class SimulationEngine
|
||||
private readonly ShipAiService _shipAi;
|
||||
private readonly SimulationProjectionService _projection;
|
||||
|
||||
internal SimulationEngine(OrbitalSimulationOptions orbitalSimulation, IBalanceService balance)
|
||||
internal SimulationEngine(OrbitalSimulationOptions orbitalSimulation, IBalanceService balance, IPlayerStateStore playerStateStore)
|
||||
{
|
||||
_balance = balance;
|
||||
_playerStateStore = playerStateStore;
|
||||
_orbitalSimulation = orbitalSimulation;
|
||||
_orbitalStateUpdater = new OrbitalStateUpdater(_orbitalSimulation);
|
||||
_infrastructureSimulation = new InfrastructureSimulationService();
|
||||
@@ -42,8 +44,8 @@ internal sealed class SimulationEngine
|
||||
_infrastructureSimulation.UpdateClaims(world, events);
|
||||
_infrastructureSimulation.UpdateConstructionSites(world, events);
|
||||
_geopolitics.Update(world, simulationDeltaSeconds, events);
|
||||
_commanderPlanning.UpdateCommanders(world, simulationDeltaSeconds, events);
|
||||
_playerFaction.Update(world, simulationDeltaSeconds, events);
|
||||
_commanderPlanning.UpdateCommanders(world, _playerStateStore, simulationDeltaSeconds, events);
|
||||
_playerFaction.Update(world, _playerStateStore, simulationDeltaSeconds, events);
|
||||
_stationLifecycle.UpdateStations(world, simulationDeltaSeconds, events);
|
||||
|
||||
foreach (var ship in world.Ships.ToList())
|
||||
@@ -76,7 +78,7 @@ internal sealed class SimulationEngine
|
||||
{
|
||||
foreach (var ship in world.Ships.Where(candidate => candidate.Health <= 0f).ToList())
|
||||
{
|
||||
CreateWreck(world, "ship", ship.Id, ship.SystemId, ship.Position, ship.Definition.CargoCapacity + (ship.Definition.MaxHealth * 0.08f));
|
||||
CreateWreck(world, "ship", ship.Id, ship.SystemId, ship.Position, ship.Definition.GetTotalCargoCapacity() + (ship.Definition.Hull * 0.08f));
|
||||
world.Ships.Remove(ship);
|
||||
if (ship.DockedStationId is not null && world.Stations.FirstOrDefault(station => station.Id == ship.DockedStationId) is { } dockedStation)
|
||||
{
|
||||
@@ -94,7 +96,7 @@ internal sealed class SimulationEngine
|
||||
commander.IsAlive = false;
|
||||
}
|
||||
|
||||
events.Add(new SimulationEventRecord("ship", ship.Id, "destroyed", $"{ship.Definition.Label} was destroyed.", DateTimeOffset.UtcNow));
|
||||
events.Add(new SimulationEventRecord("ship", ship.Id, "destroyed", $"{ship.Definition.Name} was destroyed.", DateTimeOffset.UtcNow));
|
||||
}
|
||||
|
||||
foreach (var station in world.Stations.Where(candidate => candidate.Health <= 0f).ToList())
|
||||
|
||||
@@ -32,7 +32,6 @@ internal sealed class SimulationProjectionService
|
||||
BuildPolicyDeltas(world),
|
||||
BuildShipDeltas(world),
|
||||
BuildFactionDeltas(world),
|
||||
BuildPlayerFactionDelta(world),
|
||||
BuildGeopoliticsDelta(world));
|
||||
|
||||
public WorldSnapshot BuildSnapshot(SimulationWorld world, long sequence)
|
||||
@@ -177,9 +176,9 @@ internal sealed class SimulationProjectionService
|
||||
policy.BlacklistedSystemIds.OrderBy(id => id, StringComparer.Ordinal).ToList())).ToList(),
|
||||
world.Ships.Select(ship => ToShipDelta(world, ship)).Select(ship => new ShipSnapshot(
|
||||
ship.Id,
|
||||
ship.Label,
|
||||
ship.Kind,
|
||||
ship.Class,
|
||||
ship.Name,
|
||||
ship.Purpose,
|
||||
ship.Type,
|
||||
ship.SystemId,
|
||||
ship.LocalPosition,
|
||||
ship.LocalVelocity,
|
||||
@@ -225,7 +224,6 @@ internal sealed class SimulationProjectionService
|
||||
faction.StrategicState,
|
||||
faction.DecisionLog,
|
||||
faction.Commanders)).ToList(),
|
||||
ToPlayerFactionSnapshot(world.PlayerFaction),
|
||||
ToGeopoliticalStateSnapshot(world.Geopolitics));
|
||||
}
|
||||
|
||||
@@ -276,11 +274,6 @@ internal sealed class SimulationProjectionService
|
||||
faction.LastDeltaSignature = BuildFactionSignature(faction, FindFactionCommander(world, faction.Id));
|
||||
}
|
||||
|
||||
if (world.PlayerFaction is not null)
|
||||
{
|
||||
world.PlayerFaction.LastDeltaSignature = BuildPlayerFactionSignature(world.PlayerFaction);
|
||||
}
|
||||
|
||||
if (world.Geopolitics is not null)
|
||||
{
|
||||
world.Geopolitics.LastDeltaSignature = BuildGeopoliticalSignature(world.Geopolitics);
|
||||
@@ -450,23 +443,6 @@ internal sealed class SimulationProjectionService
|
||||
return deltas;
|
||||
}
|
||||
|
||||
private static PlayerFactionSnapshot? BuildPlayerFactionDelta(SimulationWorld world)
|
||||
{
|
||||
if (world.PlayerFaction is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var signature = BuildPlayerFactionSignature(world.PlayerFaction);
|
||||
if (signature == world.PlayerFaction.LastDeltaSignature)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
world.PlayerFaction.LastDeltaSignature = signature;
|
||||
return ToPlayerFactionSnapshot(world.PlayerFaction);
|
||||
}
|
||||
|
||||
private static GeopoliticalStateSnapshot? BuildGeopoliticsDelta(SimulationWorld world)
|
||||
{
|
||||
if (world.Geopolitics is null)
|
||||
@@ -544,11 +520,13 @@ internal sealed class SimulationProjectionService
|
||||
ship.TargetPosition.Z.ToString("0.###"),
|
||||
ship.State.ToContractValue(),
|
||||
string.Join(",", ship.OrderQueue
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.OrderByDescending(GetOrderSourcePriority)
|
||||
.ThenByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => $"{order.Id}:{order.Kind}:{order.Status.ToContractValue()}:{order.Priority}:{order.TargetEntityId}:{order.TargetSystemId}:{order.ItemId}:{order.WaitSeconds:0.###}:{order.Radius:0.###}:{order.MaxSystemRange?.ToString(CultureInfo.InvariantCulture) ?? "none"}:{order.KnownStationsOnly}")),
|
||||
.Select(order => $"{order.Id}:{order.Kind}:{order.SourceKind.ToContractValue()}:{order.SourceId}:{order.Status.ToContractValue()}:{order.Priority}:{order.TargetEntityId}:{order.TargetSystemId}:{order.ItemId}:{order.WaitSeconds:0.###}:{order.Radius:0.###}:{order.MaxSystemRange?.ToString(CultureInfo.InvariantCulture) ?? "none"}:{order.KnownStationsOnly}")),
|
||||
ship.DefaultBehavior.Kind,
|
||||
ship.DefaultBehavior.TargetEntityId ?? "none",
|
||||
ship.DefaultBehavior.ItemId ?? "none",
|
||||
ship.DefaultBehavior.TargetPosition?.X.ToString("0.###") ?? "none",
|
||||
ship.DefaultBehavior.TargetPosition?.Y.ToString("0.###") ?? "none",
|
||||
ship.DefaultBehavior.TargetPosition?.Z.ToString("0.###") ?? "none",
|
||||
@@ -642,59 +620,6 @@ internal sealed class SimulationProjectionService
|
||||
return $"{faction.Credits:0.###}|{faction.PopulationTotal:0.###}|{faction.OreMined:0.###}|{faction.GoodsProduced:0.###}|{faction.ShipsBuilt}|{faction.ShipsLost}|{faction.DefaultPolicySetId}|{assignmentSig}|{strategicSig}|{doctrineSig}|{decisionSig}|{theaterSig}|{campaignSig}|{objectiveSig}|{reservationSig}|{productionSig}";
|
||||
}
|
||||
|
||||
private static string BuildPlayerFactionSignature(PlayerFactionRuntime player)
|
||||
{
|
||||
var intentSig = $"{player.StrategicIntent.StrategicPosture}:{player.StrategicIntent.EconomicPosture}:{player.StrategicIntent.MilitaryPosture}:{player.StrategicIntent.LogisticsPosture}:{player.StrategicIntent.DesiredReserveRatio:0.###}";
|
||||
var registrySig = string.Join("|",
|
||||
player.AssetRegistry.ShipIds.Count,
|
||||
player.AssetRegistry.StationIds.Count,
|
||||
player.AssetRegistry.CommanderIds.Count,
|
||||
player.AssetRegistry.FleetIds.Count,
|
||||
player.AssetRegistry.TaskForceIds.Count,
|
||||
player.AssetRegistry.StationGroupIds.Count,
|
||||
player.AssetRegistry.EconomicRegionIds.Count,
|
||||
player.AssetRegistry.FrontIds.Count,
|
||||
player.AssetRegistry.ReserveIds.Count);
|
||||
var orgSig = string.Join("|",
|
||||
player.Fleets.Count,
|
||||
player.TaskForces.Count,
|
||||
player.StationGroups.Count,
|
||||
player.EconomicRegions.Count,
|
||||
player.Fronts.Count,
|
||||
player.Reserves.Count,
|
||||
player.Policies.Count,
|
||||
player.AutomationPolicies.Count,
|
||||
player.ReinforcementPolicies.Count,
|
||||
player.ProductionPrograms.Count,
|
||||
player.Directives.Count,
|
||||
player.Assignments.Count,
|
||||
player.Alerts.Count);
|
||||
var policySig = string.Join(";",
|
||||
player.Policies.OrderBy(policy => policy.Id, StringComparer.Ordinal)
|
||||
.Select(policy => $"{policy.Id}:{policy.ScopeKind}:{policy.ScopeId}:{policy.PolicySetId}:{policy.TradeAccessPolicy}:{policy.DockingAccessPolicy}:{policy.ConstructionAccessPolicy}:{policy.OperationalRangePolicy}:{policy.CombatEngagementPolicy}:{policy.AvoidHostileSystems}:{policy.FleeHullRatio:0.###}:{policy.UpdatedAtUtc.UtcTicks}"));
|
||||
var automationSig = string.Join(";",
|
||||
player.AutomationPolicies.OrderBy(policy => policy.Id, StringComparer.Ordinal)
|
||||
.Select(policy => $"{policy.Id}:{policy.ScopeKind}:{policy.ScopeId}:{policy.Enabled}:{policy.BehaviorKind}:{policy.UseOrders}:{policy.StagingOrderKind}:{policy.MaxSystemRange}:{policy.KnownStationsOnly}:{policy.Radius:0.###}:{policy.WaitSeconds:0.###}:{policy.PreferredItemId}:{policy.UpdatedAtUtc.UtcTicks}"));
|
||||
var directiveSig = string.Join(";",
|
||||
player.Directives.OrderBy(directive => directive.Id, StringComparer.Ordinal)
|
||||
.Select(directive => $"{directive.Id}:{directive.ScopeKind}:{directive.ScopeId}:{directive.Kind}:{directive.BehaviorKind}:{directive.UseOrders}:{directive.StagingOrderKind}:{directive.TargetEntityId}:{directive.TargetSystemId}:{directive.ItemId}:{directive.Priority}:{directive.UpdatedAtUtc.UtcTicks}"));
|
||||
var assignmentSig = string.Join(";",
|
||||
player.Assignments.OrderBy(assignment => assignment.Id, StringComparer.Ordinal)
|
||||
.Select(assignment => $"{assignment.Id}:{assignment.AssetKind}:{assignment.AssetId}:{assignment.FleetId}:{assignment.TaskForceId}:{assignment.StationGroupId}:{assignment.EconomicRegionId}:{assignment.FrontId}:{assignment.ReserveId}:{assignment.DirectiveId}:{assignment.PolicyId}:{assignment.AutomationPolicyId}:{assignment.Role}:{assignment.Status}:{assignment.UpdatedAtUtc.UtcTicks}"));
|
||||
var decisionSig = string.Join(",", player.DecisionLog.Select(entry => entry.Id));
|
||||
var orgDetailSig = string.Join(";",
|
||||
player.Fleets.OrderBy(entry => entry.Id, StringComparer.Ordinal).Select(entry => $"fleet:{entry.Id}:{entry.FrontId}:{entry.HomeSystemId}:{entry.HomeStationId}:{entry.CommanderId}:{entry.UpdatedAtUtc.UtcTicks}")
|
||||
.Concat(player.TaskForces.OrderBy(entry => entry.Id, StringComparer.Ordinal).Select(entry => $"task-force:{entry.Id}:{entry.FleetId}:{entry.FrontId}:{entry.CommanderId}:{entry.UpdatedAtUtc.UtcTicks}"))
|
||||
.Concat(player.StationGroups.OrderBy(entry => entry.Id, StringComparer.Ordinal).Select(entry => $"station-group:{entry.Id}:{entry.EconomicRegionId}:{entry.UpdatedAtUtc.UtcTicks}"))
|
||||
.Concat(player.EconomicRegions.OrderBy(entry => entry.Id, StringComparer.Ordinal).Select(entry => $"economic-region:{entry.Id}:{entry.SharedEconomicRegionId}:{entry.Role}:{entry.UpdatedAtUtc.UtcTicks}"))
|
||||
.Concat(player.Fronts.OrderBy(entry => entry.Id, StringComparer.Ordinal).Select(entry => $"front:{entry.Id}:{entry.SharedFrontLineId}:{entry.TargetFactionId}:{entry.Priority:0.###}:{entry.UpdatedAtUtc.UtcTicks}"))
|
||||
.Concat(player.Reserves.OrderBy(entry => entry.Id, StringComparer.Ordinal).Select(entry => $"reserve:{entry.Id}:{entry.HomeSystemId}:{entry.UpdatedAtUtc.UtcTicks}")));
|
||||
var alertSig = string.Join(";",
|
||||
player.Alerts.OrderBy(alert => alert.Id, StringComparer.Ordinal)
|
||||
.Select(alert => $"{alert.Id}:{alert.Kind}:{alert.Severity}:{alert.AssetKind}:{alert.AssetId}:{alert.RelatedDirectiveId}:{alert.Status}:{alert.CreatedAtUtc.UtcTicks}"));
|
||||
return $"{player.SovereignFactionId}|{player.Status}|{intentSig}|{registrySig}|{orgSig}|{policySig}|{automationSig}|{directiveSig}|{assignmentSig}|{decisionSig}|{orgDetailSig}|{alertSig}";
|
||||
}
|
||||
|
||||
private static string BuildGeopoliticalSignature(GeopoliticalStateRuntime state)
|
||||
{
|
||||
var diplomacySig = string.Join(";",
|
||||
@@ -882,9 +807,9 @@ internal sealed class SimulationProjectionService
|
||||
|
||||
return new ShipDelta(
|
||||
ship.Id,
|
||||
ship.Definition.Label,
|
||||
ship.Definition.Kind,
|
||||
ship.Definition.Class,
|
||||
ship.Definition.Name,
|
||||
ship.Definition.Purpose.ToDataValue(),
|
||||
ship.Definition.Type.ToDataValue(),
|
||||
ship.SystemId,
|
||||
ToDto(ship.Position),
|
||||
ToDto(ship.Velocity),
|
||||
@@ -906,7 +831,7 @@ internal sealed class SimulationProjectionService
|
||||
ship.DockedStationId,
|
||||
ship.CommanderId,
|
||||
ship.PolicySetId,
|
||||
ship.Definition.CargoCapacity,
|
||||
ship.Definition.GetTotalCargoCapacity(),
|
||||
|
||||
ToShipTravelSpeed(ship).Speed,
|
||||
ToShipTravelSpeed(ship).Unit,
|
||||
@@ -936,11 +861,14 @@ internal sealed class SimulationProjectionService
|
||||
|
||||
private static IReadOnlyList<ShipOrderSnapshot> ToShipOrderSnapshots(ShipRuntime ship) =>
|
||||
ship.OrderQueue
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.OrderByDescending(GetOrderSourcePriority)
|
||||
.ThenByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => new ShipOrderSnapshot(
|
||||
order.Id,
|
||||
order.Kind,
|
||||
order.SourceKind.ToContractValue(),
|
||||
order.SourceId,
|
||||
order.Status.ToContractValue(),
|
||||
order.Priority,
|
||||
order.InterruptCurrentPlan,
|
||||
@@ -962,6 +890,14 @@ internal sealed class SimulationProjectionService
|
||||
order.FailureReason))
|
||||
.ToList();
|
||||
|
||||
private static int GetOrderSourcePriority(ShipOrderRuntime order) => order.SourceKind switch
|
||||
{
|
||||
ShipOrderSourceKind.Player => 300,
|
||||
ShipOrderSourceKind.Commander => 200,
|
||||
ShipOrderSourceKind.Behavior => 100,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
private static DefaultBehaviorSnapshot ToDefaultBehaviorSnapshot(DefaultBehaviorRuntime behavior) =>
|
||||
new(
|
||||
behavior.Kind,
|
||||
@@ -969,7 +905,7 @@ internal sealed class SimulationProjectionService
|
||||
behavior.HomeStationId,
|
||||
behavior.AreaSystemId,
|
||||
behavior.TargetEntityId,
|
||||
behavior.PreferredItemId,
|
||||
behavior.ItemId,
|
||||
behavior.PreferredNodeId,
|
||||
behavior.PreferredConstructionSiteId,
|
||||
behavior.PreferredModuleId,
|
||||
@@ -1385,252 +1321,6 @@ internal sealed class SimulationProjectionService
|
||||
entry.OccurredAtUtc))
|
||||
.ToList();
|
||||
|
||||
private static PlayerFactionSnapshot? ToPlayerFactionSnapshot(PlayerFactionRuntime? player)
|
||||
{
|
||||
if (player is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PlayerFactionSnapshot(
|
||||
player.Id,
|
||||
player.Label,
|
||||
player.SovereignFactionId,
|
||||
player.Status,
|
||||
player.CreatedAtUtc,
|
||||
player.UpdatedAtUtc,
|
||||
new PlayerAssetRegistrySnapshot(
|
||||
player.AssetRegistry.ShipIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.StationIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.CommanderIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.ClaimIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.ConstructionSiteIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.PolicySetIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.MarketOrderIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.FleetIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.TaskForceIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.StationGroupIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.EconomicRegionIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.FrontIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
player.AssetRegistry.ReserveIds.OrderBy(id => id, StringComparer.Ordinal).ToList()),
|
||||
new PlayerStrategicIntentSnapshot(
|
||||
player.StrategicIntent.StrategicPosture,
|
||||
player.StrategicIntent.EconomicPosture,
|
||||
player.StrategicIntent.MilitaryPosture,
|
||||
player.StrategicIntent.LogisticsPosture,
|
||||
player.StrategicIntent.DesiredReserveRatio,
|
||||
player.StrategicIntent.AllowDelegatedCombatAutomation,
|
||||
player.StrategicIntent.AllowDelegatedEconomicAutomation,
|
||||
player.StrategicIntent.Notes),
|
||||
player.Fleets.Select(fleet => new PlayerFleetSnapshot(
|
||||
fleet.Id,
|
||||
fleet.Label,
|
||||
fleet.Status,
|
||||
fleet.Role,
|
||||
fleet.CommanderId,
|
||||
fleet.FrontId,
|
||||
fleet.HomeSystemId,
|
||||
fleet.HomeStationId,
|
||||
fleet.PolicyId,
|
||||
fleet.AutomationPolicyId,
|
||||
fleet.ReinforcementPolicyId,
|
||||
fleet.AssetIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
fleet.TaskForceIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
fleet.DirectiveIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
fleet.UpdatedAtUtc)).ToList(),
|
||||
player.TaskForces.Select(taskForce => new PlayerTaskForceSnapshot(
|
||||
taskForce.Id,
|
||||
taskForce.Label,
|
||||
taskForce.Status,
|
||||
taskForce.Role,
|
||||
taskForce.FleetId,
|
||||
taskForce.CommanderId,
|
||||
taskForce.FrontId,
|
||||
taskForce.PolicyId,
|
||||
taskForce.AutomationPolicyId,
|
||||
taskForce.AssetIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
taskForce.DirectiveIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
taskForce.UpdatedAtUtc)).ToList(),
|
||||
player.StationGroups.Select(group => new PlayerStationGroupSnapshot(
|
||||
group.Id,
|
||||
group.Label,
|
||||
group.Status,
|
||||
group.Role,
|
||||
group.EconomicRegionId,
|
||||
group.PolicyId,
|
||||
group.AutomationPolicyId,
|
||||
group.StationIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
group.DirectiveIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
group.FocusItemIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
group.UpdatedAtUtc)).ToList(),
|
||||
player.EconomicRegions.Select(region => new PlayerEconomicRegionSnapshot(
|
||||
region.Id,
|
||||
region.Label,
|
||||
region.Status,
|
||||
region.Role,
|
||||
region.SharedEconomicRegionId,
|
||||
region.PolicyId,
|
||||
region.AutomationPolicyId,
|
||||
region.SystemIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
region.StationGroupIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
region.DirectiveIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
region.UpdatedAtUtc)).ToList(),
|
||||
player.Fronts.Select(front => new PlayerFrontSnapshot(
|
||||
front.Id,
|
||||
front.Label,
|
||||
front.Status,
|
||||
front.Priority,
|
||||
front.Posture,
|
||||
front.SharedFrontLineId,
|
||||
front.TargetFactionId,
|
||||
front.SystemIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
front.FleetIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
front.ReserveIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
front.DirectiveIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
front.UpdatedAtUtc)).ToList(),
|
||||
player.Reserves.Select(reserve => new PlayerReserveGroupSnapshot(
|
||||
reserve.Id,
|
||||
reserve.Label,
|
||||
reserve.Status,
|
||||
reserve.ReserveKind,
|
||||
reserve.HomeSystemId,
|
||||
reserve.PolicyId,
|
||||
reserve.AssetIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
reserve.FrontIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
reserve.UpdatedAtUtc)).ToList(),
|
||||
player.Policies.Select(policy => new PlayerFactionPolicySnapshot(
|
||||
policy.Id,
|
||||
policy.Label,
|
||||
policy.ScopeKind,
|
||||
policy.ScopeId,
|
||||
policy.PolicySetId,
|
||||
policy.AllowDelegatedCombat,
|
||||
policy.AllowDelegatedTrade,
|
||||
policy.ReserveCreditsRatio,
|
||||
policy.ReserveMilitaryRatio,
|
||||
policy.TradeAccessPolicy,
|
||||
policy.DockingAccessPolicy,
|
||||
policy.ConstructionAccessPolicy,
|
||||
policy.OperationalRangePolicy,
|
||||
policy.CombatEngagementPolicy,
|
||||
policy.AvoidHostileSystems,
|
||||
policy.FleeHullRatio,
|
||||
policy.BlacklistedSystemIds.OrderBy(id => id, StringComparer.Ordinal).ToList(),
|
||||
policy.Notes,
|
||||
policy.UpdatedAtUtc)).ToList(),
|
||||
player.AutomationPolicies.Select(policy => new PlayerAutomationPolicySnapshot(
|
||||
policy.Id,
|
||||
policy.Label,
|
||||
policy.ScopeKind,
|
||||
policy.ScopeId,
|
||||
policy.Enabled,
|
||||
policy.BehaviorKind,
|
||||
policy.UseOrders,
|
||||
policy.StagingOrderKind,
|
||||
policy.MaxSystemRange,
|
||||
policy.KnownStationsOnly,
|
||||
policy.Radius,
|
||||
policy.WaitSeconds,
|
||||
policy.PreferredItemId,
|
||||
policy.Notes,
|
||||
policy.RepeatOrders.Select(ToShipOrderTemplateSnapshot).ToList(),
|
||||
policy.UpdatedAtUtc)).ToList(),
|
||||
player.ReinforcementPolicies.Select(policy => new PlayerReinforcementPolicySnapshot(
|
||||
policy.Id,
|
||||
policy.Label,
|
||||
policy.ScopeKind,
|
||||
policy.ScopeId,
|
||||
policy.ShipKind,
|
||||
policy.DesiredAssetCount,
|
||||
policy.MinimumReserveCount,
|
||||
policy.AutoTransferReserves,
|
||||
policy.AutoQueueProduction,
|
||||
policy.SourceReserveId,
|
||||
policy.TargetFrontId,
|
||||
policy.Notes,
|
||||
policy.UpdatedAtUtc)).ToList(),
|
||||
player.ProductionPrograms.Select(program => new PlayerProductionProgramSnapshot(
|
||||
program.Id,
|
||||
program.Label,
|
||||
program.Status,
|
||||
program.Kind,
|
||||
program.TargetShipKind,
|
||||
program.TargetModuleId,
|
||||
program.TargetItemId,
|
||||
program.TargetCount,
|
||||
program.CurrentCount,
|
||||
program.StationGroupId,
|
||||
program.ReinforcementPolicyId,
|
||||
program.Notes,
|
||||
program.UpdatedAtUtc)).ToList(),
|
||||
player.Directives.Select(directive => new PlayerDirectiveSnapshot(
|
||||
directive.Id,
|
||||
directive.Label,
|
||||
directive.Status,
|
||||
directive.Kind,
|
||||
directive.ScopeKind,
|
||||
directive.ScopeId,
|
||||
directive.TargetEntityId,
|
||||
directive.TargetSystemId,
|
||||
directive.TargetPosition is null ? null : ToDto(directive.TargetPosition.Value),
|
||||
directive.HomeSystemId,
|
||||
directive.HomeStationId,
|
||||
directive.SourceStationId,
|
||||
directive.DestinationStationId,
|
||||
directive.BehaviorKind,
|
||||
directive.UseOrders,
|
||||
directive.StagingOrderKind,
|
||||
directive.ItemId,
|
||||
directive.PreferredNodeId,
|
||||
directive.PreferredConstructionSiteId,
|
||||
directive.PreferredModuleId,
|
||||
directive.Priority,
|
||||
directive.Radius,
|
||||
directive.WaitSeconds,
|
||||
directive.MaxSystemRange,
|
||||
directive.KnownStationsOnly,
|
||||
directive.PatrolPoints.Select(ToDto).ToList(),
|
||||
directive.RepeatOrders.Select(ToShipOrderTemplateSnapshot).ToList(),
|
||||
directive.PolicyId,
|
||||
directive.AutomationPolicyId,
|
||||
directive.Notes,
|
||||
directive.CreatedAtUtc,
|
||||
directive.UpdatedAtUtc)).ToList(),
|
||||
player.Assignments.Select(assignment => new PlayerAssignmentSnapshot(
|
||||
assignment.Id,
|
||||
assignment.AssetKind,
|
||||
assignment.AssetId,
|
||||
assignment.FleetId,
|
||||
assignment.TaskForceId,
|
||||
assignment.StationGroupId,
|
||||
assignment.EconomicRegionId,
|
||||
assignment.FrontId,
|
||||
assignment.ReserveId,
|
||||
assignment.DirectiveId,
|
||||
assignment.PolicyId,
|
||||
assignment.AutomationPolicyId,
|
||||
assignment.Role,
|
||||
assignment.Status,
|
||||
assignment.UpdatedAtUtc)).ToList(),
|
||||
player.DecisionLog.Select(entry => new PlayerDecisionLogEntrySnapshot(
|
||||
entry.Id,
|
||||
entry.Kind,
|
||||
entry.Summary,
|
||||
entry.RelatedEntityKind,
|
||||
entry.RelatedEntityId,
|
||||
entry.OccurredAtUtc)).ToList(),
|
||||
player.Alerts.Select(alert => new PlayerAlertSnapshot(
|
||||
alert.Id,
|
||||
alert.Kind,
|
||||
alert.Severity,
|
||||
alert.Summary,
|
||||
alert.AssetKind,
|
||||
alert.AssetId,
|
||||
alert.RelatedDirectiveId,
|
||||
alert.Status,
|
||||
alert.CreatedAtUtc)).ToList());
|
||||
}
|
||||
|
||||
private static GeopoliticalStateSnapshot? ToGeopoliticalStateSnapshot(GeopoliticalStateRuntime? state)
|
||||
{
|
||||
if (state is null)
|
||||
|
||||
Reference in New Issue
Block a user