Load shared save preview metadata
This commit is contained in:
@@ -1708,6 +1708,17 @@ entry 1 equal to 81, 83 extended values, and the nine-DWORD reserved tail. The p
|
||||
file exactly; catalog/extended/tail sections remain opaque and are preserved losslessly rather than
|
||||
reinterpreted as mod state.
|
||||
|
||||
`SAVE.BIN` also proves why a numbered `.DAT`/`.STH` pair alone cannot reproduce a complete menu row.
|
||||
The numbered fixed header supplies only timestamp and accumulated playtime, and `.STH` supplies the
|
||||
112x84 screenshot. The remaining preview record is maintained through selected-cell ops in shared
|
||||
`SAVE.DAT`: three parallel 210-cell string banks hold chapter/title (`GStr[0x0+]`), location
|
||||
(`GStr[0xd2+]`), and protagonist name (`GStr[0x1a4+]`); eight 210-cell integer banks beginning at
|
||||
`GInt[0x5]`, `0xd7`, `0x1a9`, `0x27b`, `0x34d`, `0x41f`, `0x4f1`, and `0x5c3` hold portrait entity,
|
||||
level, training count, growth, personality, difficulty/mode badge, cleared-ending mask, and installed
|
||||
append mask respectively. Save and stage-select paths snapshot these cells with `0x1a2`/`0x1a9`;
|
||||
the menu restores them with `0x1a3`/`0x1aa`. For the NG+ history display, `SAVE.BIN` scans bits 0..14
|
||||
of the restored `GInt[0x4f1 + slot]` mask and draws one 17x17 ending badge for every set bit.
|
||||
|
||||
#### Common `.DAT` container
|
||||
|
||||
Both shared and numbered `.DAT` payloads use the same native container. The fixed header is exactly
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- DO NOT EDIT -- generated from vm-map/globals.toml by tools/globals_build.py --build -->
|
||||
# Global Variable Reference (generated)
|
||||
|
||||
4278 globals (435 curated, 3843 auto shape-inferred). Source of truth: `vm-map/globals.toml`.
|
||||
4278 globals (445 curated, 3833 auto shape-inferred). Source of truth: `vm-map/globals.toml`.
|
||||
|
||||
## choice-output
|
||||
|
||||
@@ -51,6 +51,14 @@
|
||||
|
||||
| address | name | conf | source | usage |
|
||||
|---|---|---|---|---|
|
||||
| `0x5` | save_slot_portrait_entity_indices | high | investigation | SAVE and SELSTAGE snapshot current_entity_index through op 0x1a2. SAVE.BIN restores the slot cell with op 0x1a3 and uses its form range when choosing the portrait atlas region. |
|
||||
| `0xd7` | save_slot_protagonist_levels | high | investigation | SAVE and SELSTAGE copy unit_current_levels[current_entity_index] into this shared SAVE.DAT-selected bank. SAVE.BIN restores and renders it as the row's LV value. |
|
||||
| `0x1a9` | save_slot_training_action_counts | high | investigation | SAVE and SELSTAGE snapshot training_action_total_execution_count into this shared SAVE.DAT-selected per-slot bank; copy/move/delete operations keep it aligned with the rest of the preview record. |
|
||||
| `0x27b` | save_slot_growth_values | high | investigation | SAVE and SELSTAGE snapshot familiar_training_progress through op 0x1a2. SAVE.BIN restores and renders it as the row's growth value. |
|
||||
| `0x34d` | save_slot_personality_values | high | investigation | SAVE and SELSTAGE snapshot familiar_alignment through op 0x1a2. SAVE.BIN restores and renders the signed value in the row's personality field. |
|
||||
| `0x41f` | save_slot_difficulty_indices | high | investigation | SAVE snapshots difficulty_index through op 0x1a2. SAVE.BIN restores the per-slot value and selects the corresponding 34x17 row badge from SO010. |
|
||||
| `0x4f1` | save_slot_cleared_ending_masks | high | investigation | SAVE snapshots the current cleared-ending inheritance mask through op 0x1a2. SAVE.BIN restores it from shared SAVE.DAT, scans bits 0..14, and draws one 17x17 badge for every achieved ending on that slot and subsequent inherited-loop saves. |
|
||||
| `0x5c3` | save_slot_append_install_masks | high | investigation | SAVE snapshots the current installed-append mask through op 0x1a2. SAVE.BIN compares each saved bit against the current mask and marks previews whose required append data is missing. |
|
||||
| `0x6d3` | story_event_flags | high | investigation | Shared one-based story/event flag bank. Progression, recruitment, item, and stage logic read or write individual cells; STINIT object prerequisite ids are decremented by one before SETOBJ tests this array. |
|
||||
| `0x2e49` | character_voice_suppressed | high | investigation | Base of the per-character voice enable/suppress settings. INITCONFIG zero-fills all 13 cells and registers each with the shared profile service; LOADCONFIG restores them. CONFIG indexes the table to preview a character voice and write 0/1. ROOM reads cell 0 before assigning its selected greeter's greeting/farewell voice ids, so the port's former scalar interpretation of zero-int-range (writing 13 into the base cell) suppressed those voices on every natural boot. This names the script-visible setting array without choosing a persistence backend for op 0x1a2/0x1a3. |
|
||||
| `0x3239` | adv_layer_surface_slots | high | investigation | Shared ADV graphics-layer surface-slot registry. Scene setup initializes the three banks. The CG loader uses the primary slot for a fresh retained object, alternates between columns zero and one when replacing an already-bound layer, and uses column two for the transition/crossfade surface and cleanup. The corpus has 2,657 table-base accesses across 309 scripts. Columns: 0=primary_surface_slot, 1=alternate_surface_slot, 2=transition_surface_slot. |
|
||||
@@ -346,15 +354,7 @@
|
||||
| `0x15a1e0` | character_profile_portrait_x_offsets | high | investigation | INFOCH adds the selected cell to the centered portrait x coordinate. The 100-cell spacing to the adjacent CIINIT arrays and the direct indexed reader establish the reserved per-profile placement column. |
|
||||
| `0x15a244` | character_profile_portrait_y_offsets | high | investigation | INFOCH adds the selected cell to the bottom-aligned portrait y coordinate. The 100-cell spacing to the adjacent CIINIT arrays and the direct indexed reader establish the reserved per-profile placement column. |
|
||||
| `0x15a2a9` | glossary_topic_unlock_seen_decision_ids | high | investigation | VIINIT's three unlock prerequisites per glossary topic. INFOVO subtracts one from each positive value and exposes the topic when any referenced scene_decision_seen_flags cell is set; debug modes expose the same populated topics unconditionally. Columns: 0=unlock_seen_decision_1, 1=unlock_seen_decision_2, 2=unlock_seen_decision_3. |
|
||||
| `0x5` | — | low | auto-shape | array |
|
||||
| `0xd2` | — | low | auto-shape | array |
|
||||
| `0xd7` | — | low | auto-shape | array |
|
||||
| `0x1a4` | — | low | auto-shape | array |
|
||||
| `0x1a9` | — | low | auto-shape | array |
|
||||
| `0x2e2` | — | low | auto-shape | array |
|
||||
| `0x41f` | — | low | auto-shape | array |
|
||||
| `0x4f1` | — | low | auto-shape | array |
|
||||
| `0x5c3` | — | low | auto-shape | array |
|
||||
| `0x69e` | — | low | auto-shape | array |
|
||||
| `0x6fe` | — | low | auto-shape | array |
|
||||
| `0x712` | — | low | auto-shape | array |
|
||||
@@ -504,6 +504,8 @@
|
||||
|
||||
| address | name | conf | source | usage |
|
||||
|---|---|---|---|---|
|
||||
| `0xd2` | save_slot_location_names | high | investigation | SAVE and SELSTAGE snapshot the current location label into this shared SAVE.DAT-selected string bank. SAVE.BIN restores it with op 0x1aa for the row's location field. |
|
||||
| `0x1a4` | save_slot_protagonist_names | high | investigation | SAVE and SELSTAGE snapshot the active familiar's display name into this shared SAVE.DAT-selected string bank. SAVE.BIN restores it with op 0x1aa beside the portrait. |
|
||||
| `0x27e` | unit_class_titles | high | investigation | Persistent per-unit class/title string table. CALCCC writes the selected class_change_title_output into the current unit's cell; character and status presentation scripts read the resulting title. |
|
||||
| `0x315` | unit_story_display_names | high | investigation | CNINIT's sparse unit-id keyed story-name table. Scene scripts and HISTORY draw the selected speaker's value, DEBUGADV uses it for its scripted speaker previews, and INPUTNAME rejects a player-entered familiar name that collides with any populated row. The table intentionally leaves Lily's form ids 2..4 empty. |
|
||||
| `0x7db` | modal_message_lines | high | investigation | Shared ten-string modal buffer. Producers append messages or menu options at modal_message_line_count; MES measures and draws each string, and SBUNKI reuses the same entries for an interactive selection list. |
|
||||
@@ -533,7 +535,6 @@
|
||||
| `0x278` | — | med | auto-shape | string-table (written by FIELD) |
|
||||
| `0x279` | — | med | auto-shape | string-table (written by INPUTNAME) |
|
||||
| `0x27a` | — | med | auto-shape | string-table (written by READY) |
|
||||
| `0x27b` | — | med | auto-shape | string-table (written by READY) |
|
||||
| `0x27c` | — | med | auto-shape | string-table (written by READY) |
|
||||
| `0x27d` | — | med | auto-shape | string-table (written by READY) |
|
||||
| `0x316` | — | med | auto-shape | string-table (written by CNINIT) |
|
||||
@@ -589,7 +590,6 @@
|
||||
| `0x349` | — | med | auto-shape | string-table (written by CNINIT) |
|
||||
| `0x34b` | — | med | auto-shape | string-table (written by CNINIT) |
|
||||
| `0x34c` | — | med | auto-shape | string-table (written by CNINIT) |
|
||||
| `0x34d` | — | med | auto-shape | string-table (written by CNINIT) |
|
||||
| `0x34e` | — | med | auto-shape | string-table (written by CNINIT) |
|
||||
| `0x34f` | — | med | auto-shape | string-table (written by CNINIT) |
|
||||
| `0x350` | — | med | auto-shape | string-table (written by CNINIT) |
|
||||
|
||||
@@ -3510,15 +3510,24 @@ executes `0x1a1`, runs `CALLBACK_LOAD.BIN`, and reaches the saved script's activ
|
||||
A second, read-only compatibility gate points the same real-script path at the installed Himegari
|
||||
`SAVE00.DAT`. It decodes the complete native layout, resolves the installed save's first persisted script
|
||||
through the mounted SYS4 catalogs, and enters that frame with `FrameCause.SaveRestore`; the test stops at
|
||||
that boundary before gameplay continues and never writes to the original AppData tree. No codec, VM, or
|
||||
script-control correction was required by these gates.
|
||||
that boundary before gameplay continues and never writes to the original AppData tree.
|
||||
|
||||
The Godot profile remains intentionally isolated at `user://SAVE`. For visual acceptance, a copied
|
||||
`SAVE00.DAT`/`.STH` pair can be placed there without exposing the original save directory to writes.
|
||||
JSON inspection/export, namespaced mod state, migrations, and richer import UX remain extended-mode work.
|
||||
The first visual acceptance run exposed an incomplete-fixture/lifecycle issue rather than a numbered
|
||||
codec error. A numbered pair carries the fixed timestamp/playtime header and screenshot, but `SAVE.BIN`
|
||||
loads its chapter, location, protagonist name, level, growth, personality, difficulty badge, 15-bit
|
||||
cleared-ending/NG+ mask, and append-install mask from slot-indexed selected cells in shared `SAVE.DAT`.
|
||||
Godot had injected the store without loading `SharedProfile`, so those `0x1a3`/`0x1aa` reads correctly
|
||||
returned zero/empty. Startup now loads shared `SAVE.DAT` and `RT.DAT` before constructing the gameplay VM
|
||||
(self-test remains isolated), and the real-script regression covers the three preview strings, numeric
|
||||
glyph values, and one 17x17 badge per set ending bit.
|
||||
|
||||
Validation: all 386 engine tests pass, opcode lint reports zero errors/warnings, the Godot C# build has
|
||||
zero warnings, and the threaded headless run reports `SELFTEST OK`.
|
||||
The Godot profile remains intentionally isolated at `user://SAVE`. Visual compatibility therefore uses
|
||||
copied `SAVE00.DAT`/`.STH`, `SAVE.DAT`, and `RT.DAT` files without exposing the original save directory
|
||||
to writes. JSON inspection/export, namespaced mod state, migrations, and richer import UX remain
|
||||
extended-mode work.
|
||||
|
||||
Validation: all 386 engine tests pass, global/opcode lint reports zero errors/warnings, the Godot C#
|
||||
build has zero warnings, and the threaded headless run reports `SELFTEST OK`.
|
||||
|
||||
## Data-semantics sidebar: focused append EBINIT inspection (2026-07-24)
|
||||
|
||||
|
||||
@@ -101,12 +101,26 @@ public class SaveUiIntegrationTests
|
||||
}
|
||||
store.SaveNumberedThumbnail(
|
||||
0, NumberedThumbnailCodec.Encode(new(112, 84, pixels)));
|
||||
var authoredProfile = new SharedProfile();
|
||||
authoredProfile.StoreString(0x000, "序章 封印、そして");
|
||||
authoredProfile.StoreString(0x0d2, "base part-time job");
|
||||
authoredProfile.StoreString(0x1a4, "Lily");
|
||||
authoredProfile.StoreInteger(0x0d7, 80);
|
||||
authoredProfile.StoreInteger(0x27b, 98);
|
||||
authoredProfile.StoreInteger(0x34d, 69);
|
||||
authoredProfile.StoreInteger(0x41f, 0);
|
||||
authoredProfile.StoreInteger(0x4f1, 0b1011);
|
||||
authoredProfile.Save(
|
||||
store, new NativeSystemTime(2026, 7, 5, 24, 13, 42, 17, 321), 7_445);
|
||||
var loadedProfile = new SharedProfile();
|
||||
Assert.True(loadedProfile.Load(store));
|
||||
|
||||
var scripts = Sys4ScriptProvider.Load(Table);
|
||||
var host = new StopAtFirstMenuPollHost();
|
||||
var vm = new VirtualMachine(
|
||||
scripts.RequireByName("SAVE.BIN"), Table, host,
|
||||
new VmOptions(MaxSteps: 500_000), scripts,
|
||||
sharedProfile: loadedProfile,
|
||||
nativeDatStore: store);
|
||||
|
||||
Assert.Throws<MenuReadyException>(() => vm.Run());
|
||||
@@ -118,6 +132,15 @@ public class SaveUiIntegrationTests
|
||||
Assert.Contains(host.SurfaceStrings, item => item.Text == "07");
|
||||
Assert.Contains(host.SurfaceStrings, item => item.Text == "24");
|
||||
Assert.Contains(host.SurfaceStrings, item => item.Text == "13");
|
||||
Assert.Contains(host.SurfaceStrings, item => item.Text == "序章 封印、そして");
|
||||
Assert.Contains(host.SurfaceStrings, item => item.Text == "base part-time job");
|
||||
Assert.Contains(host.SurfaceStrings, item => item.Text == "Lily");
|
||||
var objects = vm.Gfx.SnapshotVisibleObjects().ToDictionary(item => item.Handle);
|
||||
Assert.Equal((0, 96), (objects[0x13137].SrcX, objects[0x13138].SrcX)); // level 80
|
||||
Assert.Equal((96, 108), (objects[0x13146].SrcX, objects[0x13147].SrcX)); // growth 98
|
||||
Assert.Equal((108, 72), (objects[0x13155].SrcX, objects[0x13156].SrcX)); // personality 69
|
||||
Assert.Equal(3, host.TextureDraws.Count(
|
||||
item => item.Slot == 193 && item.Width == 17 && item.Height == 17));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -191,11 +214,15 @@ public class SaveUiIntegrationTests
|
||||
[(0x2, Array.Empty<Operand>())], []), 0x00fefefd);
|
||||
var provider = new SaveUiProvider(nativeScripts, null, loadCallback);
|
||||
var host = new ClickFirstSlotHost();
|
||||
var store = new DirectoryNativeDatStore(root, Identity);
|
||||
var sharedProfile = new SharedProfile();
|
||||
Assert.True(sharedProfile.Load(store));
|
||||
var vm = new VirtualMachine(
|
||||
nativeScripts.RequireByName("SAVE.BIN"), Table, host,
|
||||
new VmOptions(MaxSteps: 1_000_000), provider,
|
||||
new StopAtInstalledResumeSink(),
|
||||
nativeDatStore: new DirectoryNativeDatStore(root, Identity));
|
||||
sharedProfile: sharedProfile,
|
||||
nativeDatStore: store);
|
||||
host.Vm = vm;
|
||||
vm.Globals[0x6241b] = 1;
|
||||
vm.Globals[0x696] = 0;
|
||||
|
||||
@@ -27,6 +27,8 @@ internal class RecordingHost : IHost
|
||||
public readonly List<SurfaceRectFill> SurfaceFills = new();
|
||||
public readonly List<SurfaceRectCopy> SurfaceCopies = new();
|
||||
public readonly List<(long First, long Count)> PresentedRanges = new();
|
||||
public readonly List<(int Slot, int SourceX, int SourceY, int Width, int Height, int X, int Y)>
|
||||
TextureDraws = new();
|
||||
public readonly List<AdvWaitIndicatorConfig> WaitIndicators = new();
|
||||
public readonly List<bool> WaitIndicatorEnabledChanges = new();
|
||||
public readonly List<int> PublishedAdvTextLayouts = new();
|
||||
@@ -144,7 +146,8 @@ internal class RecordingHost : IHost
|
||||
public void SetTexture(long resId, int slot) => Textures.Add((resId, slot));
|
||||
public void ClearRenderTarget(int surfaceSlot) => ClearedRenderTargets.Add(surfaceSlot);
|
||||
public void ReleaseSurfaceRange(int firstSlot, int count) => ReleasedSurfaceRanges.Add((firstSlot, count));
|
||||
public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { }
|
||||
public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy)
|
||||
=> TextureDraws.Add((slot, sx, sy, w, h, dx, dy));
|
||||
public (int Width, int Height) GetTextureSize(int slot) => (0, 0);
|
||||
public void PlayBgm(long id) { }
|
||||
public void PlayVoice(long id) => Voices.Add(id);
|
||||
|
||||
@@ -257,8 +257,11 @@ public partial class Main : Godot.Control
|
||||
new NativeSaveIdentity(
|
||||
NativeSaveMagic.S4SD, 0x4a343234, "姫狩りダンジョンマイスター",
|
||||
SaveVersion1: 3, SaveVersion2: 10, NumberedCompatibilityId: 0x42323234));
|
||||
var sharedProfile = new SharedProfile();
|
||||
if (!_selftest) sharedProfile.Load(nativeSaveStore);
|
||||
_vm = new VirtualMachine(script, table, _host,
|
||||
new VmOptions(MaxSteps: 20_000_000, IgnoreExitRequests: nativeDebugMenu), provider, sink,
|
||||
sharedProfile: sharedProfile,
|
||||
nativeDatStore: nativeSaveStore);
|
||||
if (scripts != null)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,116 @@
|
||||
[meta]
|
||||
note = "Curated global addresses override the auto shape-inference map (build/global-var-map.json)."
|
||||
|
||||
[[global]]
|
||||
address = "0x0"
|
||||
name = "save_slot_chapter_titles"
|
||||
category = "string-table"
|
||||
type = "string[210]"
|
||||
value_domain = "per-slot chapter/title preview text; empty means no authored preview"
|
||||
usage = "SAVE and SELSTAGE snapshot the current chapter/title into this shared SAVE.DAT-selected string bank. SAVE.BIN restores the indexed cell with op 0x1aa and draws it at the top of each populated row; it is not stored in the numbered DAT header."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0xd2"
|
||||
name = "save_slot_location_names"
|
||||
category = "string-table"
|
||||
type = "string[210]"
|
||||
value_domain = "per-slot player-facing location/stage name"
|
||||
usage = "SAVE and SELSTAGE snapshot the current location label into this shared SAVE.DAT-selected string bank. SAVE.BIN restores it with op 0x1aa for the row's location field."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x1a4"
|
||||
name = "save_slot_protagonist_names"
|
||||
category = "string-table"
|
||||
type = "string[210]"
|
||||
value_domain = "per-slot protagonist/familiar display name"
|
||||
usage = "SAVE and SELSTAGE snapshot the active familiar's display name into this shared SAVE.DAT-selected string bank. SAVE.BIN restores it with op 0x1aa beside the portrait."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x5"
|
||||
name = "save_slot_portrait_entity_indices"
|
||||
category = "data-table"
|
||||
type = "int[210]"
|
||||
value_domain = "runtime entity/form index used to select the save-row portrait"
|
||||
usage = "SAVE and SELSTAGE snapshot current_entity_index through op 0x1a2. SAVE.BIN restores the slot cell with op 0x1a3 and uses its form range when choosing the portrait atlas region."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0xd7"
|
||||
name = "save_slot_protagonist_levels"
|
||||
category = "data-table"
|
||||
type = "int[210]"
|
||||
value_domain = "nonnegative unit level"
|
||||
usage = "SAVE and SELSTAGE copy unit_current_levels[current_entity_index] into this shared SAVE.DAT-selected bank. SAVE.BIN restores and renders it as the row's LV value."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x1a9"
|
||||
name = "save_slot_training_action_counts"
|
||||
category = "data-table"
|
||||
type = "int[210]"
|
||||
value_domain = "nonnegative accumulated training-action count"
|
||||
usage = "SAVE and SELSTAGE snapshot training_action_total_execution_count into this shared SAVE.DAT-selected per-slot bank; copy/move/delete operations keep it aligned with the rest of the preview record."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x27b"
|
||||
name = "save_slot_growth_values"
|
||||
category = "data-table"
|
||||
type = "int[210]"
|
||||
value_domain = "familiar training progress"
|
||||
usage = "SAVE and SELSTAGE snapshot familiar_training_progress through op 0x1a2. SAVE.BIN restores and renders it as the row's growth value."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x34d"
|
||||
name = "save_slot_personality_values"
|
||||
category = "data-table"
|
||||
type = "int[210]"
|
||||
value_domain = "signed familiar alignment/personality value"
|
||||
usage = "SAVE and SELSTAGE snapshot familiar_alignment through op 0x1a2. SAVE.BIN restores and renders the signed value in the row's personality field."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x41f"
|
||||
name = "save_slot_difficulty_indices"
|
||||
category = "data-table"
|
||||
type = "int[210]"
|
||||
value_domain = "difficulty/mode badge index"
|
||||
usage = "SAVE snapshots difficulty_index through op 0x1a2. SAVE.BIN restores the per-slot value and selects the corresponding 34x17 row badge from SO010."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x4f1"
|
||||
name = "save_slot_cleared_ending_masks"
|
||||
category = "data-table"
|
||||
type = "int[210]"
|
||||
value_domain = "15-bit ending/NG+ inheritance mask; bit i draws ending badge i"
|
||||
usage = "SAVE snapshots the current cleared-ending inheritance mask through op 0x1a2. SAVE.BIN restores it from shared SAVE.DAT, scans bits 0..14, and draws one 17x17 badge for every achieved ending on that slot and subsequent inherited-loop saves."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x5c3"
|
||||
name = "save_slot_append_install_masks"
|
||||
category = "data-table"
|
||||
type = "int[210]"
|
||||
value_domain = "32-bit installed append-selector mask at save time"
|
||||
usage = "SAVE snapshots the current installed-append mask through op 0x1a2. SAVE.BIN compares each saved bit against the current mask and marks previews whose required append data is missing."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x8c877"
|
||||
name = "current_item_id"
|
||||
|
||||
Reference in New Issue
Block a user