Clear ADV History presentation on exit

This commit is contained in:
gamer147
2026-07-19 11:32:36 -04:00
parent 792d37ccfe
commit eee9022cfb
7 changed files with 46 additions and 3 deletions

View File

@@ -1393,6 +1393,12 @@ Label and independently animated wait marker. Native rendering gets this layerin
part of retained composition; the port must state it explicitly because those two elements are separate
Godot overlays. They reappear with the same parked page after the modal frame returns.
History's target-layout render batches are likewise presentation bindings, not part of the retained backlog.
`HISTORY.BIN@0x1100` re-enables recording with op `0x1bb(1)` after erasing its object range and releasing
surfaces `0xc0/0xc1`; that existing exit boundary now tells the host to discard all bound History batches.
The semantic text/index records remain untouched, so reopening History rebuilds fresh rows while exiting
cannot leave the old labels above the resumed ADV page.
History's remaining work is stored voice replay through `0x1bd` and the `0xd3/0xd4/0xd5` smooth-scroll
callback scheduler. None changes backlog ownership or requires choosing a save/profile backend.

View File

@@ -1801,6 +1801,12 @@ class of inherited-state bridges.
Godot also suppresses the parked page's ordinary dialogue Label and wait indicator while any nested timed
raw-input frame owns the modal screen, then restores them on return. Root Control anchor presets are now
applied after parenting, removing the remaining occurrence of the associated runtime layout diagnostic.
A follow-up exit check found that the host retained the last History render batches after the script had
erased its objects and re-enabled recording. Op `0x1bb(1)` at `HISTORY.BIN@0x1100` is now the presentation
end boundary: it clears only the host's transient layout bindings, leaving the engine-owned backlog intact
for the next opening. The real interaction regression requires zero active History batches after return.
Validation: engine 198/198, zero-warning Godot build, threaded `SELFTEST OK`, and vm0 RECOVER clean.
**Next:** manually recheck the five History rows and overlay cleanup against the original. If they match, proceed

View File

@@ -167,6 +167,8 @@ public class HistoryInteractionOpsTests
Assert.True(host.SawRenderedText);
Assert.True(host.HistoryReturned);
Assert.Equal(1, host.Waits); // the enclosing ADV page was never released or re-entered
Assert.Equal(1, host.HistoryPresentationEnds);
Assert.Empty(host.ActiveHistoryRenders);
var historyButtons = host.FirstHistoryFrame
.Where(render => render.Handle >= 0xd2fa && render.Handle <= 0xd300)

View File

@@ -18,6 +18,8 @@ internal class RecordingHost : IHost
public readonly List<(int Slot, int X, int Y)> TextCursors = new();
public readonly List<(int Surface, int X, int Y, string Text)> SurfaceStrings = new();
public readonly List<AdvTextHistoryRenderBatch> HistoryRenders = new();
public readonly Dictionary<int, AdvTextHistoryRenderBatch> ActiveHistoryRenders = new();
public int HistoryPresentationEnds;
public readonly List<int> ClearedTextLayouts = new();
public readonly List<SurfaceRectFill> SurfaceFills = new();
public readonly List<(long First, long Count)> PresentedRanges = new();
@@ -38,8 +40,21 @@ internal class RecordingHost : IHost
=> SurfaceStrings.Add((surfaceSlot, x, y, text));
public void DrawStringToSurface(int surfaceSlot, int x, int y, string text, AdvTextStyle style)
=> SurfaceStrings.Add((surfaceSlot, x, y, text));
public void ClearRenderedAdvTextLayout(int layoutSlot) => ClearedTextLayouts.Add(layoutSlot);
public void RenderTextHistory(AdvTextHistoryRenderBatch batch) => HistoryRenders.Add(batch);
public void ClearRenderedAdvTextLayout(int layoutSlot)
{
ClearedTextLayouts.Add(layoutSlot);
ActiveHistoryRenders.Remove(layoutSlot);
}
public void RenderTextHistory(AdvTextHistoryRenderBatch batch)
{
HistoryRenders.Add(batch);
ActiveHistoryRenders[batch.LayoutSlot] = batch;
}
public void EndTextHistoryPresentation()
{
HistoryPresentationEnds++;
ActiveHistoryRenders.Clear();
}
public int MessageWindowAlphaSetting { get; set; }
public void FillSurfaceRect(SurfaceRectFill fill) => SurfaceFills.Add(fill);
public void PresentObjectRange(GfxState gfx, long firstHandle, long count)

View File

@@ -24,6 +24,9 @@ public interface IHost
=> DrawStringToSurface(surfaceSlot, x, y, text);
void ClearRenderedAdvTextLayout(int layoutSlot) { }
void RenderTextHistory(AdvTextHistoryRenderBatch batch) { }
// History render batches are transient bindings, unlike the retained backlog itself. HISTORY.BIN's
// recording re-enable at exit ends that presentation and drops every bound target layout.
void EndTextHistoryPresentation() { }
int MessageWindowAlphaSetting => 0;
void FillSurfaceRect(SurfaceRectFill fill) { }
void PresentObjectRange(GfxState gfx, long firstHandle, long count) { }

View File

@@ -772,7 +772,12 @@ public sealed class VirtualMachine
case "reset-message-voice-state": // 0x1bc resets native per-message voice/queued-voice state
_autoVoicePending = false; return pc + 1;
case "set-text-history-recording": // 0x1bb: HISTORY.BIN suppresses recording its own UI
if (Read(a[0]) is 0 or 1) TextHistory.SetRecordingEnabled(Read(a[0]) == 1);
if (Read(a[0]) is 0 or 1)
{
bool enabled = Read(a[0]) == 1;
TextHistory.SetRecordingEnabled(enabled);
if (enabled) _host.EndTextHistoryPresentation();
}
return pc + 1;
case "append-text-history-metadata": // 0x1d2: typed value attached to the current group
TextHistory.AppendMetadata(Read(a[0]), Read(a[1]), _advTextStyle); return pc + 1;

View File

@@ -149,6 +149,12 @@ public sealed class GodotAdvHost : IHost
});
}
public void EndTextHistoryPresentation()
{
lock (_textLock) _historyText.Clear();
_timeline?.Event("history-presentation-end");
}
public IReadOnlyList<AdvTextHistoryRenderBatch> SnapshotRenderedTextHistory()
{
lock (_textLock) return _historyText.Values.OrderBy(batch => batch.LayoutSlot).ToArray();