namespace AcDream.App.World;
///
/// Owns retail's live-object, inbound-dispatch, and command-interpreter frame
/// phases.
///
///
/// Retail SmartBox::UseTime (0x00455410) advances
/// CObjectMaint::UseTime and CPhysics::UseTime before draining
/// SmartBox::in_queue, then calls CommandInterpreter::UseTime.
/// Keeping both boundaries explicit prevents an inbound Hidden transition
/// from freezing an action due to complete this frame while ensuring the
/// periodic AutonomousPosition check observes accepted inbound state.
///
public sealed class RetailLiveFrameCoordinator
{
private readonly Action _advanceObjectRuntime;
private readonly Action _dispatchInboundNetwork;
private readonly Action _runPostNetworkCommands;
private readonly Action _reconcileSpatialPresentation;
public RetailLiveFrameCoordinator(
Action advanceObjectRuntime,
Action dispatchInboundNetwork,
Action runPostNetworkCommands,
Action reconcileSpatialPresentation)
{
_advanceObjectRuntime = advanceObjectRuntime
?? throw new ArgumentNullException(nameof(advanceObjectRuntime));
_dispatchInboundNetwork = dispatchInboundNetwork
?? throw new ArgumentNullException(nameof(dispatchInboundNetwork));
_runPostNetworkCommands = runPostNetworkCommands
?? throw new ArgumentNullException(nameof(runPostNetworkCommands));
_reconcileSpatialPresentation = reconcileSpatialPresentation
?? throw new ArgumentNullException(nameof(reconcileSpatialPresentation));
}
public void Tick(float deltaSeconds)
{
float frameDelta = (float)NormalizeDeltaSeconds(deltaSeconds);
_advanceObjectRuntime(frameDelta);
_dispatchInboundNetwork();
_runPostNetworkCommands();
_reconcileSpatialPresentation();
}
public static double NormalizeDeltaSeconds(double deltaSeconds) =>
double.IsFinite(deltaSeconds)
&& deltaSeconds > 0.0
&& deltaSeconds <= float.MaxValue
? deltaSeconds
: 0.0;
}