Investigate INPUTNAME string opcodes
This commit is contained in:
@@ -611,16 +611,16 @@ handle array** (native entry-state a cold single-scene harness skips), NOT a sto
|
|||||||
table). So the intended lifecycle is **enter `aba5c=1` → intro loop fills slots → `aba5c→0` → content uses
|
table). So the intended lifecycle is **enter `aba5c=1` → intro loop fills slots → `aba5c→0` → content uses
|
||||||
slots.** Cold we skip straight to content with an empty slot table → all layers collapse to slot 0 → grey.
|
slots.** Cold we skip straight to content with an empty slot table → all layers collapse to slot 0 → grey.
|
||||||
|
|
||||||
**The loop iterator `op 0x140` is a native video-service call — not statically reproducible.** Handler =
|
**The loop iterator `op 0x140` is a native AGERC service call.** Handler =
|
||||||
**`0x4299c0`** (dispatch `ctx[0x9b74c]=0x4299c0`; created+typed `EngineCtx*`+annotated; Kelebek `u0041F9C0` is
|
**`0x4299c0`** (dispatch `ctx[0x9b74c]=0x4299c0`; created+typed `EngineCtx*`+annotated; Kelebek `u0041F9C0` is
|
||||||
VA-drift). It records the generic 9-dword instruction length, copies operand-2/3 strings (`"LABEL"`, `"J"`) + operand-4 int, calls
|
VA-drift). It records the generic 9-dword instruction length, copies operand-2/3 strings (`"LABEL"`, `"J"`) + operand-4 int, calls
|
||||||
**`(*DAT_005c6018)(8, ctx[0x54fe8], &{str,str,int})`**, and writes the returned PC-like value back to operand 1
|
**`(*g_pfnAgercHostCallback)(8, ctx[0x54fe8], &{str,str,int})`**, and writes the returned PC-like value back
|
||||||
(SC0000: `G[0x6be]`). `DAT_005c6018` is a **runtime-resolved function pointer** (all 6 xrefs are READs, no
|
to operand 1 (SC0000: `G[0x6be]`). The callback has no static writer in the unpacked AGE image because the
|
||||||
static writer) — the engine's **native video / transition / timing service**: `FUN_00405740` (a screen-
|
loaded resource DLL supplies it. A read-only live probe now resolves it to `AGERC.DLL+0x1050`; the imported
|
||||||
transition/fade routine full of DirectDraw-layer calls) calls the *same* pointer with `cmd_id=3` and branches
|
`/support/AGERC.DLL` image names that thunk `agerc_host_callback_export` and its worker
|
||||||
on its return (`1`/`2` = transition progress). It is the **same class as the DirectDraw workers this project
|
`agerc_dispatch_host_command@0x100025f0`. Command 8 opens AGERC dialog resource 8. The same callback's
|
||||||
deliberately does not model.** ⇒ faithfully emulating `0x140` = emulating the native video service = out of
|
command 3 services `FUN_00405740` screen transitions. This closes the callback's ownership and makes a
|
||||||
static scope, permanently.
|
future `0x140` dive statically possible, but does not by itself identify command 8's LABEL iterator result.
|
||||||
|
|
||||||
**The two companion ops (confirmed):**
|
**The two companion ops (confirmed):**
|
||||||
- **`0x7b` (`FUN_0041ebf0`)** — *save yield handlers*: writes op1→`ctx[0x6da88+idx*4]`, op2→`ctx[0x6db28+idx*4]`
|
- **`0x7b` (`FUN_0041ebf0`)** — *save yield handlers*: writes op1→`ctx[0x6da88+idx*4]`, op2→`ctx[0x6db28+idx*4]`
|
||||||
@@ -638,8 +638,8 @@ completion so content plays — we reproduce the *observable effect*, not the vi
|
|||||||
byte-identical across all ~136 ADV scenes, so it generalizes with zero per-scene work. **Payoff beyond the
|
byte-identical across all ~136 ADV scenes, so it generalizes with zero per-scene work. **Payoff beyond the
|
||||||
slot fix:** the same `0x7b`/`0x7c` + handler machinery is the ADV frame loop, so a clean host model becomes
|
slot fix:** the same `0x7b`/`0x7c` + handler machinery is the ADV frame loop, so a clean host model becomes
|
||||||
the seam for the interactive-ADV backlog (`0x90` hotspots / EMPTY scenes) and likely fixes the stuck magic
|
the seam for the interactive-ADV backlog (`0x90` hotspots / EMPTY scenes) and likely fixes the stuck magic
|
||||||
circle (scene-phase cleanup). **Permanently out of static scope:** the real intro-transition *timing/pacing*
|
circle (scene-phase cleanup). The real intro-transition *timing/pacing* inside AGERC's command-8 service
|
||||||
inside the loop (it lives in the native video service) — we approximate it host-side, as everywhere else.
|
remains intentionally unmodeled; the port approximates it host-side, as it does other native transitions.
|
||||||
**Host model implemented (2026-07-09).** `VirtualMachine` recognizes only the ADV `"LABEL","J"` form
|
**Host model implemented (2026-07-09).** `VirtualMachine` recognizes only the ADV `"LABEL","J"` form
|
||||||
(138 corpus scripts; all have the same terminal-check shape), synthesizes `G[0xaba5c]=1` on top-level
|
(138 corpus scripts; all have the same terminal-check shape), synthesizes `G[0xaba5c]=1` on top-level
|
||||||
scene entry, forces one setup-body pass even if `G[0x6be]` is stale, then returns the terminal immediate
|
scene entry, forces one setup-body pass even if `G[0x6be]` is stale, then returns the terminal immediate
|
||||||
@@ -2859,6 +2859,38 @@ A focused regression covers same-track restart, zero aliasing, loop/one-shot sel
|
|||||||
stop/clear, fade-to-zero release, and restart after stop; the threaded self-test exercises both loop modes
|
stop/clear, fade-to-zero release, and restart after stop; the threaded self-test exercises both loop modes
|
||||||
and real stop/release.
|
and real stop/release.
|
||||||
|
|
||||||
|
**INPUTNAME native editor and CP932 string helpers (mapped 2026-07-29).** The three remaining
|
||||||
|
INPUTNAME-only gaps are one implementation slice, but have two ownership layers:
|
||||||
|
|
||||||
|
- `op_0x144_edit_fullwidth_string_dialog@0x42bdd0` is the engine wrapper for AGERC host command 10.
|
||||||
|
Its ABI is `(result_inout, initial_text)`. AGE resolves both operands into separate 1024-byte buffers,
|
||||||
|
suspends normal display ownership, calls `g_pfnAgercHostCallback(10,owner_hwnd,&{result,initial,0})`,
|
||||||
|
writes both returned buffers through their string lvalues, and restores display ownership.
|
||||||
|
- A read-only Frida probe of the pristine running game resolved `g_pfnAgercHostCallback`
|
||||||
|
(`AGE+0x1c6018`) to `AGERC.DLL+0x1050`. The companion DLL is now imported and annotated at
|
||||||
|
`/support/AGERC.DLL`: `agerc_host_callback_export@0x10001050` forwards to
|
||||||
|
`agerc_dispatch_host_command@0x100025f0`, whose command-10 branch opens dialog resource 10 with
|
||||||
|
`agerc_fullwidth_text_dialog_proc@0x10002140`.
|
||||||
|
- The dialog initializes edit control 1006 from the second buffer. Accept reads no more than 255 bytes,
|
||||||
|
rejects a result longer than 16 CP932 bytes with `字数オーバーです`, and walks it in two-byte cells through
|
||||||
|
`agerc_reject_non_dbcs_character@0x10001b50`; any half-width or invalid cell produces
|
||||||
|
`半角文字は使用できません`. A valid accept replaces the first buffer. Cancel closes without changing it.
|
||||||
|
The dispatcher copies both buffers back, so operand 1 is the result/inout value and operand 2 is the
|
||||||
|
initial edit text.
|
||||||
|
- `op_0x2c6_cp932_character_length@0x42a6d0` sets the C locale to `japanese`, calls MSVC `_mbstrlen` on
|
||||||
|
operand 2, and writes the multibyte-character count to operand 1.
|
||||||
|
- `op_0x2c8_cp932_substring@0x42c420` copies its source into a 256-byte local buffer, counts Japanese
|
||||||
|
multibyte characters, and selects `[start,start+count)` while walking `_mbbtype` lead/trail pairs
|
||||||
|
together. Native clamping replaces the requested end with the full character length when
|
||||||
|
`start+count < 1` or exceeds that length.
|
||||||
|
|
||||||
|
The release script's flow is now fully grounded. INPUTNAME's keyboard button assembles its current
|
||||||
|
character cells, copies that text into both `0x144` operands, then calls `0x2c6` and loops
|
||||||
|
`0x2c8(name,index,1)` to repopulate its eight cells. The pure helpers can use the VM's existing
|
||||||
|
`NativeStringCodePage` encoder. The modal op can follow the existing diagnostic-dialog ownership pattern:
|
||||||
|
the VM worker blocks while Godot's main thread presents a LineEdit dialog, validates the CP932 byte limit
|
||||||
|
and full-width-only rule, and signals the worker on accept or cancel. No save/profile format is involved.
|
||||||
|
|
||||||
`0xc2` is BGM rather than SFX: `op_0xc2_bgm_fade@0x4204c0` sets run-state `0x200`, arms the service timer,
|
`0xc2` is BGM rather than SFX: `op_0xc2_bgm_fade@0x4204c0` sets run-state `0x200`, arms the service timer,
|
||||||
and calls `bgm_fade_arm@0x464830`. `bgm_fade_tick@0x464960` linearly interpolates current to target percent;
|
and calls `bgm_fade_arm@0x464830`. `bgm_fade_tick@0x464960` linearly interpolates current to target percent;
|
||||||
durations at least 1000 ms take 100 steps, shorter durations take 10, and target zero releases the source.
|
durations at least 1000 ms take 100 steps, shorter durations take 10, and target zero releases the source.
|
||||||
|
|||||||
@@ -418,6 +418,20 @@ Native applies strlen to the NUL-terminated engine byte string and shifts the by
|
|||||||
|
|
||||||
This is raw strlen(bytes), not a .NET UTF-16 character count. BUNKI compares all option/title byte lengths, adds four bytes of padding, and converts the result to pixels; skipping the opcode leaves its local maximum at zero, forcing the minimum-width menu and shifting every primary label right. The C# VM shares the configurable native-string byte counter used by op 0x1a6 (CP932 by default), including embedded-NUL termination; focused tests cover literals and local-string pointers.
|
This is raw strlen(bytes), not a .NET UTF-16 character count. BUNKI compares all option/title byte lengths, adds four bytes of padding, and converts the result to pixels; skipping the opcode leaves its local maximum at zero, forcing the minimum-width menu and shifting every primary label right. The C# VM shares the configurable native-string byte counter used by op 0x1a6 (CP932 by default), including embedded-NUL termination; focused tests cover literals and local-string pointers.
|
||||||
|
|
||||||
|
### 0x2c6 `cp932-character-length` (cp932-character-length, argc 2)
|
||||||
|
- **summary:** (out)(string) - write the Japanese-locale multibyte character count of the CP932 string, counting a valid lead/trail pair as one character.
|
||||||
|
- **grounding:** source=investigation, confidence=high
|
||||||
|
- **evidence:** The real /v2 dispatch slot registers op_0x2c6_cp932_character_length@0x42a6d0. The handler sets LC_ALL to `japanese`, resolves operand 2, calls MSVC _mbstrlen, and writes the result to operand 1. INPUTNAME's sole site at 0x1002 uses this count as the loop bound before slicing each character with opcode 0x2c8.
|
||||||
|
|
||||||
|
This is character count rather than .NET UTF-16 length or raw CP932 byte length. The implementation should use VmOptions.NativeStringCodePage and preserve valid CP932 multibyte boundaries.
|
||||||
|
|
||||||
|
### 0x2c8 `cp932-substring` (cp932-substring, argc 4)
|
||||||
|
- **summary:** (out)(string)(start)(count) - copy a CP932 substring selected by multibyte-character index and count without splitting valid lead/trail pairs.
|
||||||
|
- **grounding:** source=investigation, confidence=high
|
||||||
|
- **evidence:** The real /v2 dispatch slot registers op_0x2c8_cp932_substring@0x42c420. It copies operand 2 into a 256-byte buffer, sets LC_ALL to `japanese`, obtains _mbstrlen, reads start and count, clamps end=start+count to the character length when end is below 1 or beyond that length, and walks bytes with _mbbtype so CP932 lead/trail pairs are copied together. It writes the selected byte interval back through operand 1. INPUTNAME's sole site at 0x1021 loops substring(name,index,1) into its eight local character cells.
|
||||||
|
|
||||||
|
The release call uses nonnegative in-range indices and count 1. A compatible general implementation should reproduce native end clamping (`end = length` when start+count < 1 or > length) and select the half-open character interval [start,end).
|
||||||
|
|
||||||
## control
|
## control
|
||||||
|
|
||||||
### 0x1 `throw-exit-request` (throw-exit-request, argc 0)
|
### 0x1 `throw-exit-request` (throw-exit-request, argc 0)
|
||||||
@@ -550,9 +564,9 @@ Native handler sleep_op_0xc8 @0x420ec0 is NON-BLOCKING: it arms a timer (sleep_t
|
|||||||
Implemented as process-lifecycle state owned by the persistent VM: it begins at one and op 0x9 clears it. It is not a script global, save/profile value, command-line seed, or script-name special case.
|
Implemented as process-lifecycle state owned by the persistent VM: it begins at one and op 0x9 clears it. It is not a script global, save/profile value, command-line seed, or script-name special case.
|
||||||
|
|
||||||
### 0x140 `coroutine-label-yield` (u0041F9C0, argc 4)
|
### 0x140 `coroutine-label-yield` (u0041F9C0, argc 4)
|
||||||
- **summary:** (out)(name_str)(sub_str)(in) — scene-coroutine LOOP ITERATOR / labeled yield. Handler copies name/sub strings + the int operand and calls the NATIVE video/transition service (*DAT_005c6018)(8, ctx[0x54fe8], &{name,sub,in}); writes the returned PC-like value to operand 1. In SC0000 label_462 'ループ開始' (@0x46d): `out=G[0x6be]=LABEL('J',G[0x6be])`; loop runs the intro-setup body (incl. call label_125bd = slot-table fill G[0x3239..0x324e]=4..11) and jmps back until out==G[0x6c3] (a per-scene exit-PC immediate) → mov aba5c 0 → content. The gate G[0xaba5c]==1 that opens this loop is NATIVE scene-entry state (no script sets it to 1). DAT_005c6018 is runtime-resolved (all xrefs READ) = SAME class as the DirectDraw workers we don't model. PORT = HOST-MODEL IMPLEMENTED: synthesize the ADV scene-entry gate, run the LABEL/J setup body once, then return the structurally discovered per-scene terminal; do not emulate the video service. See engine-re.md §Scene-coroutine framework.
|
- **summary:** (out)(name_str)(sub_str)(in) — scene-coroutine LOOP ITERATOR / labeled yield. Handler copies name/sub strings + the int operand and calls AGERC host command 8 through g_pfnAgercHostCallback(8, ctx[0x54fe8], &{name,sub,in}); writes the returned PC-like value to operand 1. In SC0000 label_462 'ループ開始' (@0x46d): `out=G[0x6be]=LABEL('J',G[0x6be])`; loop runs the intro-setup body (incl. call label_125bd = slot-table fill G[0x3239..0x324e]=4..11) and jmps back until out==G[0x6c3] (a per-scene exit-PC immediate) → mov aba5c 0 → content. The gate G[0xaba5c]==1 that opens this loop is NATIVE scene-entry state (no script sets it to 1). PORT = HOST-MODEL IMPLEMENTED: synthesize the ADV scene-entry gate, run the LABEL/J setup body once, then return the structurally discovered per-scene terminal; do not emulate the service dialog. See engine-re.md §Scene-coroutine framework.
|
||||||
- **grounding:** source=investigation, confidence=med
|
- **grounding:** source=investigation, confidence=med
|
||||||
- **evidence:** Ghidra: handler 0x4299c0 (dispatch ctx[0x9b74c]=0x4299c0; created+typed EngineCtx*+annotated; Kelebek u0041F9C0 = VA-drift). Records the generic 9-dword instruction length; op2→local_204, op3→local_104, op4→local_208; (*DAT_005c6018)(8, ctx[0x54fe8], &local_210) → FUN_00425fb0(1,ret). DAT_005c6018: 6 xrefs all READ, no static writer; FUN_00405740 (screen-fade) calls it w/ cmd 3, branches on ret 1/2 = transition progress = native video service.
|
- **evidence:** Ghidra: handler 0x4299c0 (dispatch ctx[0x9b74c]=0x4299c0; created+typed EngineCtx*+annotated; Kelebek u0041F9C0 = VA-drift). Records the generic 9-dword instruction length; op2→local_204, op3→local_104, op4→local_208; g_pfnAgercHostCallback(8, ctx[0x54fe8], &local_210) → FUN_00425fb0(1,ret). A read-only probe resolves the callback to AGERC.DLL+0x1050; imported /support/AGERC.DLL identifies agerc_dispatch_host_command@0x100025f0 and its command-8 dialog-resource branch. FUN_00405740 calls the same dispatcher with command 3 and branches on return 1/2 for transition progress. Command 8's exact LABEL iterator calculation remains unresolved, so confidence remains medium.
|
||||||
|
|
||||||
### 0x143 `run-mounted-append-autoruns` (u00415FB0, argc 0)
|
### 0x143 `run-mounted-append-autoruns` (u00415FB0, argc 0)
|
||||||
- **summary:** () - enqueue record zero from every mounted nonzero AAI selector in ascending selector order, then execute those packed scripts serially before resuming the caller.
|
- **summary:** () - enqueue record zero from every mounted nonzero AAI selector in ascending selector order, then execute those packed scripts serially before resuming the caller.
|
||||||
@@ -1232,6 +1246,17 @@ op 0x90 (u0041BEB0, argc 7): `0x90 x y w h tgt_a tgt_b tgt_c`. Kelebek left it "
|
|||||||
- **grounding:** source=investigation, confidence=high
|
- **grounding:** source=investigation, confidence=high
|
||||||
- **evidence:** Ghidra /v2: op_0x12e_find_hit_rectangle@0x428ff0 resolves the reference rectangle and three array operands as VM pointers, decodes rectangle/offset values with anti_tamper_a, and starts at incoming_index+1. Each candidate is [left,right,top,bottom]; the worker subtracts its per-entry x/y offsets from the pointer, inclusively intersects it with the reference rectangle, and writes the matched array index or -1 to operand 1. HISTORY.BIN uses decoded local arrays for scrollbar/control regions, close region 8, and visible text rows 9..13.
|
- **evidence:** Ghidra /v2: op_0x12e_find_hit_rectangle@0x428ff0 resolves the reference rectangle and three array operands as VM pointers, decodes rectangle/offset values with anti_tamper_a, and starts at incoming_index+1. Each candidate is [left,right,top,bottom]; the worker subtracts its per-entry x/y offsets from the pointer, inclusively intersects it with the reference rectangle, and writes the matched array index or -1 to operand 1. HISTORY.BIN uses decoded local arrays for scrollbar/control regions, close region 8, and visible text rows 9..13.
|
||||||
|
|
||||||
|
### 0x144 `edit-fullwidth-string-dialog` (edit-fullwidth-string-dialog, argc 2)
|
||||||
|
- **summary:** (result_inout)(initial_text) - synchronously open AGERC's modal full-width text editor. Accept writes at most eight valid CP932 double-byte characters to operand 1; cancel leaves operand 1 unchanged. Operand 2 supplies the initial edit text and is preserved.
|
||||||
|
- **grounding:** source=investigation, confidence=high
|
||||||
|
- **evidence:** The real /v2 dispatch slot registers op_0x144_edit_fullwidth_string_dialog@0x42bdd0. It copies both resolved string operands into 0x400-byte buffers, calls the runtime host callback g_pfnAgercHostCallback with command 10 and owner HWND, then writes both returned buffers back. A read-only Frida probe of the pristine game resolved that callback to AGERC.DLL+0x1050. Imported /support/AGERC.DLL shows agerc_dispatch_host_command@0x100025f0 opening dialog resource 10 with agerc_fullwidth_text_dialog_proc@0x10002140: edit control 1006 is initialized from operand 2; IDOK rejects more than 16 bytes (`字数オーバーです`) or any non-DBCS cell (`半角文字は使用できません`) before copying the accepted text to operand 1; IDCANCEL closes without changing operand 1. INPUTNAME's sole site at 0xdcd passes its assembled current name in both operands, then resplits operand 1 through 0x2c6/0x2c8.
|
||||||
|
|
||||||
|
This is INPUTNAME's optional native keyboard-entry button, not the surrounding script-authored
|
||||||
|
character palette. The VM can use a synchronous host seam like the existing diagnostic dialog because
|
||||||
|
the Godot host runs script execution on its worker thread while the main thread owns the modal UI.
|
||||||
|
Compatibility requires the native full-width-only and 16-CP932-byte limits before accepting the result.
|
||||||
|
|
||||||
|
|
||||||
### 0x19a `get-message-skip` (u00414E50, argc 1)
|
### 0x19a `get-message-skip` (u00414E50, argc 1)
|
||||||
- **summary:** (out) - return the current all-message skip state set by op 0x88.
|
- **summary:** (out) - return the current all-message skip state set by op 0x88.
|
||||||
- **grounding:** source=investigation, confidence=high
|
- **grounding:** source=investigation, confidence=high
|
||||||
@@ -1938,10 +1963,6 @@ Port status (2026-07-24): implemented through the same profile-lifetime setting
|
|||||||
- **summary:** —
|
- **summary:** —
|
||||||
- **grounding:** source=kelebek, confidence=low
|
- **grounding:** source=kelebek, confidence=low
|
||||||
|
|
||||||
### 0x144 `u004259D0` (u004259D0, argc 2)
|
|
||||||
- **summary:** —
|
|
||||||
- **grounding:** source=kelebek, confidence=low
|
|
||||||
|
|
||||||
### 0x145 `u00416040` (u00416040, argc 1)
|
### 0x145 `u00416040` (u00416040, argc 1)
|
||||||
- **summary:** Broader AGE-catalog compatibility stub; the port currently traces and skips it.
|
- **summary:** Broader AGE-catalog compatibility stub; the port currently traces and skips it.
|
||||||
- **grounding:** source=kelebek, confidence=low
|
- **grounding:** source=kelebek, confidence=low
|
||||||
@@ -2325,19 +2346,11 @@ Port status (2026-07-24): implemented through the same profile-lifetime setting
|
|||||||
- **grounding:** source=kelebek, confidence=low
|
- **grounding:** source=kelebek, confidence=low
|
||||||
- **evidence:** Not observed in Himegari's script corpus; ABI label/argc come from Kelebek's AGE table.
|
- **evidence:** Not observed in Himegari's script corpus; ABI label/argc come from Kelebek's AGE table.
|
||||||
|
|
||||||
### 0x2c6 `u0042B5E0` (u0042B5E0, argc 2)
|
|
||||||
- **summary:** —
|
|
||||||
- **grounding:** source=kelebek, confidence=low
|
|
||||||
|
|
||||||
### 0x2c7 `u0042B5F0` (u0042B5F0, argc 4)
|
### 0x2c7 `u0042B5F0` (u0042B5F0, argc 4)
|
||||||
- **summary:** Broader AGE-catalog compatibility stub; the port currently traces and skips it.
|
- **summary:** Broader AGE-catalog compatibility stub; the port currently traces and skips it.
|
||||||
- **grounding:** source=kelebek, confidence=low
|
- **grounding:** source=kelebek, confidence=low
|
||||||
- **evidence:** Not observed in Himegari's script corpus; ABI label/argc come from Kelebek's AGE table.
|
- **evidence:** Not observed in Himegari's script corpus; ABI label/argc come from Kelebek's AGE table.
|
||||||
|
|
||||||
### 0x2c8 `u0042B610` (u0042B610, argc 4)
|
|
||||||
- **summary:** —
|
|
||||||
- **grounding:** source=kelebek, confidence=low
|
|
||||||
|
|
||||||
### 0x2c9 `2C9` (2C9, argc 3)
|
### 0x2c9 `2C9` (2C9, argc 3)
|
||||||
- **summary:** Broader AGE-catalog compatibility stub; the port currently traces and skips it.
|
- **summary:** Broader AGE-catalog compatibility stub; the port currently traces and skips it.
|
||||||
- **grounding:** source=kelebek, confidence=med
|
- **grounding:** source=kelebek, confidence=med
|
||||||
|
|||||||
@@ -909,6 +909,27 @@ and true stop/release.
|
|||||||
**NEXT:** investigate INPUTNAME's `0x144`/`0x2c6`/`0x2c8` cluster as one modal name-entry and CP932
|
**NEXT:** investigate INPUTNAME's `0x144`/`0x2c6`/`0x2c8` cluster as one modal name-entry and CP932
|
||||||
string slice.
|
string slice.
|
||||||
|
|
||||||
|
**INPUTNAME string/input slice investigated (2026-07-29):** all three singleton handlers are now exact.
|
||||||
|
`0x2c6(out,string)` is Japanese-locale `_mbstrlen`; `0x2c8(out,string,start,count)` slices by CP932
|
||||||
|
multibyte-character positions while keeping lead/trail pairs intact. INPUTNAME uses them together to split
|
||||||
|
the current name into its eight script-owned display/edit cells.
|
||||||
|
|
||||||
|
`0x144(result_inout,initial_text)` is the separate native keyboard-entry button. AGE copies both strings
|
||||||
|
into bounded buffers and calls runtime host command 10. A read-only live probe resolved that callback to
|
||||||
|
`AGERC.DLL+0x1050`; the shipped DLL is now imported and annotated in Ghidra. Its command-10 resource dialog
|
||||||
|
initializes from operand 2, accepts at most 16 CP932 bytes, rejects every non-double-byte character, writes
|
||||||
|
valid accepted text to operand 1, and leaves operand 1 unchanged on cancel. This resolves the former
|
||||||
|
runtime-pointer uncertainty and also identifies AGERC as the owner of the previously studied command-8
|
||||||
|
LABEL service used by `0x140`.
|
||||||
|
|
||||||
|
The port has a bounded implementation seam: the two pure helpers use `VmOptions.NativeStringCodePage`,
|
||||||
|
while the modal op follows the existing diagnostic-message pattern (VM worker waits, Godot main thread owns
|
||||||
|
the dialog, accept/cancel signals completion). Implementing the trio removes 3 of the remaining 9 opcode
|
||||||
|
gaps and 3 of 11 instructions; no persistence or save-format work is involved.
|
||||||
|
|
||||||
|
**NEXT:** implement and test `0x144`/`0x2c6`/`0x2c8` together, including CP932 mixed-width helper cases,
|
||||||
|
the native 16-byte/full-width acceptance rules, accept/cancel behavior, and INPUTNAME's split/rejoin shape.
|
||||||
|
|
||||||
## Later Phase B breadth
|
## Later Phase B breadth
|
||||||
|
|
||||||
**INIT data-semantics side track started (2026-07-22).** Before naming more gameplay state, the static
|
**INIT data-semantics side track started (2026-07-22).** Before naming more gameplay state, the static
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ INFERRED: dict[int, dict] = {
|
|||||||
0x10c: dict(name='map-keyboard-scancode', category='input', noop=False, confidence='high', source='investigation', summary='(action)(dik_scan_code) - map a DirectInput keyboard scan code to a logical input action.'),
|
0x10c: dict(name='map-keyboard-scancode', category='input', noop=False, confidence='high', source='investigation', summary='(action)(dik_scan_code) - map a DirectInput keyboard scan code to a logical input action.'),
|
||||||
0x10d: dict(name='consume-mouse-wheel-delta', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return the accumulated signed mouse-wheel delta and clear it.'),
|
0x10d: dict(name='consume-mouse-wheel-delta', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return the accumulated signed mouse-wheel delta and clear it.'),
|
||||||
0x13a: dict(name='register-numeric-glyph-style', category='draw', noop=False, confidence='high', source='investigation', summary='Register one of 11 decimal-glyph atlas styles as (surface slot, source x/y, digit width/height).'),
|
0x13a: dict(name='register-numeric-glyph-style', category='draw', noop=False, confidence='high', source='investigation', summary='Register one of 11 decimal-glyph atlas styles as (surface slot, source x/y, digit width/height).'),
|
||||||
0x140: dict(name='coroutine-label-yield', category='control', noop=False, confidence='med', source='investigation', summary="(out)(name_str)(sub_str)(in) — scene-coroutine LOOP ITERATOR / labeled yield. Handler copies name/sub strings + the int operand and calls the NATIVE video/transition service (*DAT_005c6018)(8, ctx[0x54fe8], &{name,sub,in}); writes the returned PC-like value to operand 1. In SC0000 label_462 'ループ開始' (@0x46d): `out=G[0x6be]=LABEL('J',G[0x6be])`; loop runs the intro-setup body (incl. call label_125bd = slot-table fill G[0x3239..0x324e]=4..11) and jmps back until out==G[0x6c3] (a per-scene exit-PC immediate) → mov aba5c 0 → content. The gate G[0xaba5c]==1 that opens this loop is NATIVE scene-entry state (no script sets it to 1). DAT_005c6018 is runtime-resolved (all xrefs READ) = SAME class as the DirectDraw workers we don't model. PORT = HOST-MODEL IMPLEMENTED: synthesize the ADV scene-entry gate, run the LABEL/J setup body once, then return the structurally discovered per-scene terminal; do not emulate the video service. See engine-re.md §Scene-coroutine framework."),
|
0x140: dict(name='coroutine-label-yield', category='control', noop=False, confidence='med', source='investigation', summary="(out)(name_str)(sub_str)(in) — scene-coroutine LOOP ITERATOR / labeled yield. Handler copies name/sub strings + the int operand and calls AGERC host command 8 through g_pfnAgercHostCallback(8, ctx[0x54fe8], &{name,sub,in}); writes the returned PC-like value to operand 1. In SC0000 label_462 'ループ開始' (@0x46d): `out=G[0x6be]=LABEL('J',G[0x6be])`; loop runs the intro-setup body (incl. call label_125bd = slot-table fill G[0x3239..0x324e]=4..11) and jmps back until out==G[0x6c3] (a per-scene exit-PC immediate) → mov aba5c 0 → content. The gate G[0xaba5c]==1 that opens this loop is NATIVE scene-entry state (no script sets it to 1). PORT = HOST-MODEL IMPLEMENTED: synthesize the ADV scene-entry gate, run the LABEL/J setup body once, then return the structurally discovered per-scene terminal; do not emulate the service dialog. See engine-re.md §Scene-coroutine framework."),
|
||||||
0x143: dict(name='run-mounted-append-autoruns', category='control', noop=False, confidence='high', source='investigation', summary='() - enqueue record zero from every mounted nonzero AAI selector in ascending selector order, then execute those packed scripts serially before resuming the caller.'),
|
0x143: dict(name='run-mounted-append-autoruns', category='control', noop=False, confidence='high', source='investigation', summary='() - enqueue record zero from every mounted nonzero AAI selector in ascending selector order, then execute those packed scripts serially before resuming the caller.'),
|
||||||
0x199: dict(name='yield-adv-coroutine', category='control', noop=False, confidence='high', source='investigation', summary='Yield/re-enter the registered ADV coroutine handler. The fifth standard chrome button uses this transition to enter the HIDEWIN/window-hidden flow.'),
|
0x199: dict(name='yield-adv-coroutine', category='control', noop=False, confidence='high', source='investigation', summary='Yield/re-enter the registered ADV coroutine handler. The fifth standard chrome button uses this transition to enter the HIDEWIN/window-hidden flow.'),
|
||||||
0x19a: dict(name='get-message-skip', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return the current all-message skip state set by op 0x88.'),
|
0x19a: dict(name='get-message-skip', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return the current all-message skip state set by op 0x88.'),
|
||||||
|
|||||||
@@ -2914,12 +2914,12 @@ abi_source = "kelebek+decode-validated"
|
|||||||
[opcode.semantics]
|
[opcode.semantics]
|
||||||
name = "coroutine-label-yield"
|
name = "coroutine-label-yield"
|
||||||
category = "control"
|
category = "control"
|
||||||
summary = "(out)(name_str)(sub_str)(in) — scene-coroutine LOOP ITERATOR / labeled yield. Handler copies name/sub strings + the int operand and calls the NATIVE video/transition service (*DAT_005c6018)(8, ctx[0x54fe8], &{name,sub,in}); writes the returned PC-like value to operand 1. In SC0000 label_462 'ループ開始' (@0x46d): `out=G[0x6be]=LABEL('J',G[0x6be])`; loop runs the intro-setup body (incl. call label_125bd = slot-table fill G[0x3239..0x324e]=4..11) and jmps back until out==G[0x6c3] (a per-scene exit-PC immediate) → mov aba5c 0 → content. The gate G[0xaba5c]==1 that opens this loop is NATIVE scene-entry state (no script sets it to 1). DAT_005c6018 is runtime-resolved (all xrefs READ) = SAME class as the DirectDraw workers we don't model. PORT = HOST-MODEL IMPLEMENTED: synthesize the ADV scene-entry gate, run the LABEL/J setup body once, then return the structurally discovered per-scene terminal; do not emulate the video service. See engine-re.md §Scene-coroutine framework."
|
summary = "(out)(name_str)(sub_str)(in) — scene-coroutine LOOP ITERATOR / labeled yield. Handler copies name/sub strings + the int operand and calls AGERC host command 8 through g_pfnAgercHostCallback(8, ctx[0x54fe8], &{name,sub,in}); writes the returned PC-like value to operand 1. In SC0000 label_462 'ループ開始' (@0x46d): `out=G[0x6be]=LABEL('J',G[0x6be])`; loop runs the intro-setup body (incl. call label_125bd = slot-table fill G[0x3239..0x324e]=4..11) and jmps back until out==G[0x6c3] (a per-scene exit-PC immediate) → mov aba5c 0 → content. The gate G[0xaba5c]==1 that opens this loop is NATIVE scene-entry state (no script sets it to 1). PORT = HOST-MODEL IMPLEMENTED: synthesize the ADV scene-entry gate, run the LABEL/J setup body once, then return the structurally discovered per-scene terminal; do not emulate the service dialog. See engine-re.md §Scene-coroutine framework."
|
||||||
noop_headless = false
|
noop_headless = false
|
||||||
source = "investigation"
|
source = "investigation"
|
||||||
confidence = "med"
|
confidence = "med"
|
||||||
depends_on = []
|
depends_on = []
|
||||||
evidence = "Ghidra: handler 0x4299c0 (dispatch ctx[0x9b74c]=0x4299c0; created+typed EngineCtx*+annotated; Kelebek u0041F9C0 = VA-drift). Records the generic 9-dword instruction length; op2→local_204, op3→local_104, op4→local_208; (*DAT_005c6018)(8, ctx[0x54fe8], &local_210) → FUN_00425fb0(1,ret). DAT_005c6018: 6 xrefs all READ, no static writer; FUN_00405740 (screen-fade) calls it w/ cmd 3, branches on ret 1/2 = transition progress = native video service."
|
evidence = "Ghidra: handler 0x4299c0 (dispatch ctx[0x9b74c]=0x4299c0; created+typed EngineCtx*+annotated; Kelebek u0041F9C0 = VA-drift). Records the generic 9-dword instruction length; op2→local_204, op3→local_104, op4→local_208; g_pfnAgercHostCallback(8, ctx[0x54fe8], &local_210) → FUN_00425fb0(1,ret). A read-only probe resolves the callback to AGERC.DLL+0x1050; imported /support/AGERC.DLL identifies agerc_dispatch_host_command@0x100025f0 and its command-8 dialog-resource branch. FUN_00405740 calls the same dispatcher with command 3 and branches on return 1/2 for transition progress. Command 8's exact LABEL iterator calculation remains unresolved, so confidence remains medium."
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 1
|
i = 1
|
||||||
@@ -3016,28 +3016,34 @@ record-zero failure. Natural SYSTEM4 boot proves BTANINIT2 -> `$1$AUTORUN.BIN` -
|
|||||||
|
|
||||||
[[opcode]]
|
[[opcode]]
|
||||||
op = 0x144
|
op = 0x144
|
||||||
label = "u004259D0"
|
label = "edit-fullwidth-string-dialog"
|
||||||
argc = 2
|
argc = 2
|
||||||
abi_source = "kelebek+decode-validated"
|
abi_source = "kelebek+decode-validated"
|
||||||
|
|
||||||
[opcode.semantics]
|
[opcode.semantics]
|
||||||
name = "u004259D0"
|
name = "edit-fullwidth-string-dialog"
|
||||||
category = "unknown"
|
category = "input"
|
||||||
summary = ""
|
summary = "(result_inout)(initial_text) - synchronously open AGERC's modal full-width text editor. Accept writes at most eight valid CP932 double-byte characters to operand 1; cancel leaves operand 1 unchanged. Operand 2 supplies the initial edit text and is preserved."
|
||||||
noop_headless = false
|
noop_headless = false
|
||||||
source = "kelebek"
|
source = "investigation"
|
||||||
confidence = "low"
|
confidence = "high"
|
||||||
depends_on = []
|
depends_on = []
|
||||||
evidence = ""
|
evidence = "The real /v2 dispatch slot registers op_0x144_edit_fullwidth_string_dialog@0x42bdd0. It copies both resolved string operands into 0x400-byte buffers, calls the runtime host callback g_pfnAgercHostCallback with command 10 and owner HWND, then writes both returned buffers back. A read-only Frida probe of the pristine game resolved that callback to AGERC.DLL+0x1050. Imported /support/AGERC.DLL shows agerc_dispatch_host_command@0x100025f0 opening dialog resource 10 with agerc_fullwidth_text_dialog_proc@0x10002140: edit control 1006 is initialized from operand 2; IDOK rejects more than 16 bytes (`字数オーバーです`) or any non-DBCS cell (`半角文字は使用できません`) before copying the accepted text to operand 1; IDCANCEL closes without changing operand 1. INPUTNAME's sole site at 0xdcd passes its assembled current name in both operands, then resplits operand 1 through 0x2c6/0x2c8."
|
||||||
|
details = """
|
||||||
|
This is INPUTNAME's optional native keyboard-entry button, not the surrounding script-authored
|
||||||
|
character palette. The VM can use a synchronous host seam like the existing diagnostic dialog because
|
||||||
|
the Godot host runs script execution on its worker thread while the main thread owns the modal UI.
|
||||||
|
Compatibility requires the native full-width-only and 16-CP932-byte limits before accepting the result.
|
||||||
|
"""
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 1
|
i = 1
|
||||||
role = ""
|
role = "result/inout string"
|
||||||
observed_types = ["l-str"]
|
observed_types = ["l-str"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 2
|
i = 2
|
||||||
role = ""
|
role = "initial edit text"
|
||||||
observed_types = ["l-str"]
|
observed_types = ["l-str"]
|
||||||
|
|
||||||
[[opcode]]
|
[[opcode]]
|
||||||
@@ -6882,64 +6888,66 @@ observed_types = ["g-str", "l-str", "l-str-ptr"]
|
|||||||
|
|
||||||
[[opcode]]
|
[[opcode]]
|
||||||
op = 0x2c6
|
op = 0x2c6
|
||||||
label = "u0042B5E0"
|
label = "cp932-character-length"
|
||||||
argc = 2
|
argc = 2
|
||||||
abi_source = "kelebek+decode-validated"
|
abi_source = "kelebek+decode-validated"
|
||||||
|
|
||||||
[opcode.semantics]
|
[opcode.semantics]
|
||||||
name = "u0042B5E0"
|
name = "cp932-character-length"
|
||||||
category = "unknown"
|
category = "compute"
|
||||||
summary = ""
|
summary = "(out)(string) - write the Japanese-locale multibyte character count of the CP932 string, counting a valid lead/trail pair as one character."
|
||||||
noop_headless = false
|
noop_headless = false
|
||||||
source = "kelebek"
|
source = "investigation"
|
||||||
confidence = "low"
|
confidence = "high"
|
||||||
depends_on = []
|
depends_on = []
|
||||||
evidence = ""
|
evidence = "The real /v2 dispatch slot registers op_0x2c6_cp932_character_length@0x42a6d0. The handler sets LC_ALL to `japanese`, resolves operand 2, calls MSVC _mbstrlen, and writes the result to operand 1. INPUTNAME's sole site at 0x1002 uses this count as the loop bound before slicing each character with opcode 0x2c8."
|
||||||
|
details = "This is character count rather than .NET UTF-16 length or raw CP932 byte length. The implementation should use VmOptions.NativeStringCodePage and preserve valid CP932 multibyte boundaries."
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 1
|
i = 1
|
||||||
role = ""
|
role = "character count out"
|
||||||
observed_types = ["l-int"]
|
observed_types = ["l-int"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 2
|
i = 2
|
||||||
role = ""
|
role = "source string"
|
||||||
observed_types = ["l-str"]
|
observed_types = ["l-str"]
|
||||||
|
|
||||||
[[opcode]]
|
[[opcode]]
|
||||||
op = 0x2c8
|
op = 0x2c8
|
||||||
label = "u0042B610"
|
label = "cp932-substring"
|
||||||
argc = 4
|
argc = 4
|
||||||
abi_source = "kelebek+decode-validated"
|
abi_source = "kelebek+decode-validated"
|
||||||
|
|
||||||
[opcode.semantics]
|
[opcode.semantics]
|
||||||
name = "u0042B610"
|
name = "cp932-substring"
|
||||||
category = "unknown"
|
category = "compute"
|
||||||
summary = ""
|
summary = "(out)(string)(start)(count) - copy a CP932 substring selected by multibyte-character index and count without splitting valid lead/trail pairs."
|
||||||
noop_headless = false
|
noop_headless = false
|
||||||
source = "kelebek"
|
source = "investigation"
|
||||||
confidence = "low"
|
confidence = "high"
|
||||||
depends_on = []
|
depends_on = []
|
||||||
evidence = ""
|
evidence = "The real /v2 dispatch slot registers op_0x2c8_cp932_substring@0x42c420. It copies operand 2 into a 256-byte buffer, sets LC_ALL to `japanese`, obtains _mbstrlen, reads start and count, clamps end=start+count to the character length when end is below 1 or beyond that length, and walks bytes with _mbbtype so CP932 lead/trail pairs are copied together. It writes the selected byte interval back through operand 1. INPUTNAME's sole site at 0x1021 loops substring(name,index,1) into its eight local character cells."
|
||||||
|
details = "The release call uses nonnegative in-range indices and count 1. A compatible general implementation should reproduce native end clamping (`end = length` when start+count < 1 or > length) and select the half-open character interval [start,end)."
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 1
|
i = 1
|
||||||
role = ""
|
role = "substring out"
|
||||||
observed_types = ["l-str-ptr"]
|
observed_types = ["l-str-ptr"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 2
|
i = 2
|
||||||
role = ""
|
role = "source string"
|
||||||
observed_types = ["l-str"]
|
observed_types = ["l-str"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 3
|
i = 3
|
||||||
role = ""
|
role = "start character index"
|
||||||
observed_types = ["l-int"]
|
observed_types = ["l-int"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 4
|
i = 4
|
||||||
role = ""
|
role = "character count"
|
||||||
observed_types = ["imm"]
|
observed_types = ["imm"]
|
||||||
[[opcode]]
|
[[opcode]]
|
||||||
op = 0x4
|
op = 0x4
|
||||||
|
|||||||
Reference in New Issue
Block a user