Repository navigation
fix(cheats): keep the teleport minimap repair in saved games - #2646
Conversation
Complete the live-state repair from NotRexed#2402 by requesting the game-data change through the engine Bool setter. A direct live-byte clear leaves the serialized value unchanged, so the minimap disappears again after a save and reload. Keep the existing accepted-teleport guard and age-selection behavior. Extend the game-free fixture with separate live and saved state, an engine update, reload, refused requests and missing bindings. Refs NotRexed#2402 Refs NotRexed#2588 Assisted-by: GPT-6 Astra Co-Authored-By: GPT-6 Astra <noreply@openai.com>
hckrman101
left a comment
There was a problem hiding this comment.
Thanks, this is a clean follow-up to #2402: same accepted-request guard, but the clear now goes through the game's own setter instead of poking the live byte, so the save's copy follows. The save → fresh-restart run in the description is the evidence that counts here, and the fixture now models live and saved state separately, so it fails on main's source and passes on this one.
Checked:
- Registers:
*c = savedbefore and after the setter call leaves the caller's context as it was; the setter runs on the caller's SP, like the other GameData calls here. - The guard is unchanged: a throttled or refused teleport, or an answer of 0 from the event manager, doesn't queue anything (the test covers each case).
- No setter binding means no write and no "restore queued" line, instead of claiming a repair. Good.
- CI: the failing Python checks are the same set main fails right now (test_env_on, test_menu_i18n, test_hdr_encode, test_linux_docker_packages, test_mouse_native, plus the fixtures #2648 repairs).
test_teleport_minimap_flag.pypasses on both Linux parts.
Non-blocking, for a follow-up:
- Switch age writes
Sequence_IsChildhoodwith the same live-onlyoot_gamedata_set_bool. If your finding holds for every Bool, a System → Save after Switch age would store the old age's saved copy. The description says Switch age wasn't tested as a runtime action. Could you check it once in a later PR (switch age, save, restart)? If it's the same bug, queuing the setter alongside the live write (the destination still needs the live value straight away) would fix it. - Nit: the comment above
oot_gamedata_set_boolstill just says it writes the bool directly. Worth adding "live value only, a save keeps the old one" so nobody picks it for a flag that has to persist.
Approving.
| set_bool(c); | ||
| *c = saved; | ||
| hos_log("cheats: teleport: the area left had hidden the minimap (MapIconDeactivateByAreaActor): restore queued"); | ||
| } |
There was a problem hiding this comment.
Nit: when the setter isn't bound, this does nothing and logs nothing. A line like ...minimap: setter not found, left hidden would make a bug report from a different game build easier to read. Not blocking.
There was a problem hiding this comment.
Done in 3eb1591b: with the setter or the game data manager not found it now logs cheats: teleport: the area left had hidden the minimap (MapIconDeactivateByAreaActor): the game's Bool setter not found, left hidden (or the game data manager not found), and the fixture's missing-binding case expects that line and no restore queued. That check fails on the commit before it.
Review of NotRexed#2646: with the game's Bool setter or the game data manager not found (another game build), the teleport left the minimap hidden and logged nothing. It now says which of the two was not found. The test expects that line and no "restore queued" in that case. Refs NotRexed#2588 Assisted-by: Claude Fable 5.2 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
What this is for: keep the minimap restored after saving and restarting following a Debug teleport (#2588). What is measured: Linux / RTX 4090, main
09aac439versus4b2388fc: the live flag, the game's own saved flag, and inspected pictures before teleport, after teleport, and after a fresh process restart. Not measured: frame rates, Windows/AMD/Steam Deck, the reporter's save, or the exact Lake Hylia route that originally set the flag.Problem
This completes @jarynclouatre's approach in #2402, based on @Zarigis's flag diagnosis in #2217. The existing accepted-teleport guard is right; the remaining problem is how the flag is written.
Two separate results on main:
MapIconDeactivateByAreaActor, and the minimap appears again. The log saysthe area left had hidden the minimap ... shown again.The existing helper writes only the Bool entry's live byte. The engine also keeps a saved copy and update bookkeeping. The normal Bool setter at
0x806a2b20takes(manager, value, hash)and queues the change through that machinery. The queue consumer updates the live and saved values, or marks a pending saved update; a direct byte write bypasses it. Sources:host/hos_main.con main, the local binding trace, and the save/reload comparison below; no generated game code is included.What changed
host/hos_main.c: after the same accepted-request check, call the engine's Bool setter for the existing minimap-suppression hash instead of the live-only helper. Preserve the caller's registers and logrestore queued, matching the deferred operation.tests/test_teleport_minimap_flag.py: keep the existing request/refusal coverage and give the fixture separate live and saved state, an engine-update step and a reload. Also check setter arguments, register restoration, and an unavailable setter binding.--sourceallows the same test to exercise main's implementation.readme.md, the debug tools paragraph: how a save that already lost its minimap is mended.The destination/event path, interface settings, and refusal behavior are unchanged. A destination can still hide its own minimap. The age switch's immediate live update remains unchanged because the destination choice immediately reads the new age; the minimap repair in its shared teleport path uses the engine setter. Sources:
host/hos_main.c:1001-1015,1030-1076at4b2388fc.How to recover an affected save with this change
Load it, use Debug → Teleport → Hyrule Field, wait for gameplay to resume, then System → Save. The native save and fresh restart in the fixed runs below retain the minimap. Older save slots are not rewritten; repeat the recovery if loading another affected slot.
How it was tested
The runs below were made on
4b2388fcover main09aac439. The branch has since been rebased onto mainde866017as03a63ea3(with the recovery note moved from the developer notes to the readme's debug tools paragraph); the regression test was run again there with GCC and Clang (passes) and against main'shost/hos_main.c(fails with both).Arch Linux, kernel 7.2.15-1-omarchy, RTX 4090, NVIDIA 615.78.08; headless, 2048×1152 output, 1280×720 captures, frame generation off. Main
09aac43907a90ae62c8ccd98c77b471d2b94eac2; fix4b2388fc77f1f5eb078531ab51171294a0007b28. Runs on 11 November 2026, local UTC−06:00. Prepared caches were reused and shader precompilation disabled for these runs. Sources: both build logs and the runs'hookshot_log.txt/ recorded environments.Game-free regression
Both GCC 16.2.1 and Clang 23.1.3:
09aac439a native save after teleport kept the minimap hidden;the minimap disappeared again after a save and reload4b2388fcaccepted teleport repairs live and saved minimap state; refusals and missing bindings leave it aloneThe fixture is Linux-only, as before; it needs no game files. Source:
tests/test_teleport_minimap_flag.pyand the captured GCC/Clang regression output.Whole
tests/run_all.py, once withCXX=g++: 453 passed, 3 failed, 20 skipped, including a passing minimap test. The failures are outside the changed implementation:nx2/test_depth_sample_types.pyandnx2/test_unsigned_image_types.py: their C++20 builds reject the unchanged assertion header's static variable inside a constexpr function.tests/test_env_on.py: unchangedHOS_FPS_LOGinhost/oot_high_fps.c:16still uses set-means-on behavior. (Main's failure at that base; since fixed by fix(fps): HOS_FPS_LOG read by the switches' rule, so test_env_on passes on main again #2575.)Those failures were retained, not patched or rerun here; no new full-main baseline was run. Source: the full-suite output, ending with
453 passed, 3 failed, 20 skippedandNo coredumps found.In the game
A normal main run from Hyrule Field through the Lake Hylia debug destination and then Lost Woods kept its minimap. To test an already affected save reproducibly, a copy of a local test save had only the previously reported suppression flag set. This is controlled reproduction of the persistent-flag case, not reproduction of the original area trigger. Sources: inspected normal-route captures and the asserted one-byte save preparation.
Sources: per-run logs, read-only flag samples, native saved-file inspection, and the corresponding inspected pictures. All four runs ended normally, with no fatal/crash/device-lost, Xid/cache-operation or NVRM lines and no core dumps. They were shared runs: no performance claim. Start → end load averages (1/5/15 minute) were respectively
31.34/14.47/12.45 → 10.10/13.48/12.68,10.15/9.55/10.30 → 7.76/9.05/10.09,66.19/28.82/22.11 → 6.80/18.64/19.76, and7.62/9.02/14.16 → 7.62/8.84/13.88(recorded run summaries).The fixed run's log contains:
One scripting mistake is retained in the evidence: the first-use map screen was still open, so one teleport request timed out without being taken. After inspecting and closing the menu, the same process completed the repair and native save. Opening and closing the actual full map left the stuck flag at 1; it was not a recovery shortcut in this test. Sources: the request replies, map-page captures, and read-only flag samples.
Pictures and captions
Minimap before teleport, after arrival at Lake Hylia, and after teleporting to Lost Woods.
Main's temporary restoration; loss after loading its native save; fixed restoration; minimap still present after native Save and a fresh restart.
Every frame in both labelled comparisons was inspected.
Not tested
The reporter's exact save/route, a naturally entered map-hiding area, the v2.1.0 binary itself, a 90-fps cap, Windows, AMD, Steam Deck, physical controllers, and Switch age as a runtime action. The save was synthetic only at the initial stuck-flag setup; all subsequent saves in the comparison were made by the game.
Risks
The binding is for the already supported game build, like the adjacent teleport bindings. The change is queued rather than synchronously forcing the live byte; the game owns its application and saved-copy bookkeeping. A missing binding leaves suppression unchanged instead of pretending to repair it. No save file is edited by Hookshot's host code.
Overlaps
Refs #2402 and #2217. The overlap check reported clean merges for its code-file overlaps. I read #2371's host hunk (destination-picture capture ticking) and #2566's host/docs hunks (output/aspect handling); neither modifies this repair block. Other PRs sharing these large files were not functionally reviewed here.
Refs #2588 (closed as fixed by #2402; this completes that fix for the saved flag. The exact route that first set the flag remains unconfirmed).
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra noreply@openai.com