103 lines
3.9 KiB
C#
103 lines
3.9 KiB
C#
using SpaceGame.Simulation.Api.Contracts;
|
|
|
|
namespace SpaceGame.Simulation.Api.Simulation;
|
|
|
|
public sealed partial class SimulationEngine
|
|
{
|
|
private readonly OrbitalSimulationOptions _orbitalSimulation;
|
|
private const float WaterConsumptionPerWorkerPerSecond = 0.004f;
|
|
private const float PopulationGrowthPerSecond = 0.012f;
|
|
private const float PopulationAttritionPerSecond = 0.018f;
|
|
private static readonly ShipBehaviorStateMachine _shipBehaviorStateMachine = ShipBehaviorStateMachine.CreateDefault();
|
|
private static readonly IReadOnlyList<WorldUpdateStep> _worldUpdatePipeline =
|
|
[
|
|
new((engine, world, deltaSeconds, nowUtc, events) => engine.UpdateOrbitalState(world)),
|
|
new((engine, world, deltaSeconds, nowUtc, events) => UpdateClaims(world, events)),
|
|
new((engine, world, deltaSeconds, nowUtc, events) => UpdateConstructionSites(world, events)),
|
|
new((engine, world, deltaSeconds, nowUtc, events) => engine.UpdateCommanders(world, deltaSeconds, events)),
|
|
new((engine, world, deltaSeconds, nowUtc, events) => engine.UpdateStations(world, deltaSeconds, events)),
|
|
];
|
|
private static readonly IReadOnlyList<ShipUpdateStep> _shipUpdatePipeline =
|
|
[
|
|
new((engine, ship, world, deltaSeconds, events) => engine.RefreshControlLayers(ship, world)),
|
|
new((engine, ship, world, deltaSeconds, events) => engine.PlanControllerTask(ship, world)),
|
|
];
|
|
|
|
public SimulationEngine(OrbitalSimulationOptions? orbitalSimulation = null)
|
|
{
|
|
_orbitalSimulation = orbitalSimulation ?? new OrbitalSimulationOptions();
|
|
}
|
|
|
|
public WorldDelta Tick(SimulationWorld world, float deltaSeconds, long sequence)
|
|
{
|
|
var events = new List<SimulationEventRecord>();
|
|
var nowUtc = DateTimeOffset.UtcNow;
|
|
world.OrbitalTimeSeconds += deltaSeconds * _orbitalSimulation.SimulatedSecondsPerRealSecond;
|
|
|
|
foreach (var step in _worldUpdatePipeline)
|
|
{
|
|
step.Execute(this, world, deltaSeconds, nowUtc, 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;
|
|
|
|
foreach (var step in _shipUpdatePipeline)
|
|
{
|
|
step.Execute(this, ship, world, deltaSeconds, events);
|
|
}
|
|
|
|
var controllerEvent = UpdateControllerTask(ship, world, deltaSeconds);
|
|
AdvanceControlState(ship, world, controllerEvent);
|
|
ship.Velocity = ship.Position.Subtract(previousPosition).Divide(deltaSeconds);
|
|
TrackHistory(ship, controllerEvent);
|
|
|
|
EmitShipStateEvents(ship, previousState, previousBehavior, previousTask, controllerEvent, events);
|
|
}
|
|
|
|
SyncSpatialState(world);
|
|
world.GeneratedAtUtc = nowUtc;
|
|
|
|
return new WorldDelta(
|
|
sequence,
|
|
world.TickIntervalMs,
|
|
world.OrbitalTimeSeconds,
|
|
new OrbitalSimulationSnapshot(_orbitalSimulation.SimulatedSecondsPerRealSecond),
|
|
world.GeneratedAtUtc,
|
|
false,
|
|
events,
|
|
BuildSpatialNodeDeltas(world),
|
|
BuildLocalBubbleDeltas(world),
|
|
BuildNodeDeltas(world),
|
|
BuildStationDeltas(world),
|
|
BuildClaimDeltas(world),
|
|
BuildConstructionSiteDeltas(world),
|
|
BuildMarketOrderDeltas(world),
|
|
BuildPolicyDeltas(world),
|
|
BuildShipDeltas(world),
|
|
BuildFactionDeltas(world));
|
|
}
|
|
|
|
private delegate void WorldUpdateStepAction(
|
|
SimulationEngine engine,
|
|
SimulationWorld world,
|
|
float deltaSeconds,
|
|
DateTimeOffset nowUtc,
|
|
List<SimulationEventRecord> events);
|
|
|
|
private delegate void ShipUpdateStepAction(
|
|
SimulationEngine engine,
|
|
ShipRuntime ship,
|
|
SimulationWorld world,
|
|
float deltaSeconds,
|
|
List<SimulationEventRecord> events);
|
|
|
|
private sealed record WorldUpdateStep(WorldUpdateStepAction Execute);
|
|
|
|
private sealed record ShipUpdateStep(ShipUpdateStepAction Execute);
|
|
}
|