using AcDream.App.Update;
using AcDream.Runtime;
namespace AcDream.App.Input;
///
/// Owns the local player's once-per-frame retail object phase.
///
///
/// Retail advances the player and sends input-originated movement/jump output
/// before SmartBox::UseTime drains inbound events. Its later
/// CommandInterpreter::UseTime position check uses current post-inbound
/// state. The cached input result is presentation-only after the barrier: its
/// one-shot commands are never replayed against a later authoritative cell.
///
internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFramePhase
{
private readonly RuntimeLocalPlayerFrameController _runtime;
public readonly record struct PresentationFrame(
MovementResult Movement,
bool Hidden,
bool AdvancedBeforeNetwork);
///
/// Whether the pre-network Hidden player update admitted a complete object
/// quantum whose retained CPartArray pose must be sampled this frame.
///
internal bool HiddenPartPoseDirty =>
_runtime.HiddenPartPoseDirty;
public RetailLocalPlayerFrameController(
ILocalPlayerFrameRuntime runtime,
IMovementInputSource movementInput)
{
_runtime = new RuntimeLocalPlayerFrameController(
runtime ?? throw new ArgumentNullException(nameof(runtime)),
movementInput
?? throw new ArgumentNullException(nameof(movementInput)));
}
public RetailLocalPlayerFrameController(
GameRuntime gameRuntime,
ILocalPlayerFrameRuntime runtime,
IMovementInputSource movementInput)
{
ArgumentNullException.ThrowIfNull(gameRuntime);
_runtime = gameRuntime.CreateLocalPlayerFrameController(
runtime ?? throw new ArgumentNullException(nameof(runtime)),
movementInput
?? throw new ArgumentNullException(nameof(movementInput)));
}
///
/// Advances the existing local object exactly once on the object side of
/// the inbound-network barrier.
///
public void AdvanceBeforeNetwork(float deltaSeconds)
=> _runtime.AdvanceBeforeNetwork(deltaSeconds);
///
/// Runs retail's post-inbound command-interpreter phase. The split
/// controller/render projection is reconciled without advancing physics,
/// then AutonomousPosition is evaluated from that current state.
///
public void RunPostNetworkCommandPhase()
=> _runtime.RunPostNetworkCommandPhase();
///
/// Produces the post-network presentation sample without advancing
/// physics. An owner first created by the inbound pass is seeded from its
/// current state and receives its first real object tick next frame.
///
public bool TryGetPresentationAfterNetwork(out PresentationFrame frame)
{
bool available = _runtime.TryGetPresentationAfterNetwork(
out AcDream.Runtime.Gameplay.RuntimeLocalPlayerPresentationFrame
shared);
frame = available
? new PresentationFrame(
shared.Movement,
shared.Hidden,
shared.AdvancedBeforeNetwork)
: default;
return available;
}
}