Skip to content

feat(menu): save and resume when restarting for changed settings - #2607

Draft
mooki000 wants to merge 6 commits into
NotRexed:mainfrom
mooki000:restart-in-place-next
Draft

mooki000 wants to merge 6 commits into
NotRexed:mainfrom
mooki000:restart-in-place-next

Conversation

@mooki000

Copy link
Copy Markdown
Contributor

Draft until #1560 lands: this carries #1560's commit (co-authored by its author) so that it can be read and tested as a whole; when #1560 merges I drop that commit and rebase.

What this is for: applying a restart-only setting should not mean returning to the title and manually loading an older save. With Restart in place on, Restart asks the game to autosave, relaunches and loads that save. What is measured: game-free checks on this branch based on main 6ff87f59, with GCC 16.2.1 and Clang 23.1.3, and three headless RTX 4090 cases: the new output size takes effect after relaunch, cancellation keeps the original process running, and a saved restart returns to the same logged position in Kokiri Forest. The save-run interval contains one known kernel mapping-refusal line, not an all-zero kernel result. Not measured: Windows runtime, AMD, Steam Deck, physical input, monitor restoration or performance.

This uses the title-loading work in #1560, credited to Nicholas Gower in its separate dependency commit. That pull request is still open.

Problem

  • Main already has Restart and Restart now. They save the options and relaunch through host/hos_relaunch.c, but do not ask the game for a fresh save or resume it.
  • The existing restart-in-place work asks for a save and passes a continuation note, but its Linux headless proof was incomplete. main() skipped hos_display_loop() without a window. Changing that condition alone is not enough: main's no-SDL loop only sleeps and never reads the queued Restart/Quit requests.
  • Both parts are needed to exercise the real menu path without opening a window. The compiled startup fixture now checks that path instead of merely accepting a headless worker wait.

What changed

  • Headless menu fix, separate commit: scripted confirmation presses count without window focus; Restart/Quit requests are posted without a window; the headless display loop serves them; ordinary POSIX game starts enter that loop. Shader preparation retains its worker-completion path. Existing window-size, startup-diagnostic and preparation assertions remain.
  • Title-loading dependency: feat(menu): skip the title screen and load the newest save #1560's Gameplay row remains off by default. Its existing newest-save lookup and A presses are reused. Main's existing hos_hid_tap is kept, not duplicated.
  • Restart in place: a Gameplay row, on by default. The menu asks the game for an autosave and displays its wait or refusal. The host observes a successful write open and save commit before allowing the relaunch. Esc, leaving the row or closing the menu cancels the pending request. A refusal asks again before returning to the title.
  • Continuation: host/oot_restart.c hands the relaunch path a one-use environment note. The restarted game accepts it only while its slot and file time still match the newest save. It then uses the title-loading path regardless of the Skip title screen row. Physical and control-client input is held out of that automatic title passage, not ordinary launches with Skip title screen alone.
  • Current-main integration: keep Aspect ratio, FOV, live prompt and HDR handlers, the sectioned menu and its shared value-cell renderer. The restart wait leaves compact mode. Option IDs are Skip title 44 and Restart in place 64; the host/renderer interface layout is unchanged.
  • Tests and documentation: the readme describes both rows; the development guide documents scripted headless Restart/Quit. The file-open fixture records restart notifications while retaining all its virtual-core checks.

How to try it

Open the Insert menu, change a setting marked as requiring a restart, then use Gameplay → Restart and confirm it, or choose Restart now when closing the menu. With Restart in place on, allow the autosave to finish. If the game refuses one, the menu asks before proceeding to the title. Esc cancels the pending restart. Turning Restart in place off keeps the ordinary title-screen restart.

Game-free checks

Production head 2a3c6f5c on 6ff87f59; test-only fixture repair 7f924403. Arch Linux, kernel 7.2.15-1-omarchy. Complete runs used tests/run_all.py --strict --jobs 8, serially through the idle/core-dump wrapper. The Clang run also mapped inherited literal GCC fixture commands to Clang; tests with other explicit tool requirements retained them.

The pushed head 14a058b1 has the same production tree as the tested build; the later commits change the file-open fixture and record the three runs.

Run Passed Failed Skipped Suite time
Complete GCC suite 450 4 20 262 s
Complete Clang suite 451 3 20 279 s
New restart, skip-title and updated startup checks against main, GCC 0 3 0 1 s
Same negative controls, Clang 0 3 0 1 s

