Refactor runtime bootstrap and ship control flows
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
using static SpaceGame.Api.Shared.Runtime.SimulationRuntimeSupport;
|
||||
using static SpaceGame.Api.Shared.Runtime.ShipBehaviorKinds;
|
||||
|
||||
namespace SpaceGame.Api.PlayerFaction.Simulation;
|
||||
|
||||
internal sealed class PlayerFactionService
|
||||
@@ -6,58 +9,61 @@ internal sealed class PlayerFactionService
|
||||
private const int MaxAlerts = 32;
|
||||
private const string PlayerFactionDomainId = "player-faction";
|
||||
|
||||
internal static bool IsPlayerFaction(SimulationWorld world, string factionId) =>
|
||||
world.PlayerFaction is not null && string.Equals(world.PlayerFaction.SovereignFactionId, factionId, StringComparison.Ordinal);
|
||||
internal static bool IsPlayerFaction(IPlayerStateStore playerStateStore, string factionId) =>
|
||||
playerStateStore.GetPlayerFactions().Any(player =>
|
||||
string.Equals(player.SovereignFactionId, factionId, StringComparison.Ordinal));
|
||||
|
||||
internal PlayerFactionRuntime EnsureDomain(SimulationWorld world)
|
||||
internal PlayerFactionRuntime? TryGetDomain(IPlayerStateStore playerStateStore, string playerId)
|
||||
{
|
||||
if (world.PlayerFaction is not null)
|
||||
{
|
||||
return world.PlayerFaction;
|
||||
}
|
||||
return playerStateStore.TryGetPlayerFaction(playerId, out var player) ? player : null;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime EnsureDomain(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId)
|
||||
{
|
||||
var sovereignFaction = world.Factions.OrderBy(faction => faction.Id, StringComparer.Ordinal).FirstOrDefault()
|
||||
?? throw new InvalidOperationException("Cannot create a player faction domain without any factions in the world.");
|
||||
|
||||
world.PlayerFaction = new PlayerFactionRuntime
|
||||
var player = playerStateStore.GetOrAddPlayerFaction(playerId, () => new PlayerFactionRuntime
|
||||
{
|
||||
Id = PlayerFactionDomainId,
|
||||
Label = $"{sovereignFaction.Label} Command",
|
||||
SovereignFactionId = sovereignFaction.Id,
|
||||
CreatedAtUtc = world.GeneratedAtUtc,
|
||||
UpdatedAtUtc = world.GeneratedAtUtc,
|
||||
};
|
||||
});
|
||||
|
||||
EnsureBaseStructures(world, world.PlayerFaction);
|
||||
SyncRegistry(world, world.PlayerFaction);
|
||||
return world.PlayerFaction;
|
||||
EnsureBaseStructures(world, player);
|
||||
SyncRegistry(world, player);
|
||||
return player;
|
||||
}
|
||||
|
||||
internal void Update(SimulationWorld world, float _deltaSeconds, ICollection<SimulationEventRecord> events)
|
||||
internal void Update(SimulationWorld world, IPlayerStateStore playerStateStore, float _deltaSeconds, ICollection<SimulationEventRecord> events)
|
||||
{
|
||||
if (world.PlayerFaction is null && world.Factions.Count == 0)
|
||||
if (playerStateStore.GetPlayerFactions().Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var player = EnsureDomain(world);
|
||||
EnsureBaseStructures(world, player);
|
||||
SyncRegistry(world, player);
|
||||
PrunePlayerState(world, player);
|
||||
RefreshGeopoliticalOrganizationContext(world, player);
|
||||
ReconcileOrganizationAssignments(world, player);
|
||||
ReconcileDirectiveScopes(player);
|
||||
RefreshProductionPrograms(world, player);
|
||||
ApplyStrategicIntegration(world, player);
|
||||
ApplyPolicies(world, player);
|
||||
ApplyAssignmentsAndDirectives(world, player, events);
|
||||
RefreshAlerts(world, player);
|
||||
player.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
||||
foreach (var player in playerStateStore.GetPlayerFactions())
|
||||
{
|
||||
EnsureBaseStructures(world, player);
|
||||
SyncRegistry(world, player);
|
||||
PrunePlayerState(world, player);
|
||||
RefreshGeopoliticalOrganizationContext(world, player);
|
||||
ReconcileOrganizationAssignments(world, player);
|
||||
ReconcileDirectiveScopes(player);
|
||||
RefreshProductionPrograms(world, player);
|
||||
ApplyStrategicIntegration(world, player);
|
||||
ApplyPolicies(world, player);
|
||||
ApplyAssignmentsAndDirectives(world, player, events);
|
||||
RefreshAlerts(world, player);
|
||||
player.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
||||
}
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime CreateOrganization(SimulationWorld world, PlayerOrganizationCommandRequest request)
|
||||
internal PlayerFactionRuntime CreateOrganization(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, PlayerOrganizationCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
var id = CreateDomainId(request.Kind, request.Label, ExistingOrganizationIds(player));
|
||||
var nowUtc = DateTimeOffset.UtcNow;
|
||||
|
||||
@@ -172,9 +178,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime DeleteOrganization(SimulationWorld world, string organizationId)
|
||||
internal PlayerFactionRuntime DeleteOrganization(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string organizationId)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
RemoveOrganization(player, organizationId);
|
||||
player.Assignments.RemoveAll(assignment =>
|
||||
assignment.FleetId == organizationId ||
|
||||
@@ -190,9 +196,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime UpdateOrganizationMembership(SimulationWorld world, string organizationId, PlayerOrganizationMembershipCommandRequest request)
|
||||
internal PlayerFactionRuntime UpdateOrganizationMembership(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string organizationId, PlayerOrganizationMembershipCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
var kind = ResolveOrganizationKind(player, organizationId);
|
||||
switch (kind)
|
||||
{
|
||||
@@ -241,9 +247,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime UpsertDirective(SimulationWorld world, string? directiveId, PlayerDirectiveCommandRequest request)
|
||||
internal PlayerFactionRuntime UpsertDirective(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string? directiveId, PlayerDirectiveCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
var directive = directiveId is null
|
||||
? null
|
||||
: player.Directives.FirstOrDefault(candidate => string.Equals(candidate.Id, directiveId, StringComparison.Ordinal));
|
||||
@@ -318,9 +324,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime DeleteDirective(SimulationWorld world, string directiveId)
|
||||
internal PlayerFactionRuntime DeleteDirective(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string directiveId)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
player.Directives.RemoveAll(directive => directive.Id == directiveId);
|
||||
foreach (var assignment in player.Assignments.Where(assignment => assignment.DirectiveId == directiveId))
|
||||
{
|
||||
@@ -332,9 +338,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime UpsertPolicy(SimulationWorld world, string? policyId, PlayerPolicyCommandRequest request)
|
||||
internal PlayerFactionRuntime UpsertPolicy(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string? policyId, PlayerPolicyCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
var policy = policyId is null
|
||||
? null
|
||||
: player.Policies.FirstOrDefault(candidate => string.Equals(candidate.Id, policyId, StringComparison.Ordinal));
|
||||
@@ -403,9 +409,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime UpsertAutomationPolicy(SimulationWorld world, string? automationPolicyId, PlayerAutomationPolicyCommandRequest request)
|
||||
internal PlayerFactionRuntime UpsertAutomationPolicy(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string? automationPolicyId, PlayerAutomationPolicyCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
var policy = automationPolicyId is null
|
||||
? null
|
||||
: player.AutomationPolicies.FirstOrDefault(candidate => string.Equals(candidate.Id, automationPolicyId, StringComparison.Ordinal));
|
||||
@@ -461,9 +467,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime UpsertReinforcementPolicy(SimulationWorld world, string? reinforcementPolicyId, PlayerReinforcementPolicyCommandRequest request)
|
||||
internal PlayerFactionRuntime UpsertReinforcementPolicy(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string? reinforcementPolicyId, PlayerReinforcementPolicyCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
var policy = reinforcementPolicyId is null
|
||||
? null
|
||||
: player.ReinforcementPolicies.FirstOrDefault(candidate => string.Equals(candidate.Id, reinforcementPolicyId, StringComparison.Ordinal));
|
||||
@@ -495,9 +501,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime UpsertProductionProgram(SimulationWorld world, string? productionProgramId, PlayerProductionProgramCommandRequest request)
|
||||
internal PlayerFactionRuntime UpsertProductionProgram(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string? productionProgramId, PlayerProductionProgramCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
var program = productionProgramId is null
|
||||
? null
|
||||
: player.ProductionPrograms.FirstOrDefault(candidate => string.Equals(candidate.Id, productionProgramId, StringComparison.Ordinal));
|
||||
@@ -527,9 +533,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime UpsertAssignment(SimulationWorld world, string assetId, PlayerAssetAssignmentCommandRequest request)
|
||||
internal PlayerFactionRuntime UpsertAssignment(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string assetId, PlayerAssetAssignmentCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
var assignment = player.Assignments.FirstOrDefault(candidate =>
|
||||
string.Equals(candidate.AssetId, assetId, StringComparison.Ordinal) &&
|
||||
string.Equals(candidate.AssetKind, request.AssetKind, StringComparison.Ordinal));
|
||||
@@ -586,9 +592,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal PlayerFactionRuntime UpdateStrategicIntent(SimulationWorld world, PlayerStrategicIntentCommandRequest request)
|
||||
internal PlayerFactionRuntime UpdateStrategicIntent(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, PlayerStrategicIntentCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
player.StrategicIntent.StrategicPosture = request.StrategicPosture;
|
||||
player.StrategicIntent.EconomicPosture = request.EconomicPosture;
|
||||
player.StrategicIntent.MilitaryPosture = request.MilitaryPosture;
|
||||
@@ -602,9 +608,9 @@ internal sealed class PlayerFactionService
|
||||
return player;
|
||||
}
|
||||
|
||||
internal ShipRuntime? EnqueueDirectShipOrder(SimulationWorld world, string shipId, ShipOrderCommandRequest request)
|
||||
internal ShipRuntime? EnqueueDirectShipOrder(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string shipId, ShipOrderCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
if (!player.AssetRegistry.ShipIds.Contains(shipId))
|
||||
{
|
||||
return null;
|
||||
@@ -625,6 +631,8 @@ internal sealed class PlayerFactionService
|
||||
{
|
||||
Id = $"order-{ship.Id}-{Guid.NewGuid():N}",
|
||||
Kind = request.Kind,
|
||||
SourceKind = ShipOrderSourceKind.Player,
|
||||
SourceId = playerId,
|
||||
Priority = request.Priority,
|
||||
InterruptCurrentPlan = request.InterruptCurrentPlan,
|
||||
Label = request.Label,
|
||||
@@ -643,11 +651,11 @@ internal sealed class PlayerFactionService
|
||||
KnownStationsOnly = request.KnownStationsOnly ?? false,
|
||||
});
|
||||
|
||||
AddDecision(player, "ship-order-enqueued", $"Queued {request.Kind} for {ship.Definition.Label}.", "ship", shipId);
|
||||
AddDecision(player, "ship-order-enqueued", $"Queued {request.Kind} for {ship.Definition.Name}.", "ship", shipId);
|
||||
player.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
||||
ship.ControlSourceKind = "player-order";
|
||||
ship.ControlSourceId = ship.OrderQueue
|
||||
.Where(order => !order.Id.StartsWith("ai-order-", StringComparison.Ordinal))
|
||||
.Where(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => order.Id)
|
||||
@@ -659,9 +667,9 @@ internal sealed class PlayerFactionService
|
||||
return ship;
|
||||
}
|
||||
|
||||
internal ShipRuntime? RemoveDirectShipOrder(SimulationWorld world, string shipId, string orderId)
|
||||
internal ShipRuntime? RemoveDirectShipOrder(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string shipId, string orderId)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
if (!player.AssetRegistry.ShipIds.Contains(shipId))
|
||||
{
|
||||
return null;
|
||||
@@ -676,21 +684,21 @@ internal sealed class PlayerFactionService
|
||||
var removed = ship.OrderQueue.RemoveAll(order => order.Id == orderId);
|
||||
if (removed > 0)
|
||||
{
|
||||
AddDecision(player, "ship-order-removed", $"Removed order {orderId} from {ship.Definition.Label}.", "ship", shipId);
|
||||
AddDecision(player, "ship-order-removed", $"Removed order {orderId} from {ship.Definition.Name}.", "ship", shipId);
|
||||
player.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
ship.ControlSourceKind = ship.OrderQueue.Any(order => !order.Id.StartsWith("ai-order-", StringComparison.Ordinal))
|
||||
ship.ControlSourceKind = ship.OrderQueue.Any(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
? "player-order"
|
||||
: "player-manual";
|
||||
ship.ControlSourceId = ship.OrderQueue
|
||||
.Where(order => !order.Id.StartsWith("ai-order-", StringComparison.Ordinal))
|
||||
.Where(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => order.Id)
|
||||
.FirstOrDefault();
|
||||
ship.ControlReason = ship.OrderQueue
|
||||
.Where(order => !order.Id.StartsWith("ai-order-", StringComparison.Ordinal))
|
||||
.Where(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => order.Label ?? order.Kind)
|
||||
@@ -702,9 +710,9 @@ internal sealed class PlayerFactionService
|
||||
return ship;
|
||||
}
|
||||
|
||||
internal ShipRuntime? ConfigureDirectShipBehavior(SimulationWorld world, string shipId, ShipDefaultBehaviorCommandRequest request)
|
||||
internal ShipRuntime? ConfigureDirectShipBehavior(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string shipId, ShipDefaultBehaviorCommandRequest request)
|
||||
{
|
||||
var player = EnsureDomain(world);
|
||||
var player = EnsureDomain(world, playerStateStore, playerId);
|
||||
if (!player.AssetRegistry.ShipIds.Contains(shipId))
|
||||
{
|
||||
return null;
|
||||
@@ -723,7 +731,7 @@ internal sealed class PlayerFactionService
|
||||
directive = new PlayerDirectiveRuntime
|
||||
{
|
||||
Id = directiveId,
|
||||
Label = $"Direct control {ship.Definition.Label}",
|
||||
Label = $"Direct control {ship.Definition.Name}",
|
||||
ScopeKind = "ship",
|
||||
ScopeId = shipId,
|
||||
Kind = "direct-control",
|
||||
@@ -732,7 +740,7 @@ internal sealed class PlayerFactionService
|
||||
player.Directives.Add(directive);
|
||||
}
|
||||
|
||||
directive.Label = $"Direct control {ship.Definition.Label}";
|
||||
directive.Label = $"Direct control {ship.Definition.Name}";
|
||||
directive.Kind = "direct-control";
|
||||
directive.ScopeKind = "ship";
|
||||
directive.ScopeId = shipId;
|
||||
@@ -746,7 +754,7 @@ internal sealed class PlayerFactionService
|
||||
directive.HomeStationId = request.HomeStationId;
|
||||
directive.SourceStationId = request.HomeStationId;
|
||||
directive.DestinationStationId = null;
|
||||
directive.ItemId = request.PreferredItemId;
|
||||
directive.ItemId = request.ItemId;
|
||||
directive.PreferredNodeId = request.PreferredNodeId;
|
||||
directive.PreferredConstructionSiteId = request.PreferredConstructionSiteId;
|
||||
directive.PreferredModuleId = request.PreferredModuleId;
|
||||
@@ -793,7 +801,7 @@ internal sealed class PlayerFactionService
|
||||
ship.ControlSourceKind = "player-directive";
|
||||
ship.ControlSourceId = directive.Id;
|
||||
ship.ControlReason = directive.Label;
|
||||
AddDecision(player, "ship-behavior-configured", $"Configured {request.Kind} for {ship.Definition.Label}.", "ship", shipId);
|
||||
AddDecision(player, "ship-behavior-configured", $"Configured {request.Kind} for {ship.Definition.Name}.", "ship", shipId);
|
||||
player.UpdatedAtUtc = directive.UpdatedAtUtc;
|
||||
ship.NeedsReplan = true;
|
||||
ship.LastReplanReason = "player-behavior-configured";
|
||||
@@ -826,7 +834,7 @@ internal sealed class PlayerFactionService
|
||||
{
|
||||
Id = "player-core-automation",
|
||||
Label = "Core Automation",
|
||||
BehaviorKind = "idle",
|
||||
BehaviorKind = Idle,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1035,7 +1043,7 @@ internal sealed class PlayerFactionService
|
||||
var changed = ApplyDirectiveToShip(commander, ship, directive, automation, assignment);
|
||||
if (changed && directive is not null)
|
||||
{
|
||||
events.Add(new SimulationEventRecord("ship", ship.Id, "player-directive", $"{ship.Definition.Label} aligned to player directive {directive.Label}.", DateTimeOffset.UtcNow, "player", "universe", ship.Id));
|
||||
events.Add(new SimulationEventRecord("ship", ship.Id, "player-directive", $"{ship.Definition.Name} aligned to player directive {directive.Label}.", DateTimeOffset.UtcNow, "player", "universe", ship.Id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1246,13 +1254,13 @@ internal sealed class PlayerFactionService
|
||||
? "player-directive"
|
||||
: automation is not null
|
||||
? "player-automation"
|
||||
: ship.OrderQueue.Any(order => !order.Id.StartsWith("ai-order-", StringComparison.Ordinal))
|
||||
: ship.OrderQueue.Any(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
? "player-order"
|
||||
: "player-manual";
|
||||
var desiredControlSourceId = directive?.Id
|
||||
?? automation?.Id
|
||||
?? ship.OrderQueue
|
||||
.Where(order => !order.Id.StartsWith("ai-order-", StringComparison.Ordinal))
|
||||
.Where(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => order.Id)
|
||||
@@ -1260,7 +1268,7 @@ internal sealed class PlayerFactionService
|
||||
var desiredControlReason = directive?.Label
|
||||
?? automation?.Label
|
||||
?? ship.OrderQueue
|
||||
.Where(order => !order.Id.StartsWith("ai-order-", StringComparison.Ordinal))
|
||||
.Where(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => order.Label ?? order.Kind)
|
||||
@@ -1342,7 +1350,7 @@ internal sealed class PlayerFactionService
|
||||
HomeStationId = directive?.HomeStationId ?? ship.DefaultBehavior.HomeStationId,
|
||||
AreaSystemId = directive?.TargetSystemId ?? directive?.HomeSystemId ?? ship.DefaultBehavior.AreaSystemId ?? ship.SystemId,
|
||||
TargetEntityId = directive?.TargetEntityId,
|
||||
PreferredItemId = directive?.ItemId ?? automation?.PreferredItemId ?? ship.DefaultBehavior.PreferredItemId,
|
||||
ItemId = directive?.ItemId ?? automation?.PreferredItemId ?? ship.DefaultBehavior.ItemId,
|
||||
PreferredNodeId = directive?.PreferredNodeId ?? ship.DefaultBehavior.PreferredNodeId,
|
||||
PreferredConstructionSiteId = directive?.PreferredConstructionSiteId ?? ship.DefaultBehavior.PreferredConstructionSiteId,
|
||||
PreferredModuleId = directive?.PreferredModuleId ?? ship.DefaultBehavior.PreferredModuleId,
|
||||
@@ -1375,6 +1383,8 @@ internal sealed class PlayerFactionService
|
||||
{
|
||||
Id = aiOrderId!,
|
||||
Kind = directive.StagingOrderKind!,
|
||||
SourceKind = ShipOrderSourceKind.Player,
|
||||
SourceId = directive.Id,
|
||||
Priority = Math.Max(0, directive.Priority),
|
||||
InterruptCurrentPlan = true,
|
||||
Label = directive.Label,
|
||||
@@ -1447,7 +1457,7 @@ internal sealed class PlayerFactionService
|
||||
target.HomeStationId = source.HomeStationId;
|
||||
target.AreaSystemId = source.AreaSystemId;
|
||||
target.TargetEntityId = source.TargetEntityId;
|
||||
target.PreferredItemId = source.PreferredItemId;
|
||||
target.ItemId = source.ItemId;
|
||||
target.PreferredNodeId = source.PreferredNodeId;
|
||||
target.PreferredConstructionSiteId = source.PreferredConstructionSiteId;
|
||||
target.PreferredModuleId = source.PreferredModuleId;
|
||||
@@ -1468,7 +1478,7 @@ internal sealed class PlayerFactionService
|
||||
&& string.Equals(left.HomeStationId, right.HomeStationId, StringComparison.Ordinal)
|
||||
&& string.Equals(left.AreaSystemId, right.AreaSystemId, StringComparison.Ordinal)
|
||||
&& string.Equals(left.TargetEntityId, right.TargetEntityId, StringComparison.Ordinal)
|
||||
&& string.Equals(left.PreferredItemId, right.PreferredItemId, StringComparison.Ordinal)
|
||||
&& string.Equals(left.ItemId, right.ItemId, StringComparison.Ordinal)
|
||||
&& string.Equals(left.PreferredNodeId, right.PreferredNodeId, StringComparison.Ordinal)
|
||||
&& string.Equals(left.PreferredConstructionSiteId, right.PreferredConstructionSiteId, StringComparison.Ordinal)
|
||||
&& string.Equals(left.PreferredModuleId, right.PreferredModuleId, StringComparison.Ordinal)
|
||||
@@ -1501,6 +1511,8 @@ internal sealed class PlayerFactionService
|
||||
private static bool ShipOrdersEqual(ShipOrderRuntime left, ShipOrderRuntime right) =>
|
||||
string.Equals(left.Id, right.Id, StringComparison.Ordinal)
|
||||
&& string.Equals(left.Kind, right.Kind, StringComparison.Ordinal)
|
||||
&& left.SourceKind == right.SourceKind
|
||||
&& string.Equals(left.SourceId, right.SourceId, StringComparison.Ordinal)
|
||||
&& left.Priority == right.Priority
|
||||
&& left.InterruptCurrentPlan == right.InterruptCurrentPlan
|
||||
&& string.Equals(left.Label, right.Label, StringComparison.Ordinal)
|
||||
@@ -1716,7 +1728,7 @@ internal sealed class PlayerFactionService
|
||||
{
|
||||
program.CurrentCount = world.Ships.Count(ship =>
|
||||
ship.FactionId == player.SovereignFactionId &&
|
||||
string.Equals(ship.Definition.Kind, program.TargetShipKind, StringComparison.Ordinal));
|
||||
string.Equals(GetShipCategory(ship.Definition), program.TargetShipKind, StringComparison.Ordinal));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2113,7 +2125,7 @@ internal sealed class PlayerFactionService
|
||||
{
|
||||
var available = world.Ships.Count(ship =>
|
||||
ship.FactionId == player.SovereignFactionId &&
|
||||
string.Equals(ship.Definition.Kind, policy.ShipKind, StringComparison.Ordinal));
|
||||
string.Equals(GetShipCategory(ship.Definition), policy.ShipKind, StringComparison.Ordinal));
|
||||
if (available < policy.DesiredAssetCount)
|
||||
{
|
||||
player.Alerts.Add(new PlayerAlertRuntime
|
||||
|
||||
Reference in New Issue
Block a user