using AcDream.App.Update; using AcDream.Runtime.Session; using AcDream.App.Input; using AcDream.App.Net; using AcDream.App.Streaming; 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. /// internal sealed class RetailLiveFrameCoordinator : IRetailLiveFramePhase { private readonly ILiveObjectFramePhase _objects; private readonly GpuWorldState _worldState; private readonly IRuntimeLiveSessionFramePhase _session; private readonly IPostNetworkCommandFramePhase _localPlayer; private readonly ILiveSpatialReconcilePhase _spatialReconciler; private readonly IWorldGenerationAvailability _availability; private readonly IRenderProjectionSyncPhase? _renderProjectionSync; public RetailLiveFrameCoordinator( ILiveObjectFramePhase objects, GpuWorldState worldState, IRuntimeLiveSessionFramePhase session, IPostNetworkCommandFramePhase localPlayer, ILiveSpatialReconcilePhase spatialReconciler, IWorldGenerationAvailability? availability = null, IRenderProjectionSyncPhase? renderProjectionSync = null) { _objects = objects ?? throw new ArgumentNullException(nameof(objects)); _worldState = worldState ?? throw new ArgumentNullException(nameof(worldState)); _session = session ?? throw new ArgumentNullException(nameof(session)); _localPlayer = localPlayer ?? throw new ArgumentNullException(nameof(localPlayer)); _spatialReconciler = spatialReconciler ?? throw new ArgumentNullException(nameof(spatialReconciler)); _availability = availability ?? AlwaysAvailableWorldGeneration.Instance; _renderProjectionSync = renderProjectionSync; } public void Tick(float deltaSeconds) { float frameDelta = (float)NormalizeDeltaSeconds(deltaSeconds); if (_availability.IsWorldAvailable) _objects.Tick(frameDelta); using (_worldState.BeginMutationBatch()) _session.Tick(); _localPlayer.RunPostNetworkCommandPhase(); if (_availability.IsWorldAvailable) _spatialReconciler.Reconcile(); else _renderProjectionSync?.SynchronizeActiveSources(); } public static double NormalizeDeltaSeconds(double deltaSeconds) => UpdateFrameClock.NormalizeDeltaSeconds(deltaSeconds); }