Both full suites pass the restart-in-place, skip-title, startup, background-input, menu restart/slots/keys/tuning and option-ID checks. The new feature tests fail on main's missing Gameplay rows. The compiled startup fixture fails main's headless idle, Restart and Quit cases; its other ten cases pass.

One failure was caused by this change: the extracted OpenFile fixture lacked the new restart observer. The test-only repair adds a recording observer, keeps every existing core-ownership assertion and checks successful, refused and failed writes. The repaired check passes with both compilers. Against main, it fails at a successful write tells restart in place its guest path once. Production code did not change after the build.

The remaining failure sets reproduce on byte-identical main sources:

  • GCC: test_depth_sample_types.py and test_unsigned_image_types.py reject a static local in a constexpr function under C++20.
  • Clang: test_vram_budget_row.py rejects unused kVramMinimumOnly under -Werror.
  • Both: test_env_on.py rejects main's set-means-on HOS_FPS_LOG read.

These unrelated fixes are not included. The raw full suites are not relabelled as green after the fixture repair. No core dumps were found.

Every test/fixture path was compared with main and the pre-rebase branch by Git blob. Only seven files differ from main. Their guards and assertions were compared separately: no check is missing. The headless worker-wait assertion now checks entry into the request loop; the old Ultrawide row assertion follows main's Aspect ratio rename. The restart-in-place and skip-title tests themselves are unchanged from the pre-rebase branch.

In the game

Arch Linux, kernel 7.2.15-1-omarchy, RTX 4090, NVIDIA 615.78.08, i9-13900K; production head 2a3c6f5c on 6ff87f59. Headless, stock input/menu scripts, 1280x720 captures, ordinary shared GPU queue. The build reused a completed matching lift after asserting the lift inputs and HLE set; it is not a mixed host/renderer build.

Case Result PID before → after Wall limit / observed wall Load before → after Virtual-core escapes Kernel NVRM / driver-fault lines
Title: change Output resolution, confirm Restart Relaunched; title reached; startup size changes 2048x1152 → 1920x1080 1395591 → 1395591 (execve) 180 / 180.8 s 80.78 → 87.58 2 0 / 0
Cancel the pending restart after changing the setting Cancelled during the autosave cooldown; original process continues with 2048x1152; 1920x1080 remains pending 1825730, no replacement 120 / 121.0 s 126.98 → 94.10 0 0 / 0
Restart with a save loaded Saved, relaunched and loaded the new save; back in Kokiri Forest at the same logged position 2482426 → 2482426 (execve) 190 / 190.6 s 9.43 → 83.85 0 1 known refusal / 0

All three ran once on 2026-11-11 and ended at their planned wall limits (exit 124), with zero fatal/crash/device-loss counts. The title case's scheduler escapes occurred during its first startup. These shared-load runs are not a performance or general stability comparison.

The title case's log, in order:

