fix(input): reseed mouse look after camera handover #2653

Merged
mooki000 merged 1 commit from fix/mouse-camera-handover into main 2026-11-12 04:31:37 +00:00
mooki000 commented 2026-11-12 04:24:02 +00:00 (Migrated from github.com)

What this is for: resume Native mouse look from the game's current camera angles after another camera takes over (current main CI). What is measured: the affected game-free check before and after, with GCC 16.2.1 and Clang 23.1.3 selected, plus one strict full-suite run, as recorded below. Not measured: a game run or Windows execution.

Cause

#2617 retains mouse target angles to prevent drift, but the existing inactive-state guard returns without invalidating that target; the pre-existing handover test then applies movement to old yaw 5 instead of current yaw 0 (host/mouse_native.c:120-148, tests/test_mouse_native.py).

The relevant failure in main's CI log is:

AssertionError: 1 != 0 : FAIL line 134: near(getf(YAW), -1.0f) (pitch 10 yaw 4)

What changed

Clear target_ok when the player camera is inactive; keep immediate stick handback and persistent angles while active. Preserve the original failing yaw assertion, exercise changed pitch and yaw on return to both active states, and document the handover in the readme.

How it was tested

Recorded on 2026-11-11, Linux kernel 7.2.15-1-omarchy, base de866017, head 58c817f7 (version and test records).

  • Untouched main a016b7a6: the affected check fails independently in both compiler environments with the diagnostic above; the branch passes independently in both (python -I -B tests/run_all.py --strict --jobs 1 tests/test_mouse_native.py records).
  • Removing only the target invalidation from an isolated copy restores the wrong-yaw failure with both compilers (two mutation records); the original no-drift and stick-handover assertions remain.
  • One full python -I -B tests/run_all.py --strict: 456 passed, 14 failed, 20 skipped in 178 s (linux, 32 at once), load 33.42 → 81.38 (complete suite output).
  • That run's remaining failures are: test_wayland_libdecor_hint.py, test_display_startup_failure.py, test_texel_buffer_ownership.py, test_audio_aux.py, test_audio_biquad.py, test_dlss_checks.py, test_env_on.py, test_framegen_preset.py, test_hdr_encode.py, test_linux_docker_packages.py, test_menu_i18n.py, test_mods_size_table.py, test_readback_part.py, test_rumble_menu.py (complete suite output). The companion fixture, capture-switch, PPA-parser and hint-catalog branches address their separate causes; #2614 owns the HDR check and is not duplicated here.

Not tested / risks

The executable fixture runs the actual camera function against authored state, but no game, real mouse/controller, Windows or camera-transition playtest was run.

Overlaps

The inspected #2567 first-person changes and #2630 camera-centering restoration do not contain this handover fix and merge cleanly in the recorded comparison.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra [email protected]

