Implement ADV History data navigation
This commit is contained in:
@@ -1325,8 +1325,14 @@ and `0x85` feed it directly; Godot remains only a presentation host and does not
|
||||
The model intentionally has no JSON or disk serialization. `GameSession.ToJson()` continues to snapshot
|
||||
only the pre-existing global banks, so landing the live backlog does not silently choose a save/profile
|
||||
backend. Native numbered-save restoration remains the explicit future integration seam described above.
|
||||
The next History slice can now implement generic inline arrays/value dispatch and ops `0x1d0..0x1d4` over
|
||||
real retained data before adding host rendering.
|
||||
The second port slice implements generic inline-array copying (`0x64`), formatted value dispatch
|
||||
(`0xa1/0xa2/0xa3`), cumulative navigation (`0x1d0`), and metadata/voice queries (`0x1d3/0x1d4`). The C#
|
||||
loader retains the original body dwords so `0x64` copies the file's plain count-prefixed values; AGE's
|
||||
rotate/XOR work belongs to its native in-memory representation, not the SYS4 file format. Navigation mirrors
|
||||
manager `+0xd6c`: layout define/reset updates the latest-entry anchor, while each `0x1d0` delta is cumulative
|
||||
and does not mutate it. Query scans stop at the next group-start record; their third operands are unused by
|
||||
the native helpers. History's remaining work is therefore presentation and interaction rather than backlog
|
||||
data access.
|
||||
|
||||
The original dependency order was **Hide Window first** to establish reusable callback/coroutine input, then
|
||||
Read-message Skip, then History after both the input layer and message-completion seam exist. Hide Window is
|
||||
|
||||
@@ -76,9 +76,9 @@
|
||||
- **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.
|
||||
|
||||
### 0x1d0 `step-text-history` (step-text-history, argc 3)
|
||||
- **summary:** (out_layout_slot)(out_record_index)(delta) - move through retained ADV text-history groups and return the resolved layout slot and first record index, or -1 outputs at a boundary.
|
||||
- **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
|
||||
- **evidence:** Ghidra /v2: op_0x1d0_step_text_history@0x427360 calls text_history_step_group@0x4537c0 with operand 3 and mode mask 2, then writes the index entry's first field (layout slot) and second field (record index). The helper walks the 8-byte logical index over 0x48-byte retained records, skips record-flag bit1 for mode mask 2, and returns -1 outputs at a boundary. HISTORY.BIN uses negative deltas to count/page backward and positive deltas to page forward.
|
||||
- **evidence:** Ghidra /v2: op_0x1d0_step_text_history@0x427360 calls text_history_step_group@0x4537c0 with operand 3 and mode mask 2, then writes the index entry's first field (layout slot) and second field (record index). Layout define/reset set manager+0xd6c to the newest entry; the helper reads but does not mutate that anchor, so deltas are cumulative. It skips duplicate record offsets and record-flag bit1, and returns -1 outputs at a boundary. HISTORY.BIN uses negative cumulative deltas to count/page backward.
|
||||
|
||||
### 0x1d1 `render-text-history` (u0041BAE0, argc 5)
|
||||
- **summary:** (layout_slot)(record_index)(flags)(color_a)(color_b) - render retained ADV text records into a selected text layout/surface.
|
||||
@@ -90,15 +90,15 @@
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: op_0x1d2_handler@0x41f9c0 tests ctx+0x55110 and, when recording is enabled, calls text_history_append_typed_metadata@0x455f00. That appends a 0x48-byte record with flag 0x20000000, operand 1 at +0x14, and operand 2 at +0x18, consuming the pending group-start flag if set. The corpus has 17,323 uses; HISTORY.BIN later queries metadata types 1 and 2 through op 0x1d3. This opcode is effectful, not a statement marker.
|
||||
|
||||
### 0x1d3 `find-text-history-value` (u0041BB90, argc 5)
|
||||
### 0x1d3 `find-text-history-value` (find-text-history-value, argc 5)
|
||||
- **summary:** (out_found)(out_value)(direction)(record_index)(value_type) - find typed metadata within one retained ADV message group.
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: op_0x1d3_find_text_history_value@0x4273c0 calls text_history_find_typed_value@0x450840 and writes its boolean result plus returned value. The helper scans the 0x48-byte text records within a logical group for flag 0x20000000 and matching type in record+0x18, returning record+0x14. HISTORY.BIN queries types 1 and 2 for line decoration/name metadata.
|
||||
- **evidence:** Ghidra /v2: op_0x1d3_find_text_history_value@0x4273c0 calls text_history_find_typed_value@0x450840 and writes its boolean result plus returned value. The helper scans forward from operand 4 until the next group-start bit for flag 0x20000000 and matching type in record+0x18, returning the last match's record+0x14. Operand 3 reaches an unused helper parameter. HISTORY.BIN passes 1 and queries types 1 and 2 for line decoration/name metadata.
|
||||
|
||||
### 0x1d4 `find-text-history-pair` (u0041BC00, argc 4)
|
||||
### 0x1d4 `find-text-history-pair` (find-text-history-pair, argc 4)
|
||||
- **summary:** (out_a)(out_b)(direction)(record_index) - find paired metadata within one retained ADV message group.
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: op_0x1d4_find_text_history_pair@0x427430 calls text_history_find_pair@0x4509f0 and writes two outputs. The helper scans the logical group for a record flagged 0x40000000 and returns its +0x14/+0x18 pair. HISTORY.BIN uses the pair to expose voice replay for a backlog entry.
|
||||
- **evidence:** Ghidra /v2: op_0x1d4_find_text_history_pair@0x427430 calls text_history_find_pair@0x4509f0 and writes two outputs. The helper scans forward from operand 4 until the next group-start bit and returns the last 0x40000000 record's +0x14/+0x18 pair, defaulting both outputs to -1. Operand 3 reaches an unused helper parameter. HISTORY.BIN passes 1 and uses the pair to expose voice replay for a backlog entry.
|
||||
|
||||
### 0x204 `draw-string` (draw-string, argc 4)
|
||||
- **summary:** (surface_slot)(x)(y)(string) - rasterize a CP932 string immediately into a numbered graphics surface using current font/color/effect state.
|
||||
@@ -152,7 +152,7 @@
|
||||
### 0x64 `copy-inline-int-array` (copy-inline-int-array, argc 2)
|
||||
- **summary:** (destination)(inline_blob_offset) - decode the count-prefixed integer literal blob at codebase + offset*4 and copy its values to consecutive VM integer cells beginning at destination.
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: op_0x64_handler@0x426b00 resolves operand 1 as a writable VM address, reads a count dword followed by encoded values from frame_codebase + operand2*4, reverses the engine rotate/XOR encoding with anti_tamper_a, and writes consecutive dwords. HISTORY.BIN uses 15 blobs to initialize its rectangle, coordinate, and lookup arrays.
|
||||
- **evidence:** Ghidra /v2: op_0x64_handler@0x426b00 resolves operand 1 as a writable VM address, reads a count dword followed by values from frame_codebase + operand2*4, reverses the native loader's rotate/XOR in-memory representation with anti_tamper_a, and writes consecutive dwords. The original SYS4 file footer stores the count and values plainly; HISTORY.BIN uses 15 blobs to initialize its rectangle, coordinate, and lookup arrays.
|
||||
|
||||
### 0x135 `bit-set` (bit-set, argc 2)
|
||||
- **summary:** (value)(bit_index) - set the indexed bit in the destination integer.
|
||||
|
||||
@@ -1704,3 +1704,27 @@ safe-noop.
|
||||
**Next:** implement generic inline integer arrays (`0x64`) and value-switch dispatch (`0xa1/0xa2/0xa3`),
|
||||
then wire History navigation/query ops `0x1d0`, `0x1d3`, and `0x1d4` against this model. Rendering op `0x1d1`
|
||||
and its presentation operations can follow once those data-side script paths execute correctly.
|
||||
|
||||
### ADV History data-side navigation implemented (2026-07-18)
|
||||
|
||||
The second bounded slice is complete. `Script.BodyDwords` retains the original SYS4 body for runtime data
|
||||
operands, and op `0x64` copies its plain count-prefixed footer values into consecutive global or local VM
|
||||
cells. The native rotate/XOR sequence reverses AGE's loader-created in-memory representation; applying it
|
||||
again to the file would corrupt HISTORY's visibly plain rectangle and coordinate arrays. Generic
|
||||
`0xa1/0xa2/0xa3` value-switch sequences now use formatted keys and branch to their registered or default PC.
|
||||
|
||||
The retained model now exposes native navigation and query behavior. Layout boundaries update a latest-entry
|
||||
anchor; op `0x1d0` resolves cumulative deltas from that anchor without mutating it, skipping duplicate first-
|
||||
record offsets and navigation-filtered records. Ops `0x1d3/0x1d4` scan from a supplied record through one
|
||||
group and return typed metadata or the voice pair with native defaults. Ghidra confirms both opcodes' third
|
||||
operands reach unused helper parameters despite HISTORY passing 1.
|
||||
|
||||
Eight new focused cases cover signed inline values, real HISTORY footer retention, matched/default value
|
||||
switches, cumulative group navigation, duplicate/filter skipping, metadata/voice queries, and missing-value
|
||||
defaults. Validation: engine 190/190, opcode generator tests/lint clean, zero-warning Godot build, threaded
|
||||
`SELFTEST OK`. HISTORY is now 63/78 distinct opcodes and 833/854 instructions handled or safe-noop; its 15
|
||||
remaining effectful gaps total 21 instructions.
|
||||
|
||||
**Next:** implement History's display slice around `0x1d1`, layout origin `0x198`, message-window alpha
|
||||
`0x131`, surface fill `0x20b`, and retained-object presentation `0x222`. After visible backlog rows render,
|
||||
finish rectangle hover/interaction, voice replay, and the `0xd3/0xd4/0xd5` smooth-scroll scheduler details.
|
||||
|
||||
@@ -110,6 +110,19 @@ task. These tags give a head start on labeling the disassembly.*
|
||||
- Non-scene scripts (`MENU`, `ADDEXP`) contain only a handful of control strings —
|
||||
consistent with the inventory's subsystem/data-table categorization.
|
||||
|
||||
## Inline integer arrays — CONFIRMED
|
||||
|
||||
Opcode `0x64` operand 2 points to a footer blob in the same body-dword coordinate space as strings. The blob
|
||||
is `[count:u32, value0:u32, ... valueN:u32]`; these dwords are stored plainly in the original SYS4 file.
|
||||
For example, `HISTORY.BIN@0x13d4` is `[4, 0, 5, 0, 538]`, and its fifteen blobs initialize the backlog UI's
|
||||
rectangle, coordinate, and lookup arrays. An op-`0x64` reference lowers the executable-code boundary just
|
||||
like a type-2 string reference.
|
||||
|
||||
Native `AGE.EXE` applies a per-context rotate/XOR representation after loading script data and reverses it
|
||||
inside the opcode handler. That transformation is not part of the on-disk format: file readers and the port
|
||||
must copy the footer's plain dwords, including two's-complement negative values, without applying the native
|
||||
memory-cookie transform.
|
||||
|
||||
## Patch-override caveat (re-confirmed)
|
||||
|
||||
49 loose script `.BIN` files in the game root shadow DATA1 copies at runtime and differ slightly in size;
|
||||
|
||||
Reference in New Issue
Block a user