Skip to content

Port: make the Debug menu binding open the debug menu - #124

Merged
Adubbz merged 1 commit into
TheMoonPeople:masterfrom
carrdylan52:pr/debug-menu-key
Oct 23, 2026
Merged

Adubbz merged 1 commit into
TheMoonPeople:masterfrom
carrdylan52:pr/debug-menu-key

Conversation

@carrdylan52

@carrdylan52 carrdylan52 commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Port: make the Debug menu binding open the debug menu

Before

PC SETTINGS > Bindings offers a "Debug menu" action (debug_menu, paddle 1 by default), but nothing reads it, so a key bound to it does nothing. You can already reach the debug menus from the keyboard: the four-shoulder/R3 chord or pad-2 Circle toggles DebugFlag, then R3 opens the dungeon or town debug menu. With debug mode on, Start+Select also goes to the developer menu (docs/DEBUG.md). Each of these takes a chord or two steps.

After

With game.debug_mode or --jump, the bound key is a one-key shortcut to the current loop's debug menu:

  • Title: Start+Select, which leaves for the developer menu.
  • Dungeon or town, while the player has control: R3 opens the debug menu.
  • A second press closes the open dungeon or town debug menu.

The key turns DebugFlag on first, so it works when the flag is off.

These presses are dropped without touching DebugFlag or the pad:

  • presses in ordinary menus, events, Georama edit and sub-games,
  • presses in a dungeon during Spheda or the player-control pause,
  • presses under a pad lock, even with a debug menu open,
  • presses in other loops.

Presses made during the pause overlay, the frame pause, a loading screen inside a tick or a mode change are dropped too, so they are not delivered once the game resumes.

How

  • DebugModeMenuButtons(loop) (port/src/debug_mode.cpp) returns the buttons for this tick, or 0 to drop the press:
    • A locked pad (GamePad__2.key_lock) returns 0 in every loop, before any other check.
    • Title: Start+Select.
    • Dungeon: R3 in either of two cases:
      • The player has control: PortDungeonFieldControl(), and also no DNG_PAUSE_PLAYER_CONTROL, no running sub-game and no Spheda being played. Fishing and Spheda run in field mode, but DngMainKey takes the debug R3 before it dispatches to them (ps2/src/dng_main.cpp:2176, 2235, 2275). These three checks are for the key only; autosave is unchanged.
      • The dungeon debug menu is already open (dngGetDebugInfo()->active in field mode). An open menu pauses the player and field steps, so it has its own check.
    • Town: R3 when PortTownFieldControl() is true, or when the edit debug menu is already open (EditDebugMode() with control in EDIT_CONTROL_DEBUG).
    • Any other loop: 0.
  • DebugModeMenuKey(loop) sets DebugFlag and injects the buttons as a new pad-1 press, but only when it delivers.
  • Why menus are excluded: in a dungeon menu, R3 toggles menu_debug_flag through MenuMainKey (ps2/src/menumain.cpp:1433). In a town menu it can reach EditDebugStart, which resets MenuBuffer__2 while the open menu is using it (ps2/src/editloop.cpp:1730, ps2/src/editdebug.cpp:178).
  • PortDungeonFieldControl and PortTownFieldControl (port/src/mainloop.cpp) are the conditions floor and town autosave already checked, moved out so both features share them. Autosave behaves as before.
  • Replay after waits: the host counts presses whenever it polls input, and InputHostPressed removes only one. The fix is port-side, with no Kazarov change:
    • DebugModeTakeMenuKey(frame) drains every pending press each tick. It counts them, as one press, only when the previous tick ended on the current mgPortFrameCount(), meaning nothing else ended a frame in between.
    • DebugModeEndMenuKeyTick marks a tick that ended more than one frame, such as a loading screen inside the tick, so the presses read at the next tick are dropped.
    • Known limit: the whole tick after a multi-frame tick is dropped, so a fresh press made during the last frame of a loading screen can be lost and needs pressing again.
    • MainLoop calls DebugModeDiscardMenuKey() when a mode starts, after the frame pause and after PauseLoop. The frame pause waits on sceGsSyncV and ends no frame, so it needs this explicit discard.
  • port/include/stubs/subgame.hpp exposes retail SubGame, so the tests can make a sub-game appear to run without starting one.
  • docs/DEBUG.md: a new "Debug menu key" section describes the key as a shortcut for the existing routes and lists where it is dropped. debug_menu is removed from "PC gaps".

