Refine ship orders and viewer controls
This commit is contained in:
@@ -672,12 +672,7 @@ internal sealed class PlayerFactionService
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ship.OrderQueue.Count >= 8)
|
||||
{
|
||||
throw new InvalidOperationException("Order queue is full.");
|
||||
}
|
||||
|
||||
ship.OrderQueue.Add(new ShipOrderRuntime
|
||||
ship.OrderQueue.EnqueuePlayerOrder(new ShipOrderRuntime
|
||||
{
|
||||
Id = $"order-{ship.Id}-{Guid.NewGuid():N}",
|
||||
Kind = request.Kind,
|
||||
@@ -704,12 +699,7 @@ internal sealed class PlayerFactionService
|
||||
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.SourceKind == ShipOrderSourceKind.Player)
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => order.Id)
|
||||
.FirstOrDefault();
|
||||
ship.ControlSourceId = ship.OrderQueue.FindLeadingOrderForSource(ShipOrderSourceKind.Player)?.Id;
|
||||
ship.ControlReason = request.Label ?? request.Kind;
|
||||
ship.NeedsReplan = true;
|
||||
ship.LastReplanReason = "player-order-enqueued";
|
||||
@@ -731,28 +721,18 @@ internal sealed class PlayerFactionService
|
||||
return null;
|
||||
}
|
||||
|
||||
var removed = ship.OrderQueue.RemoveAll(order => order.Id == orderId);
|
||||
if (removed > 0)
|
||||
var removed = ship.OrderQueue.RemoveById(orderId);
|
||||
if (removed)
|
||||
{
|
||||
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.SourceKind == ShipOrderSourceKind.Player)
|
||||
ship.ControlSourceKind = ship.OrderQueue.HasOrdersFromSource(ShipOrderSourceKind.Player)
|
||||
? "player-order"
|
||||
: "player-manual";
|
||||
ship.ControlSourceId = ship.OrderQueue
|
||||
.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.SourceKind == ShipOrderSourceKind.Player)
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => order.Label ?? order.Kind)
|
||||
.FirstOrDefault()
|
||||
ship.ControlSourceId = ship.OrderQueue.FindLeadingOrderForSource(ShipOrderSourceKind.Player)?.Id;
|
||||
ship.ControlReason = ship.OrderQueue.GetLeadingOrderLabelForSource(ShipOrderSourceKind.Player)
|
||||
?? "manual-player-control";
|
||||
ship.NeedsReplan = true;
|
||||
ship.LastReplanReason = "player-order-removed";
|
||||
@@ -760,6 +740,93 @@ internal sealed class PlayerFactionService
|
||||
return ship;
|
||||
}
|
||||
|
||||
internal ShipRuntime? UpdateDirectShipOrder(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string shipId, string orderId, ShipOrderUpdateCommandRequest request)
|
||||
{
|
||||
var player = EnsureInitializedDomain(world, playerStateStore, playerId);
|
||||
if (!player.AssetRegistry.ShipIds.Contains(shipId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ship = world.Ships.FirstOrDefault(candidate => candidate.Id == shipId);
|
||||
if (ship is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var order = ship.OrderQueue.FindById(orderId);
|
||||
if (order is null || order.SourceKind != ShipOrderSourceKind.Player)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
order.Priority = request.Priority;
|
||||
order.InterruptCurrentPlan = request.InterruptCurrentPlan;
|
||||
order.Label = request.Label;
|
||||
order.TargetEntityId = request.TargetEntityId;
|
||||
order.TargetSystemId = request.TargetSystemId;
|
||||
order.TargetPosition = request.TargetPosition is null ? null : new Vector3(request.TargetPosition.X, request.TargetPosition.Y, request.TargetPosition.Z);
|
||||
order.SourceStationId = request.SourceStationId;
|
||||
order.DestinationStationId = request.DestinationStationId;
|
||||
order.ItemId = request.ItemId;
|
||||
order.AnchorId = request.AnchorId;
|
||||
order.ConstructionSiteId = request.ConstructionSiteId;
|
||||
order.ModuleId = request.ModuleId;
|
||||
order.WaitSeconds = MathF.Max(0f, request.WaitSeconds ?? 0f);
|
||||
order.Radius = MathF.Max(0f, request.Radius ?? 0f);
|
||||
order.MaxSystemRange = request.MaxSystemRange;
|
||||
order.KnownStationsOnly = request.KnownStationsOnly ?? false;
|
||||
order.Status = OrderStatus.Queued;
|
||||
order.FailureReason = null;
|
||||
|
||||
AddDecision(player, "ship-order-updated", $"Updated order {orderId} on {ship.Definition.Name}.", "ship", shipId);
|
||||
player.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
||||
ship.ControlSourceKind = ship.OrderQueue.HasOrdersFromSource(ShipOrderSourceKind.Player)
|
||||
? "player-order"
|
||||
: "player-manual";
|
||||
ship.ControlSourceId = ship.OrderQueue.FindLeadingOrderForSource(ShipOrderSourceKind.Player)?.Id;
|
||||
ship.ControlReason = ship.OrderQueue.GetLeadingOrderLabelForSource(ShipOrderSourceKind.Player)
|
||||
?? request.Label
|
||||
?? request.Kind;
|
||||
ship.NeedsReplan = true;
|
||||
ship.LastReplanReason = "player-order-updated";
|
||||
ship.LastDeltaSignature = string.Empty;
|
||||
return ship;
|
||||
}
|
||||
|
||||
internal ShipRuntime? ReorderDirectShipOrder(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string shipId, string orderId, int targetIndex)
|
||||
{
|
||||
var player = EnsureInitializedDomain(world, playerStateStore, playerId);
|
||||
if (!player.AssetRegistry.ShipIds.Contains(shipId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ship = world.Ships.FirstOrDefault(candidate => candidate.Id == shipId);
|
||||
if (ship is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ship.OrderQueue.TryMovePlayerOrder(orderId, targetIndex))
|
||||
{
|
||||
return ship;
|
||||
}
|
||||
|
||||
AddDecision(player, "ship-order-reordered", $"Reordered order {orderId} on {ship.Definition.Name}.", "ship", shipId);
|
||||
player.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
||||
ship.ControlSourceKind = ship.OrderQueue.HasOrdersFromSource(ShipOrderSourceKind.Player)
|
||||
? "player-order"
|
||||
: "player-manual";
|
||||
ship.ControlSourceId = ship.OrderQueue.FindLeadingOrderForSource(ShipOrderSourceKind.Player)?.Id;
|
||||
ship.ControlReason = ship.OrderQueue.GetLeadingOrderLabelForSource(ShipOrderSourceKind.Player)
|
||||
?? "manual-player-control";
|
||||
ship.NeedsReplan = true;
|
||||
ship.LastReplanReason = "player-order-reordered";
|
||||
ship.LastDeltaSignature = string.Empty;
|
||||
return ship;
|
||||
}
|
||||
|
||||
internal ShipRuntime? ConfigureDirectShipBehavior(SimulationWorld world, IPlayerStateStore playerStateStore, string playerId, string shipId, ShipDefaultBehaviorCommandRequest request)
|
||||
{
|
||||
var player = EnsureInitializedDomain(world, playerStateStore, playerId);
|
||||
@@ -1321,25 +1388,15 @@ internal sealed class PlayerFactionService
|
||||
? "player-directive"
|
||||
: automation is not null
|
||||
? "player-automation"
|
||||
: ship.OrderQueue.Any(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
: ship.OrderQueue.HasOrdersFromSource(ShipOrderSourceKind.Player)
|
||||
? "player-order"
|
||||
: "player-manual";
|
||||
var desiredControlSourceId = directive?.Id
|
||||
?? automation?.Id
|
||||
?? ship.OrderQueue
|
||||
.Where(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => order.Id)
|
||||
.FirstOrDefault();
|
||||
?? ship.OrderQueue.FindLeadingOrderForSource(ShipOrderSourceKind.Player)?.Id;
|
||||
var desiredControlReason = directive?.Label
|
||||
?? automation?.Label
|
||||
?? ship.OrderQueue
|
||||
.Where(order => order.SourceKind == ShipOrderSourceKind.Player)
|
||||
.OrderByDescending(order => order.Priority)
|
||||
.ThenBy(order => order.CreatedAtUtc)
|
||||
.Select(order => order.Label ?? order.Kind)
|
||||
.FirstOrDefault()
|
||||
?? ship.OrderQueue.GetLeadingOrderLabelForSource(ShipOrderSourceKind.Player)
|
||||
?? (hasBehaviorSource ? "delegated-player-control" : "manual-player-control");
|
||||
|
||||
var assignmentChanged = !AssignmentsEqual(commander.Assignment, desiredAssignment);
|
||||
@@ -1438,7 +1495,7 @@ internal sealed class PlayerFactionService
|
||||
private static bool ReconcileDirectiveOrders(ShipRuntime ship, PlayerDirectiveRuntime? directive, PlayerAutomationPolicyRuntime? automation)
|
||||
{
|
||||
var aiOrderId = directive is null ? null : $"player-order-{directive.Id}";
|
||||
var changed = ship.OrderQueue.RemoveAll(order => order.Id.StartsWith("player-order-", StringComparison.Ordinal) && order.Id != aiOrderId) > 0;
|
||||
var changed = ship.OrderQueue.RemoveWhere(order => order.Id.StartsWith("player-order-", StringComparison.Ordinal) && order.Id != aiOrderId) > 0;
|
||||
|
||||
var useOrders = directive?.UseOrders ?? automation?.UseOrders ?? false;
|
||||
if (!useOrders || directive is null || string.IsNullOrWhiteSpace(directive.StagingOrderKind))
|
||||
@@ -1470,17 +1527,16 @@ internal sealed class PlayerFactionService
|
||||
KnownStationsOnly = directive.KnownStationsOnly,
|
||||
};
|
||||
|
||||
var existing = ship.OrderQueue.FirstOrDefault(order => order.Id == aiOrderId);
|
||||
var existing = ship.OrderQueue.FindById(aiOrderId!);
|
||||
if (existing is null)
|
||||
{
|
||||
ship.OrderQueue.Add(desiredOrder);
|
||||
ship.OrderQueue.AddOrReplaceManagedOrder(desiredOrder);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ShipOrdersEqual(existing, desiredOrder))
|
||||
{
|
||||
ship.OrderQueue.Remove(existing);
|
||||
ship.OrderQueue.Add(desiredOrder);
|
||||
ship.OrderQueue.AddOrReplaceManagedOrder(desiredOrder);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user