namespace SpaceGame.Api.Simulation.Core; public sealed class SimulationEngine { private readonly OrbitalSimulationOptions _orbitalSimulation; private readonly OrbitalStateUpdater _orbitalStateUpdater; private readonly InfrastructureSimulationService _infrastructureSimulation; private readonly CommanderPlanningService _commanderPlanning; private readonly StationSimulationService _stationSimulation; private readonly StationLifecycleService _stationLifecycle; private readonly ShipControlService _shipControl; private readonly ShipTaskExecutionService _shipTaskExecution; private readonly SimulationProjectionService _projection; public SimulationEngine(OrbitalSimulationOptions? orbitalSimulation = null) { _orbitalSimulation = orbitalSimulation ?? new OrbitalSimulationOptions(); _orbitalStateUpdater = new OrbitalStateUpdater(_orbitalSimulation); _infrastructureSimulation = new InfrastructureSimulationService(); _commanderPlanning = new CommanderPlanningService(); _stationSimulation = new StationSimulationService(); _stationLifecycle = new StationLifecycleService(_stationSimulation); _shipControl = new ShipControlService(); _shipTaskExecution = new ShipTaskExecutionService(); _projection = new SimulationProjectionService(_orbitalSimulation); } public WorldDelta Tick(SimulationWorld world, float deltaSeconds, long sequence) { var nowUtc = DateTimeOffset.UtcNow; var events = new List(); world.OrbitalTimeSeconds += deltaSeconds * _orbitalSimulation.SimulatedSecondsPerRealSecond; _orbitalStateUpdater.Update(world); _infrastructureSimulation.UpdateClaims(world, events); _infrastructureSimulation.UpdateConstructionSites(world, events); _commanderPlanning.UpdateCommanders(this, world, deltaSeconds, events); _stationLifecycle.UpdateStations(world, deltaSeconds, events); foreach (var ship in world.Ships) { var previousPosition = ship.Position; var previousState = ship.State; var previousBehavior = ship.DefaultBehavior.Kind; var previousTask = ship.ControllerTask.Kind; _shipControl.RefreshControlLayers(ship, world); _shipControl.PlanControllerTask(this, ship, world); var controllerEvent = _shipTaskExecution.UpdateControllerTask(ship, world, deltaSeconds); _shipControl.AdvanceControlState(this, ship, world, controllerEvent); ship.Velocity = ship.Position.Subtract(previousPosition).Divide(deltaSeconds); _shipControl.TrackHistory(ship, controllerEvent); _shipControl.EmitShipStateEvents(ship, previousState, previousBehavior, previousTask, controllerEvent, events); } _orbitalStateUpdater.SyncSpatialState(world); world.GeneratedAtUtc = nowUtc; return _projection.BuildDelta(world, sequence, events); } public WorldSnapshot BuildSnapshot(SimulationWorld world, long sequence) => _projection.BuildSnapshot(world, sequence); public void PrimeDeltaBaseline(SimulationWorld world) => _projection.PrimeDeltaBaseline(world); internal void PlanResourceHarvest(ShipRuntime ship, SimulationWorld world, string resourceItemId, string requiredModule) => _shipControl.PlanResourceHarvest(ship, world, resourceItemId, requiredModule); internal void PlanStationConstruction(ShipRuntime ship, SimulationWorld world) => _shipControl.PlanStationConstruction(ship, world); internal static float GetShipCargoAmount(ShipRuntime ship) => SimulationRuntimeSupport.GetShipCargoAmount(ship); }