87 lines
3.3 KiB
C#
87 lines
3.3 KiB
C#
using AcDream.App.Update;
|
|
using AcDream.Runtime;
|
|
|
|
namespace AcDream.App.Input;
|
|
|
|
/// <summary>
|
|
/// Owns the local player's once-per-frame retail object phase.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Retail advances the player and sends input-originated movement/jump output
|
|
/// before <c>SmartBox::UseTime</c> drains inbound events. Its later
|
|
/// <c>CommandInterpreter::UseTime</c> 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.
|
|
/// </remarks>
|
|
internal sealed class RetailLocalPlayerFrameController : IPostNetworkCommandFramePhase
|
|
{
|
|
private readonly RuntimeLocalPlayerFrameController _runtime;
|
|
|
|
public readonly record struct PresentationFrame(
|
|
MovementResult Movement,
|
|
bool Hidden,
|
|
bool AdvancedBeforeNetwork);
|
|
|
|
/// <summary>
|
|
/// Whether the pre-network Hidden player update admitted a complete object
|
|
/// quantum whose retained CPartArray pose must be sampled this frame.
|
|
/// </summary>
|
|
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)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Advances the existing local object exactly once on the object side of
|
|
/// the inbound-network barrier.
|
|
/// </summary>
|
|
public void AdvanceBeforeNetwork(float deltaSeconds)
|
|
=> _runtime.AdvanceBeforeNetwork(deltaSeconds);
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public void RunPostNetworkCommandPhase()
|
|
=> _runtime.RunPostNetworkCommandPhase();
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|