Implement ADV foreground transition lifecycle

This commit is contained in:
gamer147
2026-07-10 18:49:53 -04:00
parent bb16a5496a
commit 7f900c8fc6
16 changed files with 543 additions and 54 deletions

View File

@@ -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()
{