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; }