Implement ADV foreground transition lifecycle
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Age.Engine.Hosting;
|
||||
using Age.Engine.Model;
|
||||
using Age.Engine.Sys4;
|
||||
|
||||
public sealed class GodotAdvHost : IHost
|
||||
@@ -18,7 +19,11 @@ public sealed class GodotAdvHost : IHost
|
||||
private readonly GodotTimelineLog? _timeline;
|
||||
private readonly System.Threading.AutoResetEvent _frameSignal = new(false);
|
||||
private volatile bool _stopping;
|
||||
private GfxState? _foregroundGfx;
|
||||
public volatile bool IsWaiting;
|
||||
public volatile bool IsTransitionWaiting;
|
||||
private long _transitionStartedAtMs = -1;
|
||||
public long TransitionStartedAtMs => System.Threading.Interlocked.Read(ref _transitionStartedAtMs);
|
||||
public readonly List<(int Offset, string Text)> Captured = new();
|
||||
|
||||
public GodotAdvHost(Main main, ResourceMap res, string scene, Age.Engine.Hosting.FrameClock clock,
|
||||
@@ -50,8 +55,64 @@ public sealed class GodotAdvHost : IHost
|
||||
_main.CallDeferred("ClearPage");
|
||||
}
|
||||
|
||||
// called from the main thread (click) or the selftest auto-clicker
|
||||
public void SignalInput() { if (IsWaiting && _gate.CurrentCount == 0) _gate.Release(); }
|
||||
// Called from the main thread (click) or an auto-clicker. A transition click is consumed by
|
||||
// the foreground lifecycle; it never pre-arms or advances the following stable input wait.
|
||||
public void SignalInput()
|
||||
{
|
||||
if (IsTransitionWaiting && _foregroundGfx != null)
|
||||
{
|
||||
int completed = _foregroundGfx.CompleteForegroundTransitions(_clock.NowMs);
|
||||
if (completed > 0)
|
||||
{
|
||||
_timeline?.State("transition-forced-complete", new() { ["count"] = completed });
|
||||
_frameSignal.Set();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (IsWaiting && _gate.CurrentCount == 0) _gate.Release();
|
||||
}
|
||||
|
||||
public void WaitForForegroundTransition(GfxState gfx)
|
||||
{
|
||||
int started = gfx.StartForegroundTransitions(_clock.NowMs);
|
||||
if (started == 0 && !gfx.HasActiveForegroundTransitions(_clock.NowMs)) return;
|
||||
_foregroundGfx = gfx;
|
||||
System.Threading.Interlocked.Exchange(ref _transitionStartedAtMs, _clock.NowMs);
|
||||
IsTransitionWaiting = true;
|
||||
_timeline?.State("transition-start", new() { ["count"] = started });
|
||||
int lastBucket = -1;
|
||||
while (gfx.HasActiveForegroundTransitions(_clock.NowMs) && !_stopping)
|
||||
{
|
||||
var active = gfx.SnapshotForegroundTransitions(_clock.NowMs);
|
||||
int bucket = active.Count == 0 ? 100 : (int)System.Math.Floor(active[0].Progress * 10);
|
||||
if (bucket != lastBucket)
|
||||
{
|
||||
lastBucket = bucket;
|
||||
_timeline?.State("transition-progress", new()
|
||||
{
|
||||
["progress"] = active.Count == 0 ? 1.0 : active[0].Progress,
|
||||
["forced"] = active.Count != 0 && active[0].Forced,
|
||||
});
|
||||
}
|
||||
_frameSignal.WaitOne(50);
|
||||
}
|
||||
IsTransitionWaiting = false;
|
||||
System.Threading.Interlocked.Exchange(ref _transitionStartedAtMs, -1);
|
||||
_foregroundGfx = null;
|
||||
_opPacer.Reset();
|
||||
_timeline?.State("running", new() { ["transition_complete"] = true });
|
||||
}
|
||||
|
||||
public void PresentFrame(GfxState gfx)
|
||||
{
|
||||
int started = gfx.StartForegroundTransitions(_clock.NowMs);
|
||||
int completed = gfx.CompleteForegroundTransitions(_clock.NowMs);
|
||||
if (started > 0 || completed > 0)
|
||||
_timeline?.State("transition-skip-complete", new()
|
||||
{
|
||||
["started"] = started, ["completed"] = completed,
|
||||
});
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user