Implement ADV text publication service
This commit is contained in:
@@ -39,6 +39,7 @@ Struct `EngineCtx`, size `0xa1000`. Applied to the Ghidra `/v2` image (dispatch-
|
||||
| `0x552e8` | `ret_stack_b` | `void*` | per-frame return stack (companion) |
|
||||
| `0x5f304` | `sleep_timer` | `int` | sleep timer object (op 0xc8; +8 active, +0x14 start-ms, +0x18 duration) |
|
||||
| `0x5f3ac` | `timed_callback_timer` | `int` | elapsed timer object armed by op 0xd5 and sampled by the timed callback scheduler |
|
||||
| `0x5f64c` | `adv_wait_indicator_timer` | `int` | elapsed timer started by op 0x1ce and ADV wait setup to select the animated input-wait indicator frame |
|
||||
| `0x5f690` | `timed_callback_abort_pc` | `int` | optional local fallback PC supplied to op 0xd5; -1 disables abort redirection |
|
||||
| `0x5f694` | `timed_callback_entries_vector` | `int` | MSVC vector object base for 16-byte schedule entries; begin/end/capacity pointers follow |
|
||||
| `0x5f698` | `timed_callback_entries_begin` | `void*` | begin pointer for 16-byte entries {deadline_ms, field_100, primary_pc, catchup_pc} |
|
||||
@@ -48,8 +49,12 @@ Struct `EngineCtx`, size `0xa1000`. Applied to the Ghidra `/v2` image (dispatch-
|
||||
| `0x5f6a8` | `timed_callback_cursor` | `int` | next schedule entry consumed by timed_callback_sequence_tick; op 0xd3 resets to zero |
|
||||
| `0x5f6b4` | `timed_callback_script_resource_id` | `uint` | active frame script resource retained by op 0xd5 for local callback dispatch safety |
|
||||
| `0x5f6b8` | `timed_callback_script_resource_guard` | `uint` | companion current-script identity checked before redirecting to a scheduled callback |
|
||||
| `0x5f72c` | `adv_wait_indicator_frame` | `int` | current animated input-wait indicator frame, reset to zero when the service is armed |
|
||||
| `0x5f730` | `adv_wait_indicator_terminal_frame` | `int` | terminal frame returned by the indicator layout during ADV wait setup |
|
||||
| `0x5f734` | `adv_wait_indicator_enabled_value` | `int` | raw enable operand last written by op 0x1ce; nonzero arms the ADV wait-indicator service |
|
||||
| `0x6da78` | `message_skip_activation_guard` | `int` | set when op 0x88 enables Skip; suppresses the enabling click from immediately becoming a hotspot activation |
|
||||
| `0x6da80` | `message_skip_cancel_click_phase` | `int` | press/release phase used only when set:CancelMesSkipOnClick is nonzero |
|
||||
| `0x6da84` | `adv_wait_indicator_layout_slot` | `int` | ADV text layout whose wait indicator is armed or erased by input-wait setup and op 0x1ce |
|
||||
| `0x6da88` | `coroutine_yield_a` | `void*` | op 0x7b yield-state save (op1 -> +ctxidx*4) |
|
||||
| `0x6db28` | `coroutine_yield_b` | `void*` | op 0x7b yield-state save (op2 -> +ctxidx*4) |
|
||||
| `0x6dbc8` | `coroutine_runstate` | `int` | op 0x7c resume gate (run-state bit 0x2000000) |
|
||||
|
||||
@@ -1725,6 +1725,46 @@ saved.
|
||||
|
||||
---
|
||||
|
||||
### ADV text publication and wait-indicator service -- opcodes `0x1ce` / `0x20a` (2026-07-20)
|
||||
|
||||
The earlier working label "sprite-animation service" was too broad. These operations belong specifically
|
||||
to ADV text publication and the animated input-wait indicator (the bouncing marker shown after a page
|
||||
finishes typing). They do not expose a generic retained-object animation channel.
|
||||
|
||||
`op_0x1ce_set_adv_wait_indicator_enabled@0x41f8c0` stores its operand at
|
||||
`EngineCtx.adv_wait_indicator_enabled_value` (`ctx+0x5f734`). A nonzero value sets run-state bit
|
||||
`0x40000000`, resets `adv_wait_indicator_frame` (`ctx+0x5f72c`) to zero, and starts
|
||||
`adv_wait_indicator_timer` (`ctx+0x5f64c`). Zero erases the indicator belonging to
|
||||
`adv_wait_indicator_layout_slot` (`ctx+0x6da84`) with the worker's frame `-2` mode and clears the run bit.
|
||||
Every Himegari corpus use is `0x1ce(0)`, normally at entry to a modal script; `HISTORY.BIN@0x3` is the
|
||||
concrete route relevant here.
|
||||
|
||||
`op_0x20a_publish_adv_text_layout@0x422ce0` first calls
|
||||
`adv_text_publish_layout@0x450c80`. Slot zero selects the text manager's current layout; a nonzero operand
|
||||
selects that indexed layout. The worker erases the layout's old retained-object range, walks its 20-byte
|
||||
text records, and rebinds their draw objects. When run-state bit `0x40000000` is active, the opcode also
|
||||
calls `adv_text_publish_wait_indicator_frame@0x453120` with the current indicator frame. The latter worker
|
||||
uses frame `-1` to return/capture the terminal frame, `-2` to erase the indicator object, and a
|
||||
nonnegative frame to choose and bind the corresponding atlas cell. All corpus uses are `0x20a(1)`;
|
||||
`HISTORY.BIN@0x13ab` reaches it through the shared ADV redraw callback.
|
||||
|
||||
Opcode `0x72` owns the normal implicit start of the same service: it records the waiting layout, captures
|
||||
the indicator's terminal frame, resets the active frame to zero, starts the timer, and raises run-state bit
|
||||
`0x40000000`. Completing the input wait erases the object and clears the bit. In the original interpreter,
|
||||
return from a nested modal script flows through that shared redraw/wait path and re-arms the parent marker.
|
||||
The port's host blocks inside the enclosing wait while servicing the nested HISTORY callback, so it restores
|
||||
the previously enabled parent marker at the callback-return boundary. This is lifecycle equivalence, not a
|
||||
script-specific seed or global-state workaround.
|
||||
|
||||
The port exposes the two explicit operations as host services: `0x1ce` controls marker eligibility and
|
||||
`0x20a` requests retained ADV publication. Godot's existing indicator clock/configuration remains the
|
||||
animation implementation. The real SC0000-to-HISTORY regression proves HISTORY disables the marker on
|
||||
entry, executes layout-slot-1 publication on return, clears transient History rows, and leaves the enclosing
|
||||
ADV page wait in place. The expanded 63-field `EngineCtx` and semantic function annotations are applied to
|
||||
the saved `/v2` image.
|
||||
|
||||
---
|
||||
|
||||
## Native walls backlog (targets for this loop)
|
||||
|
||||
- ~~**call-script dispatch**~~ — **SOLVED** (above): `call-script <id>` = raw SYS4INI file index.
|
||||
|
||||
@@ -80,6 +80,11 @@
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: op_0x1bb_handler@0x41f650 writes 0x80000000 to ctx+0x55110 for operand 0 and zero for operand 1, rejecting other values. Text/layout/metadata/voice paths test or propagate that high bit before appending retained history. HISTORY.BIN disables recording at entry and reenables it at exit so the backlog UI does not record itself.
|
||||
|
||||
### 0x1ce `set-adv-wait-indicator-enabled` (u0041B9F0, argc 1)
|
||||
- **summary:** (enabled) - explicitly start or stop the animated ADV input-wait indicator service.
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra op_0x1ce_set_adv_wait_indicator_enabled@0x41f8c0 writes enabled to ctx+0x5f734. A nonzero value sets run bit 0x40000000, resets ctx+0x5f72c to frame zero, and starts the ctx+0x5f64c elapsed timer. Zero erases the indicator through adv_text_publish_wait_indicator_frame@0x453120 using ctx+0x6da84 and frame -2 when necessary, then clears the run bit. The corpus uses 0x1ce(0) on modal/menu entry, including HISTORY.BIN@0x3.
|
||||
|
||||
### 0x1d0 `step-text-history` (step-text-history, argc 3)
|
||||
- **summary:** (out_layout_slot)(out_record_index)(delta) - resolve a cumulative delta from the latest retained ADV boundary and return its layout slot and first record index, or -1 outputs at a boundary.
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
@@ -110,6 +115,11 @@
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: op_0x204_handler@0x422a60 resolves operand 4 as a string, fetches surface/x/y, then calls draw_string_to_surface@0x450150 on text manager ctx+0x14940. The worker validates and locks gfx-manager surface table +0xa590[slot], chooses text_raster_string_uncached@0x459d90 or cached/effect path @0x45b600, rasterizes GDI GetGlyphOutlineA bitmaps through text_blit_glyph_bitmap@0x458c80 using font/color state +0x4d0/+0x458, then unlocks. SC0000 0x9b2 draws the speaker name into 400x30 surface 0xd at (1,1); following 0x1fb binds it to retained object 0xe678 at (74,444).
|
||||
|
||||
### 0x20a `publish-adv-text-layout` (u00420CE0, argc 1)
|
||||
- **summary:** (layout_slot) - republish one ADV text layout and, while active, its current wait-indicator frame.
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra op_0x20a_publish_adv_text_layout@0x422ce0 passes the requested slot to adv_text_publish_layout@0x450c80, which rebinds the layout's retained text records. If ADV run-state bit 0x40000000 is active, it also calls adv_text_publish_wait_indicator_frame@0x453120 with ctx+0x5f72c. Slot zero resolves the text manager's current layout; the corpus always uses slot one, including HISTORY.BIN@0x13ab in its shared ADV redraw callback.
|
||||
|
||||
### 0x2bd `set-font-bold` (set-font-bold, argc 1)
|
||||
- **summary:** (enabled) - set the current primary text font weight to 700 when enabled or 0 when disabled, then rebuild the native font state.
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
@@ -1068,10 +1078,6 @@ op 0x90 (u0041BEB0, argc 7): `0x90 x y w h tgt_a tgt_b tgt_c`. Kelebek left it "
|
||||
- **summary:** —
|
||||
- **grounding:** source=kelebek, confidence=med
|
||||
|
||||
### 0x1ce `u0041B9F0` (u0041B9F0, argc 1)
|
||||
- **summary:** —
|
||||
- **grounding:** source=kelebek, confidence=low
|
||||
|
||||
### 0x1cf `u0041DA10` (u0041DA10, argc 1)
|
||||
- **summary:** —
|
||||
- **grounding:** source=kelebek, confidence=low
|
||||
@@ -1092,10 +1098,6 @@ op 0x90 (u0041BEB0, argc 7): `0x90 x y w h tgt_a tgt_b tgt_c`. Kelebek left it "
|
||||
- **summary:** —
|
||||
- **grounding:** source=kelebek, confidence=low
|
||||
|
||||
### 0x20a `u00420CE0` (u00420CE0, argc 1)
|
||||
- **summary:** —
|
||||
- **grounding:** source=kelebek, confidence=low
|
||||
|
||||
### 0x20d `u00420E10` (u00420E10, argc 1)
|
||||
- **summary:** —
|
||||
- **grounding:** source=kelebek, confidence=low
|
||||
|
||||
@@ -1926,3 +1926,29 @@ slice. Keep `0x1cb` deferred until the global save/profile storage boundary is c
|
||||
Validation: all 205 engine tests pass, including four focused History presentation cases; opcode and
|
||||
EngineCtx tests/lints are clean, vm0 RECOVER passes, the Godot build has zero warnings, and threaded
|
||||
`SELFTEST OK`.
|
||||
|
||||
### ADV History text publication / wait-indicator service implemented (2026-07-20)
|
||||
|
||||
Native RE corrects the provisional "sprite-animation service" description: `0x1ce` and `0x20a` are the
|
||||
explicit control points for ADV text publication and its animated input-wait indicator. `0x1ce(enabled)`
|
||||
starts or stops the indicator's run-state/timer/frame service; Himegari only calls it with zero when entering
|
||||
modal scripts, including HISTORY. `0x20a(layout_slot)` republishes the selected retained text layout and,
|
||||
when the service is active, binds its current indicator frame; HISTORY's shared redraw callback uses slot 1.
|
||||
Normal ADV wait opcode `0x72` implicitly arms the same service.
|
||||
|
||||
The VM now forwards both operations through generic host methods. Godot gates its existing animated marker
|
||||
on the explicit enabled state and requests recomposition for layout publication. Because the port keeps the
|
||||
parent wait blocked while a nested raw-input callback executes, it restores a previously enabled parent
|
||||
marker when that callback returns, matching the native path that re-enters the shared redraw/wait routine.
|
||||
No script offsets, boot seeds, or persistence assumptions were introduced.
|
||||
|
||||
A focused synthetic regression verifies the two service calls, and the real SC0000-to-HISTORY regression
|
||||
requires marker disable plus layout-slot-1 publication while preserving the same enclosing ADV wait and
|
||||
cleaning the modal rows. The canonical opcode and EngineCtx sources are regenerated; the `/v2` handlers and
|
||||
workers are named/commented, the expanded 63-field `EngineCtx` is applied, and the image is saved. HISTORY
|
||||
is now 77/78 distinct opcodes and 853/854 instructions handled or safe-noop. The only remaining instruction
|
||||
is the deliberately deferred `0x1cb` Read-message Skip setting getter, pending a global profile/save backend
|
||||
decision.
|
||||
|
||||
Validation: all 206 engine tests pass, opcode and EngineCtx tests/lints are clean, vm0 RECOVER passes, the
|
||||
Godot build has zero warnings, and threaded `SELFTEST OK`.
|
||||
|
||||
Reference in New Issue
Block a user