Files
Commonwealth-Online-Public/docs/pause-menu-vanilla-settings-plan.md
T
andrew 8acdb4f555 Extract reusable settings UI
Move the Commonwealth Online settings screen into a shared module with its own data, styles, and controller API. The pause menu now mounts the reusable component, keeps the prompt bar behavior consistent, and animates the panel open/close with a subtler transition.
2026-07-05 21:30:52 +12:00

252 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Pause Menu: Vanilla Game Settings Integration Plan
**Status:** Planned (not implemented)
**Date:** 2026-07-04
**Related prototype:** `ui/views/CommonwealthOnline/pause-menu/`
**Related inject pattern:** `plugin/src/F4TMainMenuInject.cpp`
This document records the agreed approach for opening Fallout 4s built-in settings from the Commonwealth Online custom pause UI, without showing QUICKSAVE, LOAD, QUIT, and the rest of the vanilla pause list.
---
## Goal
From the custom pause menu **SETTINGS → GAME SETTINGS → OPEN FALLOUT 4 SETTINGS**:
1. Show **only** the vanilla settings panel (right column: Audio, Display, etc.).
2. **Hide** the entire left pause column (QUICKSAVE, SAVE, LOAD, INSTALLED, MODS, HELP, SETTINGS, QUIT).
3. When the player presses **B / Escape** and backs out of settings, **restore the custom PrismaUI pause menu**.
Multiplayer options stay in the custom HTML **MULTIPLAYER SETTINGS** tab. This plan is only for the full vanilla game settings UI.
---
## Why not simpler approaches
### PrismaUI always on top
PrismaUI_F4 composites HTML in the D3D11 `Present` hook, **after** the full game frame (including all Scaleform menus). While a PrismaUI view is shown, it sits above PauseMenu and any settings UI.
So you **cannot** truly interleave:
```text
PauseMenu (left list) < custom UI < Settings panel
```
You only get:
```text
all Scaleform < PrismaUI (while the view is visible)
```
### Settings is not a standalone menu
In Fallout 4, settings is the **pause menu with SETTINGS selected**: left list + right settings panel in the same StartMenu / PauseMenu UI. Hiding PrismaUI and “opening settings” alone still shows QUICKSAVE, LOAD, QUIT, etc.
### Render-to-texture inside SWF
Possible in principle (custom `IMenu`, Ultralight → texture → Scaleform image) so custom UI participates in the menu stack. That is a large research project. Editing MainMenu / PauseMenu ActionScript is fragile (crashes already seen on main menu AS changes), which is why Multiplayer uses list inject + PrismaUI instead.
**Decision:** Do not use RTT/SWF hosting for this feature. Use runtime GFx + menu lifecycle, same class of work as main-menu inject.
---
## Chosen approach
Treat vanilla settings as a **modal sub-flow** owned by C++:
```text
CustomPause → VanillaSettingsOnly → CustomPause
```
| Phase | What the player sees | PrismaUI | PauseMenu |
| --- | --- | --- | --- |
| Custom pause | CO map / left nav / settings tabs | Shown + focused | Closed, or open but fully covered / unused |
| Vanilla settings only | Right-hand settings panel only | Hidden + unfocused | Open; left column hidden; navigated into settings |
| Back from settings | Custom pause again | Shown + focused | Closed or reset; left column restored if needed |
This is the **opposite** of Multiplayer inject: remove / hide pause rows and chrome instead of inserting a row.
---
## Technical background
### Shared StartMenu UI
- `RE::PauseMenu` and `RE::MainMenu` both inherit `RE::StartMenuBase`.
- Title and pause share the same list pattern the inject already uses:
- `MainPanel_mc.List_mc`
- `MainPanel_mc.List_mc.entryList`
- Pause mode is detectable via the movie variable `PauseMode` (main-menu inject **skips** inject when `PauseMode` is true).
- `StartMenuBase` exposes useful targets, including `mainPanel`, `settingsCategoryList`, and `settingsList`.
### Existing inject pattern to mirror
`F4TMainMenuInject.cpp`:
- Resolves `entryList` on the live GFx movie.
- Inserts a row (`text` + logical `index`).
- Calls `listWidget.Invoke("InvalidateData")`.
- Hooks `InitMainList` so the list is re-applied after the game rebuilds it.
- Opens the browser by handling item press / returning to `MAIN_STATE`.
Pause settings work should follow the same style: **runtime GFx only**, no SWF decompile, scoped to a dedicated flow flag.
---
## Implementation plan
### 1. Bridge from HTML
Prototype already stubs:
- `window.CommonwealthOnlineUI.openGameSettings`
Wire this to F4SE (same pattern as server browser interop): JS invoke → plugin enters `VanillaSettingsOnly`.
### 2. Enter `VanillaSettingsOnly`
On `openGameSettings`:
1. Set a plugin flag, e.g. `g_vanillaSettingsFromCustomPause = true`.
2. Ensure `PauseMenu` is open (open it if the custom pause flow did not already leave it open for pause state).
3. Resolve pause-mode `MainPanel_mc.List_mc.entryList`.
4. **Hide the entire left column** via GFx `SetVisible(false)` on `MainPanel_mc` / list (preferred for “only settings visible”). Optionally also strip `entryList` to only SETTINGS as a safety net so nothing in the left list remains activatable if visibility fails.
5. **Open settings** programmatically:
- Discover SETTINGS logical `index` in pause mode by logging `entryList` while paused (indices differ from title screen; do not reuse `kLoadIndex` / `kMultiplayerIndex`).
- Select SETTINGS and invoke the same open path the list uses (mirror `OpenMultiplayerMenu` / item-press handling), **or** drive `currentState` / settings panel if a stable GFx path is found.
6. **Hide and unfocus** the PrismaUI pause view so input goes to vanilla settings.
Player should see only the settings panel (and game blur / pause chrome that is not the left list).
### 3. Stay in settings
While `g_vanillaSettingsFromCustomPause`:
- If `InitMainList` (or equivalent) rebuilds the pause list, **re-hide** the left column (and re-strip if stripping).
- Do not run title-screen Multiplayer inject on this menu.
- Do not show the custom pause UI.
### 4. Exit back to custom pause
Detect leave-settings / back:
- PauseMenu `currentState` returns from settings toward main pause list, and/or
- Settings panel closes, and/or
- B / Escape after settings (prefer detecting state, not only the key).
On exit:
1. Restore left column visibility (and full `entryList` if stripped).
2. Close `PauseMenu` if it was only opened for this flow, **or** hide it immediately so the player never sees QUICKSAVE / LOAD / QUIT.
3. Clear `g_vanillaSettingsFromCustomPause`.
4. **Show + focus** the PrismaUI pause view (settings tab / game settings pane as appropriate).
5. Ensure Escape handling returns to custom UI behavior (JS `keydown` / plugin focus), same idea as the server browser.
**Important:** Vanilla often backs from settings **to the pause list**, then B again closes pause. For this flow, the first back from settings should go **straight to custom UI**, with no flash of the full pause list. Hide/close PauseMenu as soon as settings is left.
### 5. Abort / edge cases
- Player force-closes menus, loads, or quits: clear the flag, restore list visibility, do not leave PauseMenu permanently stripped.
- Custom pause closed while settings open: still clear flag and restore vanilla pause to a normal state.
- Resolution / safe area: left-column hide is clip-based, so it should not need a transparent “hole” rect (unlike a PrismaUI mask approach).
---
## State machine (summary)
```text
openGameSettings()
[CustomPause] ──────────────────────────► [VanillaSettingsOnly]
▲ │
│ settings back / Escape │
└────────────────────────────────────────────┘
restore list, close/hide PauseMenu,
Show+Focus PrismaUI pause view
```
---
## Alternatives considered (not chosen for v1)
| Approach | Why not for v1 |
| --- | --- |
| Transparent PrismaUI hole over settings panel | Possible, but alignment and input focus are harder; left list still exists underneath |
| Hide PrismaUI only (full pause menu) | Shows QUICKSAVE / LOAD / QUIT — fails the goal |
| Custom `IMenu` + Ultralight render-to-texture | Correct for true stack interleaving; too large for this feature |
| Patch PauseMenu.swf ActionScript | Crash risk; project already avoided this on main menu |
| Reimplement all FO4 settings in HTML | Huge scope; vanilla settings already work |
---
## Discovery checklist (before coding)
Run in-game with F4SE logging while PauseMenu is open:
1. Confirm `PauseMode == true` on the pause movie.
2. Dump `MainPanel_mc.List_mc.entryList` entries (`text`, `index`) and note SETTINGS index.
3. Confirm `SetVisible(false)` on the left panel clip hides the whole column without breaking the settings panel.
4. Find a reliable way to open settings (item press invoke vs `currentState` / menuObj members).
5. Find a reliable “left settings” signal for returning to custom UI.
6. Confirm B / Escape order: settings → (must not show list) → custom UI.
---
## Suggested implementation order
1. Pause menu PrismaUI view wired like the server browser (show/hide/focus), without vanilla settings yet.
2. `openGameSettings` bridge → open PauseMenu, hide PrismaUI (accept full pause list temporarily).
3. Hide left column + auto-open settings.
4. Exit detection → restore custom pause with no list flash.
5. `InitMainList` re-apply while flag is set.
6. Polish: abort paths, logging, controller + keyboard.
---
## Files likely involved
| Area | Path |
| --- | --- |
| HTML / bridge stub | `ui/views/CommonwealthOnline/pause-menu/script.js` |
| Reusable settings UI | `ui/views/CommonwealthOnline/settings/` (`CO_Settings.create`) |
| Pause PrismaUI (new, similar to browser) | `plugin/src/F4TPrismaUI.cpp` (or dedicated pause module) |
| Pause list hide / settings open (new) | e.g. `plugin/src/F4TPauseMenuSettings.cpp` — mirror `F4TMainMenuInject.cpp` |
| Types | `RE::PauseMenu`, `RE::StartMenuBase` in CommonLibF4 |
| Prototype UI copy | `ui/views/CommonwealthOnline/pause-menu/` (embeds `../settings/`) |
---
## Success criteria
- From custom pause, player can open full vanilla game settings.
- Left pause column never visible during that flow.
- No QUICKSAVE / LOAD / QUIT (or other pause actions) reachable during that flow.
- B / Escape from settings returns to custom pause, not a bare vanilla pause list.
- Normal title-screen Multiplayer inject unchanged.
- No permanent PauseMenu SWF edits.
---
## Manual test checklist (when implemented)
- Server / game running; custom pause opens in-game via PrismaUI.
- SETTINGS → GAME SETTINGS → OPEN FALLOUT 4 SETTINGS.
- Only settings panel visible; left column absent.
- Change a setting (e.g. audio slider); confirm it applies.
- B / Escape returns to custom pause (settings tab), no flash of vanilla list.
- Open settings again; still correct.
- Quit flow / reload; pause menu not permanently broken if opened without custom UI (if vanilla pause remains reachable at all).
- Controller and keyboard both work in vanilla settings and after return.
---
## References
- Main menu inject (add row): `plugin/src/F4TMainMenuInject.cpp`
- PrismaUI view lifecycle: `ThirdParty/framework-F4-Conversion/docs/view-lifecycle.md`
- PrismaUI architecture (Present overlay): `ThirdParty/framework-F4-Conversion/README.md`
- Pause menu prototype settings UI: `ui/views/CommonwealthOnline/pause-menu/`
- Menu flags / depth (Scaleform stack): `RE::UI_MENU_FLAGS`, `RE::UI_DEPTH_PRIORITY`