**What this is for:** resume Native mouse look from the game's current camera angles after another camera takes over ([current main CI](https://github.com/NotRexed/Hookshot/actions/runs/43151254256)). **What is measured:** the affected game-free check before and after, with GCC 16.2.1 and Clang 23.1.3 selected, plus one strict full-suite run, as recorded below. **Not measured:** a game run or Windows execution. ## Cause #2617 retains mouse target angles to prevent drift, but the existing inactive-state guard returns without invalidating that target; the pre-existing handover test then applies movement to old yaw 5 instead of current yaw 0 (`host/mouse_native.c:120-148`, `tests/test_mouse_native.py`). The relevant failure in [main's CI log](https://github.com/NotRexed/Hookshot/actions/runs/43151254256) is: ```text AssertionError: 1 != 0 : FAIL line 134: near(getf(YAW), -1.0f) (pitch 10 yaw 4) ``` ## What changed Clear `target_ok` when the player camera is inactive; keep immediate stick handback and persistent angles while active. Preserve the original failing yaw assertion, exercise changed pitch and yaw on return to both active states, and document the handover in the readme. ## How it was tested Recorded on 2026-11-11, Linux kernel `7.2.15-1-omarchy`, base `de866017`, head `58c817f7` (version and test records). - Untouched main `a016b7a6`: the affected check fails independently in both compiler environments with the diagnostic above; the branch passes independently in both (`python -I -B tests/run_all.py --strict --jobs 1 tests/test_mouse_native.py` records). - Removing only the target invalidation from an isolated copy restores the wrong-yaw failure with both compilers (two mutation records); the original no-drift and stick-handover assertions remain. - One full `python -I -B tests/run_all.py --strict`: **`456 passed, 14 failed, 20 skipped in 178 s (linux, 32 at once)`**, load 33.42 → 81.38 (complete suite output). - That run's remaining failures are: `test_wayland_libdecor_hint.py`, `test_display_startup_failure.py`, `test_texel_buffer_ownership.py`, `test_audio_aux.py`, `test_audio_biquad.py`, `test_dlss_checks.py`, `test_env_on.py`, `test_framegen_preset.py`, `test_hdr_encode.py`, `test_linux_docker_packages.py`, `test_menu_i18n.py`, `test_mods_size_table.py`, `test_readback_part.py`, `test_rumble_menu.py` (complete suite output). The companion fixture, capture-switch, PPA-parser and hint-catalog branches address their separate causes; #2614 owns the HDR check and is not duplicated here. ## Not tested / risks The executable fixture runs the actual camera function against authored state, but no game, real mouse/controller, Windows or camera-transition playtest was run. ## Overlaps The inspected #2567 first-person changes and #2630 camera-centering restoration do not contain this handover fix and merge cleanly in the recorded comparison. Assisted-by: GPT-6 Astra Co-Authored-By: GPT-6 Astra <[email protected]>
hckrman101 (Migrated from github.com) approved these changes 2026-11-12 04:28:20 +00:00
hckrman101 (Migrated from github.com) left a comment

Thanks, this is the right fix. I traced it on main: the free-look guard clears target_ok just before the slingshot block, the state(4) frame reseeds from yaw 5, and then the state-0 branch returned without dropping that target, so the first frame back turned from 5 instead of the game's 0 (yaw 4, the CI failure). Clearing it in the not-3/4 branch closes that.

What I checked:

  • Every way back from a non-3/4 state now reseeds yaw and pitch from the game's current angles before the frame's motion is added, so there's no jump on the first frame back. Going 3 to 4 or 4 to 3 doesn't touch it (the stick path still reseeds), and a camera that stays in 3/4 the whole time behaves exactly as before; the no-drift checks still cover that.
  • The loop is a real test both times through: on the first pass the stale target would be yaw 5 / pitch 10, on the second -1 / 20.5, and both differ from the 0 / 20 the game sets, so a stale yaw or pitch fails either way back (3 and 4).

One thing for a follow-up, not this PR: the reseed only happens when the hook runs in another state. If the player camera's update stops running altogether (the pause menu, a scene load) and the camera comes back at the same address in state 3 with new angles, target_ok is still 1 and the old target gets written over them. I haven't checked in game whether that happens. If it does, the fix is just as small: reseed when the hook hasn't run within LIVE_NS (read last_hook_ns before it's overwritten).

Python checks are still running; the rest is green.

Thanks, this is the right fix. I traced it on main: the free-look guard clears `target_ok` just before the slingshot block, the `state(4)` frame reseeds from yaw 5, and then the state-0 branch returned without dropping that target, so the first frame back turned from 5 instead of the game's 0 (yaw 4, the CI failure). Clearing it in the not-3/4 branch closes that. What I checked: - Every way back from a non-3/4 state now reseeds yaw and pitch from the game's current angles before the frame's motion is added, so there's no jump on the first frame back. Going 3 to 4 or 4 to 3 doesn't touch it (the stick path still reseeds), and a camera that stays in 3/4 the whole time behaves exactly as before; the no-drift checks still cover that. - The loop is a real test both times through: on the first pass the stale target would be yaw 5 / pitch 10, on the second -1 / 20.5, and both differ from the 0 / 20 the game sets, so a stale yaw or pitch fails either way back (3 and 4). One thing for a follow-up, not this PR: the reseed only happens when the hook *runs* in another state. If the player camera's update stops running altogether (the pause menu, a scene load) and the camera comes back at the same address in state 3 with new angles, `target_ok` is still 1 and the old target gets written over them. I haven't checked in game whether that happens. If it does, the fix is just as small: reseed when the hook hasn't run within `LIVE_NS` (read `last_hook_ns` before it's overwritten). Python checks are still running; the rest is green.
Commenting is not possible because the repository is archived.
No description provided.