Tests

  • DebugMenuKey cases in port/src/tests/debug_mode_test.cpp:
    • The title and field mapping.
    • Dropped presses, with DebugFlag and the pad unchanged, in:
      • non-game loops,
      • dungeon menu and event menu,
      • dungeon events, and each of DNG_PAUSE_PLAYER_STEP, DNG_PAUSE_FIELD_STEP and DNG_PAUSE_PLAYER_CONTROL on its own,
      • dungeon fishing, and Spheda while it is played (a Spheda that is not being played leaves the key alone),
      • town menu, Georama edit, background read, events, player lock, pause and sub-game,
      • a pad lock in the title, dungeon and town, and a pad lock with the dungeon or town debug menu already open.
    • Dungeon second press: both presses go through the real DngMainKey. The first opens the menu, and the second closes it and restores the field's pause flags.
    • Town second press: the open edit debug menu gets the new R3 that EditDebugLoop closes on, and control stays with the menu. EditDebugLoop itself draws through the renderer and the save data, so the test stops at that press.
  • DebugMenuKeyInput cases bind F9 and press it through the host input (InputSetScriptedDevices):
    • a press inside an ordinary tick counts once,
    • a press during the frame pause, the pause overlay or a loading screen inside a tick is dropped,
    • a press across a mode change is dropped,
    • after each wait, the next ordinary press counts.
  • Rebase validation at cd91cc100 on b949b1c0b: Windows build completed successfully. The non-GPU CTest run reported “100% tests passed out of 1665”; its 1666 selected entries comprise 1622 Passed, 43 Skipped, and one Disabled, with no failures. All 16 DebugMenuKey / DebugMenuKeyInput tests passed. This adds recorded build/test evidence; the earlier headless evidence remains historical.
  • Original pre-rebase validation (historical): full darkchronicle_tests (Windows release) compared against origin/master: no new failures and no lost passes.
    • The same 28 tests fail on both builds:
      • GPU texture, draw and movie tests,
      • EzBgm audio,
      • PlatformMc/PlatformCdvd file system,
      • MesWinFillRect,
      • GamePadSingleDebug.DeveloperMenuChordUsesHostInputPastTheGameLockAndOnlyOnAnEdge,
      • TownEyeCamera.FixedRoomReseatCutsButForcedFollowInTheSameRoomDoesNot.
    • EeKernelThreads.RotateInsidePumpWithNothingReadyDoesNotSwitch aborts the test process on both, so the runner restarts past it.
  • Headless, with {"game":{"debug_mode":true},"input":{"bindings":{"debug_menu":"F9"}}} and --fast-load:
    • --jump dungeon:1:1 --skip-events: F9 opens the dungeon DEBUG MENU, and a second F9 closes it.
    • --jump town:10: F9 opens the town edit debug menu, and a second F9 closes it.
    • With the field menu open, or its Items page, F9 changes nothing. The frame is byte-identical to the same run without F9, in both the dungeon and the town.
    • Pause overlay: Start pauses, F9 is pressed while paused, and Start resumes. The frame after resuming is byte-identical to the same run without F9, in both the dungeon and the town. The previous revision opened the debug menu on resume in both. An F9 pressed after resuming still opens the menu.
    • --jump title: F9 reaches the Ver0.334 developer menu.
    • Two cases are covered by the unit tests only. The frame pause can't be scripted headless, because input-script steps are keyed by frame and no frame advances while it is paused. The jump loads finish before the first scripted frame, so a press can't be placed inside them.

@carrdylan52
carrdylan52 marked this pull request as draft October 19, 2026 00:55
@carrdylan52
carrdylan52 marked this pull request as ready for review October 19, 2026 02:28
The Bindings page offered "Debug menu" (debug_menu), but nothing read
the action, so a key bound to it did nothing. With debug mode on, the
key is now a one-key shortcut to the current loop's debug menu: it turns
DebugFlag on and presses Start+Select on the title, or R3 in a dungeon or
town, where a second press closes the open debug menu.

R3 only reaches the debug menu while the player has control. In an
ordinary menu it toggles menu_debug_flag, and in a town menu it can start
the edit debug menu under it and reset MenuBuffer. So the key is dropped
in menus, events, Georama edit, sub-games, under a pad lock (also with a
debug menu open) and in other loops, before DebugFlag or the pad changes.
The control checks are the ones floor and town autosave already used,
now shared as PortDungeonFieldControl and PortTownFieldControl. The
dungeon adds checks for the key alone: dungeon fishing and Spheda run in
field mode but read the pad after the debug R3, and the player-control
pause holds the player.

The host counts presses whenever it polls input, so a press made while
the game waits would be delivered once it resumes. Presses count only
within one ordinary tick: MainLoop drops them when a mode starts, after
the frame pause and the pause overlay, and after a tick that ended more
than its own frame.
@Adubbz
Adubbz merged commit 5d4cf65 into TheMoonPeople:master Oct 23, 2026
3 of 7 checks passed
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.

2 participants