feat: massive AI generation

This commit is contained in:
2026-03-21 02:21:05 -04:00
parent 3b56785f9a
commit 6ccc708ae1
80 changed files with 16929 additions and 5427 deletions

View File

@@ -2,6 +2,7 @@ namespace SpaceGame.Api.Universe.Simulation;
public sealed class WorldGenerationOptions
{
public int TargetSystemCount { get; init; } = 160;
public int TargetSystemCount { get; init; }
public int AiControllerFactionCount { get; init; }
public bool GeneratePlayerFaction { get; init; }
}

View File

@@ -14,6 +14,7 @@ public sealed class WorldService(
private readonly OrbitalSimulationSnapshot _orbitalSimulation = new(orbitalSimulationOptions.Value.SimulatedSecondsPerRealSecond);
private readonly ScenarioLoader _loader = new(environment.ContentRootPath, worldGenerationOptions.Value);
private readonly SimulationEngine _engine = new(orbitalSimulationOptions.Value);
private readonly PlayerFactionService _playerFaction = new();
private readonly Dictionary<Guid, SubscriptionState> _subscribers = [];
private readonly Queue<WorldDelta> _history = [];
private SimulationWorld _world = new ScenarioLoader(environment.ContentRootPath, worldGenerationOptions.Value).Load();
@@ -74,6 +75,156 @@ public sealed class WorldService(
}
}
public ShipSnapshot? EnqueueShipOrder(string shipId, ShipOrderCommandRequest request)
{
lock (_sync)
{
var ship = _playerFaction.EnqueueDirectShipOrder(_world, shipId, request);
if (ship is null)
{
return null;
}
return GetShipSnapshotUnsafe(ship.Id);
}
}
public ShipSnapshot? RemoveShipOrder(string shipId, string orderId)
{
lock (_sync)
{
var ship = _playerFaction.RemoveDirectShipOrder(_world, shipId, orderId);
if (ship is null)
{
return null;
}
return GetShipSnapshotUnsafe(ship.Id);
}
}
public ShipSnapshot? UpdateShipDefaultBehavior(string shipId, ShipDefaultBehaviorCommandRequest request)
{
lock (_sync)
{
var ship = _playerFaction.ConfigureDirectShipBehavior(_world, shipId, request);
if (ship is null)
{
return null;
}
return GetShipSnapshotUnsafe(ship.Id);
}
}
public PlayerFactionSnapshot? GetPlayerFaction()
{
lock (_sync)
{
_playerFaction.EnsureDomain(_world);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? CreatePlayerOrganization(PlayerOrganizationCommandRequest request)
{
lock (_sync)
{
_playerFaction.CreateOrganization(_world, request);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? DeletePlayerOrganization(string organizationId)
{
lock (_sync)
{
_playerFaction.DeleteOrganization(_world, organizationId);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? UpdatePlayerOrganizationMembership(string organizationId, PlayerOrganizationMembershipCommandRequest request)
{
lock (_sync)
{
_playerFaction.UpdateOrganizationMembership(_world, organizationId, request);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? UpsertPlayerDirective(string? directiveId, PlayerDirectiveCommandRequest request)
{
lock (_sync)
{
_playerFaction.UpsertDirective(_world, directiveId, request);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? DeletePlayerDirective(string directiveId)
{
lock (_sync)
{
_playerFaction.DeleteDirective(_world, directiveId);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? UpsertPlayerPolicy(string? policyId, PlayerPolicyCommandRequest request)
{
lock (_sync)
{
_playerFaction.UpsertPolicy(_world, policyId, request);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? UpsertPlayerAutomationPolicy(string? automationPolicyId, PlayerAutomationPolicyCommandRequest request)
{
lock (_sync)
{
_playerFaction.UpsertAutomationPolicy(_world, automationPolicyId, request);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? UpsertPlayerReinforcementPolicy(string? reinforcementPolicyId, PlayerReinforcementPolicyCommandRequest request)
{
lock (_sync)
{
_playerFaction.UpsertReinforcementPolicy(_world, reinforcementPolicyId, request);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? UpsertPlayerProductionProgram(string? productionProgramId, PlayerProductionProgramCommandRequest request)
{
lock (_sync)
{
_playerFaction.UpsertProductionProgram(_world, productionProgramId, request);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? UpsertPlayerAssignment(string assetId, PlayerAssetAssignmentCommandRequest request)
{
lock (_sync)
{
_playerFaction.UpsertAssignment(_world, assetId, request);
return GetPlayerFactionSnapshotUnsafe();
}
}
public PlayerFactionSnapshot? UpdatePlayerStrategicIntent(PlayerStrategicIntentCommandRequest request)
{
lock (_sync)
{
_playerFaction.UpdateStrategicIntent(_world, request);
return GetPlayerFactionSnapshotUnsafe();
}
}
public ChannelReader<WorldDelta> Subscribe(ObserverScope scope, long afterSequence, CancellationToken cancellationToken)
{
var channel = Channel.CreateUnbounded<WorldDelta>(new UnboundedChannelOptions
@@ -158,7 +309,9 @@ public sealed class WorldService(
[],
[],
[],
[]);
[],
null,
null);
_history.Enqueue(resetDelta);
foreach (var subscriber in _subscribers.Values.ToList())
@@ -203,6 +356,12 @@ public sealed class WorldService(
};
}
private ShipSnapshot? GetShipSnapshotUnsafe(string shipId) =>
_engine.BuildSnapshot(_world, _sequence).Ships.FirstOrDefault(ship => ship.Id == shipId);
private PlayerFactionSnapshot? GetPlayerFactionSnapshotUnsafe() =>
_engine.BuildSnapshot(_world, _sequence).PlayerFaction;
private static bool HasMeaningfulDelta(WorldDelta delta) =>
delta.RequiresSnapshotRefresh
|| delta.Events.Count > 0
@@ -214,7 +373,9 @@ public sealed class WorldService(
|| delta.MarketOrders.Count > 0
|| delta.Policies.Count > 0
|| delta.Ships.Count > 0
|| delta.Factions.Count > 0;
|| delta.Factions.Count > 0
|| delta.PlayerFaction is not null
|| delta.Geopolitics is not null;
private void Unsubscribe(Guid subscriberId)
{
@@ -261,6 +422,8 @@ public sealed class WorldService(
Policies = string.Equals(scope.ScopeKind, "universe", StringComparison.OrdinalIgnoreCase) ? delta.Policies : [],
Ships = delta.Ships.Where((ship) => systemFilter is null || ship.SystemId == systemFilter).ToList(),
Factions = string.Equals(scope.ScopeKind, "universe", StringComparison.OrdinalIgnoreCase) ? delta.Factions : [],
PlayerFaction = string.Equals(scope.ScopeKind, "universe", StringComparison.OrdinalIgnoreCase) ? delta.PlayerFaction : null,
Geopolitics = string.Equals(scope.ScopeKind, "universe", StringComparison.OrdinalIgnoreCase) ? delta.Geopolitics : null,
Scope = scope,
};
}