Match retail's update ordering so object animation, particles, and scripts advance before inbound teleport state is applied. Separate input-originated movement from post-network autonomous position output, and reconcile presentation without a second physics tick so recall cannot resume after arrival. Co-authored-by: OpenAI Codex <codex@openai.com>
53 lines
2.1 KiB
C#
53 lines
2.1 KiB
C#
namespace AcDream.App.World;
|
|
|
|
/// <summary>
|
|
/// Owns retail's live-object, inbound-dispatch, and command-interpreter frame
|
|
/// phases.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Retail <c>SmartBox::UseTime</c> (<c>0x00455410</c>) advances
|
|
/// <c>CObjectMaint::UseTime</c> and <c>CPhysics::UseTime</c> before draining
|
|
/// <c>SmartBox::in_queue</c>, then calls <c>CommandInterpreter::UseTime</c>.
|
|
/// 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.
|
|
/// </remarks>
|
|
public sealed class RetailLiveFrameCoordinator
|
|
{
|
|
private readonly Action<float> _advanceObjectRuntime;
|
|
private readonly Action _dispatchInboundNetwork;
|
|
private readonly Action _runPostNetworkCommands;
|
|
private readonly Action _reconcileSpatialPresentation;
|
|
|
|
public RetailLiveFrameCoordinator(
|
|
Action<float> 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;
|
|
}
|