Harden movie playback lifecycle and diagnostics

This commit is contained in:
gamer147
2026-07-22 09:44:57 -04:00
parent 5b66cb2cd2
commit 740e10c550
25 changed files with 1145 additions and 147 deletions

View File

@@ -8,9 +8,13 @@ using Age.Engine.Diagnostics;
// engine fact delivered over the trace seam.
public sealed class GodotTraceSink : ITraceSink
{
private const int RecentStepCapacity = 128;
private readonly GodotTimelineLog? _timeline;
private readonly PageLocatorState _locator;
private readonly object _snapshotLock = new();
private readonly Stack<string> _scripts = new();
private readonly Queue<GodotTraceStepSnapshot> _recentSteps = new();
private GodotTraceStepSnapshot? _latestStep;
public GodotTraceSink(PageLocatorState locator, GodotTimelineLog? timeline = null)
{ _locator = locator; _timeline = timeline; }
// The page locator needs the exact script/offset even when the heavier timeline log is disabled.
@@ -28,8 +32,13 @@ public sealed class GodotTraceSink : ITraceSink
}
if (e.Kind == TraceEventKind.FrameEnter && e.Name != null)
{
_scripts.Push(e.Name);
PublishCallStack();
string[] callStack;
lock (_snapshotLock)
{
_scripts.Push(e.Name);
callStack = CurrentCallStackLocked();
}
_locator.CallStack(callStack);
_timeline?.Event("frame-enter", new()
{
["name"] = e.Name, ["depth"] = e.Depth,
@@ -42,12 +51,25 @@ public sealed class GodotTraceSink : ITraceSink
{
["name"] = e.Name, ["depth"] = e.Depth, ["outcome"] = e.Text,
});
_scripts.Pop();
PublishCallStack();
string[] callStack;
lock (_snapshotLock)
{
if (_scripts.Count > 0) _scripts.Pop();
callStack = CurrentCallStackLocked();
}
_locator.CallStack(callStack);
}
else if (e.Kind == TraceEventKind.Step && e.Ins != null)
{
string script = _scripts.Count > 0 ? _scripts.Peek() : "<unknown>";
string script;
lock (_snapshotLock)
{
script = _scripts.Count > 0 ? _scripts.Peek() : "<unknown>";
if (_recentSteps.Count == RecentStepCapacity) _recentSteps.Dequeue();
var step = new GodotTraceStepSnapshot(script, e.Ins.Offset, e.Opcode, e.Depth);
_latestStep = step;
_recentSteps.Enqueue(step);
}
_locator.Step(script, e.Ins.Offset);
_timeline?.Step(script, e.Ins.Offset, e.Opcode, e.Depth);
}
@@ -60,10 +82,31 @@ public sealed class GodotTraceSink : ITraceSink
_timeline?.State("halted", new() { ["reason"] = e.Text, ["steps"] = e.Steps });
}
private void PublishCallStack()
public GodotTraceSnapshot Snapshot()
{
lock (_snapshotLock)
{
GodotTraceStepSnapshot? current = _latestStep;
return new GodotTraceSnapshot(
current?.Script ?? (_scripts.Count > 0 ? _scripts.Peek() : "<unknown>"),
current?.Offset ?? -1,
current?.Opcode ?? -1,
current?.Depth ?? System.Math.Max(0, _scripts.Count - 1),
CurrentCallStackLocked(),
_recentSteps.ToArray());
}
}
private string[] CurrentCallStackLocked()
{
var stack = _scripts.ToArray();
System.Array.Reverse(stack);
_locator.CallStack(stack);
return stack;
}
}
public sealed record GodotTraceStepSnapshot(string Script, int Offset, int Opcode, int Depth);
public sealed record GodotTraceSnapshot(string CurrentScript, int CurrentOffset, int CurrentOpcode,
int CurrentDepth, IReadOnlyList<string> CallStack,
IReadOnlyList<GodotTraceStepSnapshot> RecentSteps);