acdream/src/AcDream.App/Update/UpdateFrameRuntimeAdapters.cs
Erik e91f310279 refactor(update): cut over the frame orchestrator
Reduce GameWindow.OnUpdate to one typed orchestration call and remove transitive window callbacks from teardown, liveness, teleport placement, live presentation, auto-entry, and entity packet routing. Preserve the frozen retail object/network order while making the production owner graph explicit and testable.
2026-07-22 03:31:38 +02:00

78 lines
2.5 KiB
C#

using AcDream.App.Input;
using AcDream.App.World;
using AcDream.Core.Vfx;
namespace AcDream.App.Update;
/// <summary>Bridges canonical live-entity teardown into the host frame.</summary>
internal sealed class LiveEntityTeardownFramePhase : IUpdateFrameTeardownPhase
{
private readonly LiveEntityRuntime _runtime;
public LiveEntityTeardownFramePhase(LiveEntityRuntime runtime) =>
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
public void RetryPendingTeardowns() => _runtime.RetryPendingTeardowns();
}
internal sealed class ConsoleUpdateFrameFailureSink : IUpdateFrameFailureSink
{
public void ReportTeardownFailure(AggregateException error) =>
Console.Error.WriteLine($"[live-entity-teardown] {error}");
}
/// <summary>Publishes the frame clock to the retail PhysicsScript owner.</summary>
internal sealed class PhysicsScriptClockPublisher : IUpdateFrameScriptClockPublisher
{
private readonly PhysicsScriptRunner _runner;
public PhysicsScriptClockPublisher(PhysicsScriptRunner runner) =>
_runner = runner ?? throw new ArgumentNullException(nameof(runner));
public void PublishTime(double scriptTime) => _runner.PublishTime(scriptTime);
}
internal interface IClientMonotonicTimeSource
{
double Now { get; }
}
internal sealed class StopwatchClientMonotonicTimeSource
: IClientMonotonicTimeSource
{
public double Now =>
System.Diagnostics.Stopwatch.GetTimestamp()
/ (double)System.Diagnostics.Stopwatch.Frequency;
}
/// <summary>
/// Supplies the absolute client timer to liveness independently of the
/// normalized simulation delta.
/// </summary>
internal sealed class LiveEntityLivenessFramePhase
: ILiveEntityLivenessFramePhase
{
private readonly LiveEntityLivenessController _liveness;
private readonly IClientMonotonicTimeSource _clock;
public LiveEntityLivenessFramePhase(
LiveEntityLivenessController liveness,
IClientMonotonicTimeSource clock)
{
_liveness = liveness ?? throw new ArgumentNullException(nameof(liveness));
_clock = clock ?? throw new ArgumentNullException(nameof(clock));
}
public void Tick() => _liveness.Tick(_clock.Now);
}
internal sealed class PlayerModeAutoEntryFramePhase
: IPlayerModeAutoEntryFramePhase
{
private readonly PlayerModeAutoEntry _autoEntry;
public PlayerModeAutoEntryFramePhase(PlayerModeAutoEntry autoEntry) =>
_autoEntry = autoEntry ?? throw new ArgumentNullException(nameof(autoEntry));
public void TryEnter() => _autoEntry.TryEnter();
}