Extract VM text history opcode handler
This commit is contained in:
@@ -190,6 +190,8 @@ publication, skip-aware blocking fades/crossfades, foreground-transition waits,
|
||||
`engine/Age.Engine/Vm/VirtualMachine.AdvText.cs` owns live ADV text emission, layout/cursor/wait-indicator state,
|
||||
text style and glyph-delay control, direct surface-string and retained numeric-glyph rendering, and retained
|
||||
text/wait-object bindings; text history and input/skip/auto services remain separate.
|
||||
`engine/Age.Engine/Vm/VirtualMachine.TextHistory.cs` owns history recording control, metadata append/navigation,
|
||||
retained history rendering, metadata/voice lookup, and history backlog clearing.
|
||||
|
||||
The disposable `build/page-map-<SCENE>.jsonl` files are produced by editor/development Godot runs and map
|
||||
runtime ADV page ordinals to their authoritative script offsets for `tools/locate_page.py`. Packaged exports
|
||||
|
||||
@@ -668,6 +668,12 @@ do not mix mechanical moves with semantic changes.
|
||||
`StepAdvText`; the complete instruction remains available for emission and layout-reset bytecode offsets.
|
||||
Text-history and input/skip/auto services remain outside the handler. Runtime validation remains green.
|
||||
|
||||
The eighth bounded `VirtualMachine.Step` extraction moved text-history recording control, metadata append and
|
||||
navigation, retained history rendering, metadata/voice lookup, and backlog clearing into
|
||||
`engine/Age.Engine/Vm/VirtualMachine.TextHistory.cs`. The top-level dispatcher retains all labels and aliases
|
||||
at their existing positions and routes them through guarded `StepTextHistory`; live ADV text remains with
|
||||
`StepAdvText`, while skip/auto-message services remain outside both handlers. Runtime validation remains green.
|
||||
|
||||
**Gate:** no externally visible behavior or command changes; generated artifacts are byte-identical where
|
||||
deterministic, and the corresponding engine, Python, Godot, and corpus validations remain green after
|
||||
each domain move.
|
||||
@@ -1039,9 +1045,9 @@ layer's rendering diverges from ADV; save layout.
|
||||
## 8. Immediate next step
|
||||
Continue step 2 of the **codebase consolidation** maintenance slice: behavior-neutral physical splits backed
|
||||
by the tracked launcher and layered validation driver. With the planned `Main`, `GodotAdvHost`, and `GfxState`
|
||||
domains isolated and the audio, movie, surface/texture, retained-object, and animation `VirtualMachine.Step`
|
||||
families routed through domain handlers, with retained presentation/transition dispatch now isolated as well,
|
||||
and ADV text-layout/rendering dispatch isolated, extract the ADV text-history opcode family next without
|
||||
replacing the proven dispatcher or changing public types, commands, and generated output.
|
||||
domains isolated and the audio, movie, surface/texture, retained-object, animation, presentation, ADV-text, and
|
||||
text-history `VirtualMachine.Step` families routed through domain handlers, extract the ADV skip/auto-message
|
||||
service opcode family next without replacing the proven dispatcher or changing public types, commands, and
|
||||
generated output.
|
||||
Concrete playthrough blockers may still preempt this bounded maintenance work; the consolidation effort does
|
||||
not replace Phase B gameplay validation or the open cross-platform gates.
|
||||
|
||||
72
engine/Age.Engine/Vm/VirtualMachine.TextHistory.cs
Normal file
72
engine/Age.Engine/Vm/VirtualMachine.TextHistory.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using Age.Engine.Model;
|
||||
|
||||
namespace Age.Engine.Vm;
|
||||
|
||||
public sealed partial class VirtualMachine
|
||||
{
|
||||
private int StepTextHistory(string label, IReadOnlyList<Operand> a, int pc)
|
||||
{
|
||||
switch (label)
|
||||
{
|
||||
case "set-text-history-recording": // 0x1bb: HISTORY.BIN suppresses recording its own UI
|
||||
if (Read(a[0]) is 0 or 1)
|
||||
{
|
||||
bool enabled = Read(a[0]) == 1;
|
||||
TextHistory.SetRecordingEnabled(enabled);
|
||||
if (enabled) _host.EndTextHistoryPresentation(Gfx);
|
||||
}
|
||||
return pc + 1;
|
||||
case "append-text-history-metadata": // 0x1d2: (metadata type, value)
|
||||
TextHistory.AppendMetadata(Read(a[1]), Read(a[0]), _advTextStyle); return pc + 1;
|
||||
case "step-text-history": // 0x1d0: cumulative delta from the latest retained boundary
|
||||
if (TextHistory.TryStepGroup((int)Read(a[2]), out var historyEntry))
|
||||
{
|
||||
Write(a[0], historyEntry.LayoutSlot);
|
||||
Write(a[1], historyEntry.FirstRecordIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write(a[0], -1);
|
||||
Write(a[1], -1);
|
||||
}
|
||||
return pc + 1;
|
||||
case "render-text-history": // 0x1d1: rasterize/bind one retained group to a target layout
|
||||
case "u0041BAE0":
|
||||
{
|
||||
int flags = (int)Read(a[2]);
|
||||
if ((flags & 4) == 0 && TextHistory.TryBuildRenderBatch(
|
||||
(int)Read(a[0]), (int)Read(a[1]), flags, Read(a[3]), Read(a[4]), out var batch))
|
||||
{
|
||||
batch = batch with
|
||||
{
|
||||
// Native History uses the text manager's current leading, not a retained-record field.
|
||||
Style = batch.Style with { LineSpacing = _advTextStyle.LineSpacing }
|
||||
};
|
||||
_host.RenderTextHistory(
|
||||
Gfx,
|
||||
TextHistory.GetPresentationBinding(batch.LayoutSlot),
|
||||
batch);
|
||||
}
|
||||
return pc + 1;
|
||||
}
|
||||
case "u0041BB90":
|
||||
case "find-text-history-value": // 0x1d3: operand 3 is accepted but ignored natively
|
||||
{
|
||||
bool found = TextHistory.TryFindMetadata((int)Read(a[3]), Read(a[4]), out long value);
|
||||
Write(a[0], found ? 1 : 0);
|
||||
Write(a[1], value);
|
||||
return pc + 1;
|
||||
}
|
||||
case "u0041BC00":
|
||||
case "find-text-history-pair": // 0x1d4: operand 3 is accepted but ignored natively
|
||||
TextHistory.TryFindVoicePair((int)Read(a[3]), out long voiceId, out long voiceArgument);
|
||||
Write(a[0], voiceId);
|
||||
Write(a[1], voiceArgument);
|
||||
return pc + 1;
|
||||
case "clear-text-history": // 0x85: bound the backlog to the current ordinary ADV block
|
||||
TextHistory.Clear(); return pc + 1;
|
||||
default:
|
||||
throw new InvalidOperationException($"Non-text-history opcode routed to text-history handler: {label}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2258,63 +2258,17 @@ public sealed partial class VirtualMachine
|
||||
case "block-mark":
|
||||
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)
|
||||
{
|
||||
bool enabled = Read(a[0]) == 1;
|
||||
TextHistory.SetRecordingEnabled(enabled);
|
||||
if (enabled) _host.EndTextHistoryPresentation(Gfx);
|
||||
}
|
||||
return pc + 1;
|
||||
case "append-text-history-metadata": // 0x1d2: (metadata type, value)
|
||||
TextHistory.AppendMetadata(Read(a[1]), Read(a[0]), _advTextStyle); return pc + 1;
|
||||
case "step-text-history": // 0x1d0: cumulative delta from the latest retained boundary
|
||||
if (TextHistory.TryStepGroup((int)Read(a[2]), out var historyEntry))
|
||||
{
|
||||
Write(a[0], historyEntry.LayoutSlot);
|
||||
Write(a[1], historyEntry.FirstRecordIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write(a[0], -1);
|
||||
Write(a[1], -1);
|
||||
}
|
||||
return pc + 1;
|
||||
case "set-text-history-recording":
|
||||
case "append-text-history-metadata":
|
||||
case "step-text-history":
|
||||
case "render-text-history": // 0x1d1: rasterize/bind one retained group to a target layout
|
||||
case "u0041BAE0":
|
||||
{
|
||||
int flags = (int)Read(a[2]);
|
||||
if ((flags & 4) == 0 && TextHistory.TryBuildRenderBatch(
|
||||
(int)Read(a[0]), (int)Read(a[1]), flags, Read(a[3]), Read(a[4]), out var batch))
|
||||
{
|
||||
batch = batch with
|
||||
{
|
||||
// Native History uses the text manager's current leading, not a retained-record field.
|
||||
Style = batch.Style with { LineSpacing = _advTextStyle.LineSpacing }
|
||||
};
|
||||
_host.RenderTextHistory(
|
||||
Gfx,
|
||||
TextHistory.GetPresentationBinding(batch.LayoutSlot),
|
||||
batch);
|
||||
}
|
||||
return pc + 1;
|
||||
}
|
||||
case "u0041BB90":
|
||||
case "find-text-history-value": // 0x1d3: operand 3 is accepted but ignored natively
|
||||
{
|
||||
bool found = TextHistory.TryFindMetadata((int)Read(a[3]), Read(a[4]), out long value);
|
||||
Write(a[0], found ? 1 : 0);
|
||||
Write(a[1], value);
|
||||
return pc + 1;
|
||||
}
|
||||
case "u0041BC00":
|
||||
case "find-text-history-pair": // 0x1d4: operand 3 is accepted but ignored natively
|
||||
TextHistory.TryFindVoicePair((int)Read(a[3]), out long voiceId, out long voiceArgument);
|
||||
Write(a[0], voiceId);
|
||||
Write(a[1], voiceArgument);
|
||||
return pc + 1;
|
||||
case "clear-text-history": // 0x85: bound the backlog to the current ordinary ADV block
|
||||
TextHistory.Clear(); return pc + 1;
|
||||
case "clear-text-history":
|
||||
return StepTextHistory(label, a, pc);
|
||||
case "set-font-size":
|
||||
case "set-ruby-font-size":
|
||||
case "u0041B3D0":
|
||||
|
||||
Reference in New Issue
Block a user