oe: output resolution 2048x1152 (the game's)
menu: restart, in place: the game is asked to save first
restart: no game is in play yet: the game starts again at its title
display: window closed for a restart (the Insert menu's Restart now)
hookshot v2.1.0-rc.3-193-g2a3c6f5c (source 5feb7b9a)
oe: output resolution 1920x1080

1: 1920x1080 chosen, a restart is needed. 2: Gameplay, Restart, press again to confirm. 3: the relaunched game at the title

Panel 1 shows 1920x1080 with the restart-required marker; panel 2 the Gameplay/Restart confirmation; panel 3 the replacement image at the title with Continue/New Game. The new output size is established by the log, not by the scaled capture.

Cancellation: the log says restart: the game saved a moment ago and takes no autosave for another 1357 updates: waiting, then restart: cancelled 2997 ms after Restart. There is one startup banner and no restart-close line. Its only startup output-size line remains 2048x1152. The inspected picture after cancellation still marks the selected 1920x1080 as requiring a restart, and the final picture shows play continuing.

1: Restart waits for the autosave cooldown. 2: cancelled, 1920x1080 still needs a restart. 3: the original process goes on playing

Save loaded: the game took its autosave request, wrote slot_02/progress.sav and reported restart: the game saved slot_02 10021 ms after Restart: restarting to continue there. The replacement logs 1920x1080, accepts the continuation note for that slot and logs skip title: loaded, the player is running. It returns to Kokiri Forest, beside the mossy rock near Link's house, 52.8 s after Restart, with 0.00 m displacement in the rounded position log. The camera view differs: this is a save/load, not restoration of every process state.

1: before Restart, beside the mossy rock. 2: the game waits before taking its autosave. 3: returned at the same logged position

Kernel exception: title and cancellation have no NVRM line. The save-run interval contains one NVRM: memMap_IMPL: CPU mapping not supported for addressSpace: 0x1, the known mapping refusal, and no Xid or kmemsysDoCacheOp line. Both game images log that dma-buf imports are disabled on NVIDIA; the global kernel line cannot be attributed to a process from this evidence. My check for zero kernel lines therefore fails for that run and is reported as failed; the three functional checks pass. It was not rerun.

Not tested

Windows runtime, AMD and Steam Deck; physical controllers/keyboard/mouse; a moved window returning to the same monitor; co-op reconnection; long sessions; corrupt saves; other areas; Restart in place off in a current-build game run. No frame-rate or stutter improvement is claimed. The headless harness cannot establish window placement.

Risks

  • This is the game's autosave, not a full process snapshot. It does not preserve enemies or objects in flight. A save that the game refuses is not forced.
  • The autosave cooldown can make Restart wait. Cancelling a request after the game accepted it does not undo the game's save; it cancels the relaunch.
  • Automatic title presses depend on the game's title/load flow and stop after their timeout. This does not validate damaged save contents.
  • Linux relaunch uses execve, so the replacement image keeps the PID. Windows uses a new process and its inherited environment block; that runtime path was not exercised here.

Overlaps

The open-head scan and conflict hunks were read. No combined game run with those branches is claimed.

Questions for you

Can #1560 land first so its dependency commit can be dropped from this branch? The headless menu repair is also isolated as its own commit.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra noreply@openai.com

mooki000 and others added 6 commits November 11, 2026 23:58
Keep the menu requests, the headless display loop and the POSIX main-loop entry together. Shader preparation keeps its worker-completion path. Extend the startup fixture with headless Restart and Quit while retaining window sizing, failure diagnostics and preparation checks.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Rebase Nicholas Gower’s pull request NotRexed#1560 for the restart-in-place dependency. Keep the existing hos_hid_tap implementation, current menu rows and option handlers. The option remains off by default.

Co-Authored-By: Nicholas Gower <nicholasgower01@gmail.com>
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Keep the existing restart-in-place state machine on the current menu. Ask the game for its autosave before relaunching, pass a one-use continuation note and use the title-loading dependency to return to that save. Cancelling stops the pending restart. Adapt its status cell to the shared row renderer and leave compact mode before showing the save wait.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <noreply@openai.com>
The extracted OpenFile now calls the restart observer on successful writes. Supply a recording observer, keep every existing virtual-core assertion, and check successful, refused and failed writes without changing production code.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Record the tested build, menu setting change, inspected pictures and zero kernel driver lines. Keep the startup virtual-core escapes and shared-load limitation visible; no performance or window-placement claim.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Record the two authorized headless cases on the unchanged production build. Cancellation leaves the original process running; the saved restart returns to the same logged position. Keep the known kernel mapping-refusal line and the shared-load limits visible instead of claiming an all-zero kernel result.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <noreply@openai.com>
@mooki000

Copy link
Copy Markdown
Contributor Author

Rebased 14a058b1 onto current main 87991bc8 as ff3f413d, preserving all six commits and their complete messages/trailers, including Nicholas Gower's exact #1560 co-author line. Resolutions retain both sets of historical test records, main's current prompts/camera/Bug report/reset behavior, and the updated Restart explanation in all 13 catalogues; save/resume behavior and defaults are unchanged. On the first rebase, GCC passed 137 selected checks and Clang 136 with only main's background-input fixture warning; the suite was 471 passed / 1 inherited failure / 20 skipped. Main then moved only by #2671; the final rebase changes no PR file blob. Feature/fixture checks and main negatives were rerun with both compilers, along with #2671's offline test and Windows-target host syntax (zero errors under the documented platform supplement). The final PR gate passes. The suite was not repeated, and no new game run or native Windows execution is claimed; this remains a draft carrying #1560. Sources: the #2607 evidence and final-handoff ledger above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant