Bring HUD closer and isolate floating native menus

This commit is contained in:
ElHombreAlex committed 2026-10-03 19:17:12 +02:00
1 parent 028de594bb
commit 46102cabf7
18 files changed
+84 -22

No files matched your search

+8
View File
@@ -1,5 +1,13 @@
# Changelog
## HUD clearance and menu correction — source update, 2026-10-03
- Reduce the HUD's collision clearance above the ship/shield from 14 cm to 8 cm. Headset-following priority is unchanged.
- Show native in-run Ship, pause-menu and Options windows only on their floating world panel, preserving the status/crew HUD. Initial and hangar menus remain head-relative.
- Resolve and require `MenuScreenOnRender` and `OptionsScreenOnRender` hooks to isolate native menus from the supplemental HUD capture. Existing installations must rerun [hook resolution](docs/INSTALLATION.md#4-resolve-the-local-executable-hooks).
Verification: 40 Python tests, focused Vulkan HUD/input checks and native before/after captures passed. The duplicate pause-menu/Options pixels disappeared from the HUD; complete world-panel captures remained unchanged. Physical headset comfort and stereo performance still need the maintainer's playtest.
## HUD, wheel and launch corrections — source update, 2026-10-03
- Gameplay HUD follows the headset at a fixed readable size. It clamps above the transformed hull/shield only when its movement would intersect the ship; full menus remain head-relative.
+6 -4
View File
@@ -11,9 +11,9 @@ An experimental OpenXR mod for **FTL: Faster Than Light**. Walk around a miniatu
## What it does
- Floating player and enemy ships with opposing bows, room interiors, visible shields and movable encounter placement.
- Compact original HUD following the headset, with clearance above the ship when needed; upper status and crew roster, controller navigation, Tactical, shortcuts, system power and illustrated Help.
- Compact original HUD following the headset, with 8 cm clearance above the ship when needed; upper status and crew roster, controller navigation, Tactical, shortcuts, system power and illustrated Help.
- Crew selection and drag-to-room orders, door controls, weapon/beam targeting and native system targeting.
- Contextual Jump/Ship/Store actions, a cockpit-anchored sector map, floating event dialogs and complete native shop/ship panels.
- Contextual Jump/Ship/Store actions, a cockpit-anchored sector map, floating event dialogs and complete native shop/ship/Options panels displayed only above the ship during a run.
- An eight-slot action wheel with localized equipped names, family/ammo hints, Shift/Ctrl shortcuts and a QWERTY VR keyboard for renaming crew and ships.
- Original procedural voxel crew, weapons and drones, weapon charge indicators, room-condition feedback, cross-shaped breaches and native miss cues.
- Surrounding stars and native-state-driven asteroid, sun, nebula/storm and pulsar environments.
@@ -66,11 +66,13 @@ The [controls guide](docs/CONTROLS.md) explains crew movement, room targeting, t
## Current state
The maintainer has played substantial portions of runs on Steam Frame and confirmed that earlier revisions are playable. The compact gameplay HUD now follows the headset first and stops above the ship only when it would intersect the hull or shield. Equipped weapon entries remain available on the wheel when no drones are installed. Room floors retain role icons and condition colors; health/status bars and counters are removed. System Power, storm-aware free power, native miss feedback and cross-shaped breaches remain available.
The maintainer has played substantial portions of runs on Steam Frame and confirmed that earlier revisions are playable. The compact gameplay HUD follows the headset first and stops above the ship only when it would intersect the hull or shield. Its collision clearance is now 8 cm, bringing it 6 cm closer. In-run Ship, pause-menu and Options windows appear only above the ship, without a duplicate on the headset HUD. Equipped weapon entries remain available on the wheel when no drones are installed. Room floors retain role icons and condition colors; health/status bars and counters are removed. System Power, storm-aware free power, native miss feedback and cross-shaped breaches remain available.
Core game input, capture, native state and graceful launch/exit have been verified in an isolated game. **Complete campaign coverage and measured stereo headset performance remain open.** Hacking target acceptance is verified; drone attachment/effect completion still needs encounter testing. The renderer presents hazards and some effects approximately while the original game remains authoritative.
The **current source** passed 38 Python tests and nine Godot suites in the prepared source folder. Desktop and VR wrappers passed combined launch/exit in desktop smoke mode, including the GitHub Desktop checkout's FTL-VR alias, with clean client logs and no bridge errors; a separate copied campaign also verified native weapon entries in the rendered wheel. VR preflight passed, while physical Steam Frame comfort and stereo performance remain unmeasured for these changes. Campaign hashes and game executable fingerprints were preserved. Historical Tactical delivery reached about **28–29 updates/second in desktop scene checks**; this is texture delivery, not headset FPS. A clean installation on a different machine has not yet been tested. See [STATUS.md](docs/STATUS.md) for details.
The **current source** passed 40 Python tests and focused Vulkan HUD/input checks. Native before/after captures verified that Ship, pause-menu and Options windows remain complete above the ship while their duplicate HUD pixels are absent. Both local folders passed their VR-wrapper desktop smoke launches with clean client logs and no bridge errors; setup and VR readiness checks passed separately. Campaign files remained unchanged. **Existing installations must refresh their local hooks** using [Installation step 4](docs/INSTALLATION.md#4-resolve-the-local-executable-hooks).
The preceding revision passed nine Godot suites and combined desktop launch/exit checks. Physical Steam Frame comfort and stereo performance remain to test for these changes. Historical Tactical delivery reached about **28–29 updates/second in desktop scene checks**; this is texture delivery, not headset FPS. A clean installation on a different machine has not yet been tested. See [STATUS.md](docs/STATUS.md) for details.
## Repository layout
+3 -1
View File
@@ -341,7 +341,9 @@ function attachHudPass() {
// Only supplemental draw calls are suppressed; the normal game draw runs.
const symbols={hud_pass:hudPassFlag};
let code='extern unsigned int hud_pass;\n';
const names=['TabbedWindowOnRender','ChoiceBoxOnRender','MouseControlOnRender','CommandGuiRenderPause','StarMapOnRender'];
// Esc and Options are separate render methods from the ship/store tabs.
// They belong only to the normal screen capture used by the world panel.
const names=['TabbedWindowOnRender','ChoiceBoxOnRender','MouseControlOnRender','CommandGuiRenderPause','StarMapOnRender','MenuScreenOnRender','OptionsScreenOnRender'];
for (let i=0;i<names.length;i++) {
if (!config.rvas[names[i]]) throw new Error('Missing native HUD method '+names[i]);
symbols['original_'+i]=Memory.alloc(Process.pointerSize);
+2 -2
View File
@@ -48,9 +48,9 @@ The native missed flag and a post-update event feed evasion feedback so brief mi
## Original HUD and floating windows
The game renders its original HUD into a separate native framebuffer. This retains native fonts, localization and values even when the normal backbuffer displays Tactical, the map or a window. The bridge removes unwanted world/enemy HUD pixels and preserves complete native window content for floating panels. Gameplay crops the upper native status and crew region to a fixed-size headset-relative panel, omitting the lower strip; Power/Shortcuts/the wheel supply those actions. Main menus and desktop Tactical/map views retain full framing.
The game renders its original HUD into a separate native framebuffer. This retains native fonts, localization and values even when the normal backbuffer displays Tactical, the map or a window. The bridge removes unwanted world/enemy HUD pixels and preserves complete native window content for floating panels. Supplemental capture suppresses native window draw methods, including the separate `MenuScreen::OnRender` and `OptionsScreen::OnRender` methods, so in-run panels are not duplicated on the headset HUD. Normal capture remains unchanged. Gameplay crops the upper native status and crew region to a fixed-size headset-relative panel, omitting the lower strip; Power/Shortcuts/the wheel supply those actions. Main menus and desktop Tactical/map views retain full framing.
[hud_anchor.gd](../scripts/hud_anchor.gd) gives the headset-relative pose priority and keeps fixed metre dimensions for readable text. Collision checks use the transformed hull/shield envelope and the panel's swept movement. Only a potential intersection engages the above-ship clamp; looking down cannot pass the HUD through the ship. The panel returns to headset-relative placement when clearance permits. Pause is attached above the same HUD panel.
[hud_anchor.gd](../scripts/hud_anchor.gd) gives the headset-relative pose priority and keeps fixed metre dimensions for readable text. Collision checks use the transformed hull/shield envelope and the panel's swept movement. Only a potential intersection engages the above-ship clamp, with 8 cm clearance; looking down cannot pass the HUD through the ship. The panel returns to headset-relative placement when clearance permits. Pause is attached above the same HUD panel.
Transport uses atomic raw RGBA files with an `FVR1` header, dimensions, sequence and timestamp. Tactical is captured at a target **30 Hz / 960×540**; map/windows retain **1280×720**. The independent HUD targets **10 Hz / 1280×720**. Native input coordinates remain **1280×720** regardless of capture resolution. PNG previews update at about 1 Hz and are diagnostics rather than the live transport.
+1 -1
View File
@@ -84,7 +84,7 @@ These are native key equivalents shown on buttons, not extra physical controller
Events, Store (including BUY/SELL), upgrades, crew and equipment windows float above the player ship. Their original localized controls stay interactive. Main menus remain complete, head-relative 2D views.
Gameplay uses a **compact HUD anchored to the headset**, retaining native upper status and the crew roster while removing the lower weapons/reactor/system/subsystem strip. Use Power, Shortcuts or the wheel for those lower-strip actions. The HUD keeps a fixed readable size and follows the headset whenever there is room. If that movement would carry the panel into the ship or shield, it stops above the ship until clearance permits headset-relative placement again. A raised or oversized table can therefore raise the panel during overlap. The hand panel retains visual and pointing priority where it overlaps the HUD. Desktop Tactical/map inspection keeps the complete native view.
Gameplay uses a **compact HUD anchored to the headset**, retaining native upper status and the crew roster while removing the lower weapons/reactor/system/subsystem strip. Use Power, Shortcuts or the wheel for those lower-strip actions. The HUD keeps a fixed readable size and follows the headset whenever there is room. If that movement would carry the panel into the ship or shield, it stops 8 cm above the ship until clearance permits headset-relative placement again. A raised or oversized table can therefore raise the panel during overlap. The hand panel retains visual and pointing priority where it overlaps the HUD. Ship, shop, pause-menu and Options windows opened during a run appear only above the ship; point at that floating panel to use them. Initial/hangar menus and desktop Tactical/map inspection keep the complete native view.
To rename a ship or crew member, click its original name-edit field. A floating **QWERTY keyboard** appears:
+2 -2
View File
@@ -29,13 +29,13 @@ After installing the documented Python requirements, run from the repository roo
python -m unittest discover -s tools -p "test_*.py"
```
The current prepared source passed **38 Python tests**, including empty native drone-list and portable-launcher regressions. The tests exercise synthetic archive/layout/font extraction, bridge schema/input translation, native-pixel filtering, raw frame publication and launcher preflight/error handling. They do not launch FTL. Temporary fixture files are created by the tests. Godot suites and focused native checks are recorded in [STATUS](STATUS.md); physical headset coverage remains separate.
The current source passed **40 Python tests**, including empty native drone-list, portable-launcher and modal-HUD hook/preflight regressions. The tests exercise synthetic archive/layout/font extraction, bridge schema/input translation, native-pixel filtering, raw frame publication and launcher preflight/error handling. They do not launch FTL. Temporary fixture files are created by the tests. Godot suites and focused native checks are recorded in [STATUS](STATUS.md); physical headset coverage remains separate.
## Godot checks
Use a **separate development checkout or disposable local-data folder** with the required extracted assets. Some suites write screenshots/test frames under `local_game_data/`; do not run them over an active production bridge or package those outputs. Create the local output folder before graphical suites if it is missing.
The nine suites below passed for the current prepared source in the configured development environment, including the latest HUD/wheel/bar corrections. See [STATUS](STATUS.md) for evidence and limits. A fresh source checkout lacks game assets; model/input/font checks may fail until local extraction is complete.
The nine suites below passed for the preceding HUD/wheel/bar revision in the configured development environment. The latest clearance/menu correction reran focused Vulkan HUD-layout and input checks, plus native before/after capture checks. See [STATUS](STATUS.md) for evidence and limits. A fresh source checkout lacks game assets; model/input/font checks may fail until local extraction is complete.
```powershell
godot --headless --xr-mode off --path . --script tools/test_combat.gd -- --demo
+3 -1
View File
@@ -106,7 +106,9 @@ Use `CApp.zhl` from the matching **win32/1.6.9** directory of the Hyperspace sou
"C:\Games\FTL-VR-Lab\hooks.json"
```
Keep the entire signature directory together. The resolver also reads neighboring files such as `CEvent.zhl`, `TextInput.zhl`, `CommandGui.zhl`, `TabbedWindow.zhl`, `ChoiceBox.zhl`, `MouseControl.zhl`, `StarMap.zhl`, `SystemControl.zhl`, `SystemBox.zhl` and `ShipSystem.zhl`. It checks unique signatures and structure probes, then stores the fingerprint and resolved addresses locally. Do not copy somebody else's `hooks.json` as a substitute.
Keep the entire signature directory together. The resolver also reads neighboring files such as `CEvent.zhl`, `TextInput.zhl`, `CommandGui.zhl`, `TabbedWindow.zhl`, `ChoiceBox.zhl`, `MouseControl.zhl`, `StarMap.zhl`, `MenuScreen.zhl`, `OptionsScreen.zhl`, `SystemControl.zhl`, `SystemBox.zhl` and `ShipSystem.zhl`. It checks unique signatures and structure probes, then stores the fingerprint and resolved addresses locally. Do not copy somebody else's `hooks.json` as a substitute.
**Updating an existing installation:** close the client and game, then rerun this step with the current `resolve_hooks.py` against your verified lab executable. The HUD/menu correction requires the new `MenuScreenOnRender` and `OptionsScreenOnRender` addresses. Keep the matching `MenuScreen.zhl` and `OptionsScreen.zhl` beside `CApp.zhl`. No game reinstall or save reset is needed. Run `CHECK-SETUP.cmd` afterward.
## 5. Extract local presentation assets
+15 -5
View File
@@ -10,9 +10,9 @@ This is a playable experimental client connected to the real game. It is suitabl
| --- | --- |
| Campaign | FTL runs its normal campaign, events, difficulty, combat rules, audio and saves |
| Ships | Dynamic local layouts, extruded hull presentation, rooms, weapon mounts, opposing bows in combat and stable movable encounter placement |
| HUD | Compact original status/crew panel follows the headset first at a fixed readable size; lower strip removed; clamps above the transformed hull/shield only when its movement would intersect the ship; full main menus remain head-relative |
| HUD | Compact original status/crew panel follows the headset first at a fixed readable size; lower strip removed; clamps 8 cm above the transformed hull/shield only when its movement would intersect the ship; full main menus remain head-relative |
| Navigation | Available actions only; actual sector map appears above/ahead of the pilot room and faces the viewer |
| Menus/dialogs | Main menus remain 2D; native shop/ship windows and event choices float in the encounter; BUY/SELL panels are retained |
| Menus/dialogs | Main menus remain 2D; in-run native shop/ship, pause-menu and Options windows appear only above the ship; event choices float in the encounter; BUY/SELL panels are retained |
| Crew | Native positions/tasks/selection, animated procedural race models, grab preview and native move orders; occupied crew face the viewer |
| Targeting | Weapon and beam room targeting, plus native mind-control, teleporter and hacking target routing |
| Systems | Dpad Up and a Navigation button open System Power; native capped reactor availability, storm loss and battery availability remain separate |
@@ -26,11 +26,21 @@ This is a playable experimental client connected to the real game. It is suitabl
## Verification recorded during development
### Latest HUD, wheel and launch corrections
### Latest HUD clearance and menu correction
HUD collision clearance is **8 cm**, reduced by 6 cm while preserving headset-following priority and the ship/shield intersection guard. Separate native pause-menu and Options draw methods are suppressed only during the supplemental HUD pass; the original capture still supplies their complete floating panels. In-run panel ownership also takes priority over a simultaneous native menu flag. Initial and hangar menus keep their full headset screen.
The current source passed **40 Python tests** and focused **Vulkan HUD-layout/input checks** on the RTX 4060 Ti. Native before/after captures from a separate QA profile verified Ship, pause-menu and Options panels: duplicate HUD pixels were absent after the fix and world-panel content was retained. These are desktop/native capture checks; physical Steam Frame comfort and stereo performance still need the maintainer's playtest.
The updated prepared folder passed `RUN-VR.cmd --smoke`, and the GitHub Desktop checkout passed `RUN-FTL-VR.cmd --smoke`: Vulkan desktop rendering, clean client logs, no bridge errors and disconnected bridges after graceful exit. Both folders passed `CHECK-SETUP.cmd`; VR launch `--check` passed separately. Production archive/settings were restored, hooks refreshed and all four campaign hashes verified again after both launches. Private QA fixtures are absent. The matching 120-file source package passed publication checks with no failures or warnings. These checks do not exercise the physical headset.
Existing installations must rerun [Installation step 4](INSTALLATION.md#4-resolve-the-local-executable-hooks), which now also resolves neighboring `MenuScreen.zhl` and `OptionsScreen.zhl` signatures. The launcher rejects older hook files before starting the game.
### Preceding HUD, wheel and launch corrections
The gameplay HUD uses a headset-relative pose whenever it has room. Collision checks include the transformed hull/shield envelope and the panel's swept movement, so looking down cannot carry it through the ship. The wheel now handles empty native drone lists without losing equipped weapon entries. Room-floor bars and counters are removed. Launcher corrections expose failures and keep runtime files local.
The current source passed **38 Python tests and nine Godot suites** in the prepared `FTL-Tabletop-VR` folder. The suites include native empty-drone-list normalization, defensive wheel parsing, headset-relative HUD placement/collision checks and removal of room-floor bars. UI, controller and frame-transport suites used actual GPU rendering on the RTX 4060 Ti.
That revision passed **38 Python tests and nine Godot suites** in the prepared `FTL-Tabletop-VR` folder. The suites include native empty-drone-list normalization, defensive wheel parsing, headset-relative HUD placement/collision checks and removal of room-floor bars. UI, controller and frame-transport suites used actual GPU rendering on the RTX 4060 Ti.
Actual `RUN-DESKTOP.cmd --smoke` and `RUN-VR.cmd --smoke` launched the isolated FTL process and Godot client, then exited successfully with clean client logs and no bridge errors. The GitHub Desktop checkout's `RUN-FTL-VR.cmd --smoke` alias passed the same combined launch/exit check. These smoke tests use desktop rendering; VR preflight passed separately. A copied save profile opened the current campaign, paused it and supplied actual Artemis Missiles and Burst Laser Mark II entries to a GPU-rendered wheel check; the drone-equipment collection was normalized to a list and bridge errors remained empty.
@@ -56,7 +66,7 @@ Production combined Vulkan launch/save/exit smoke passed: exit 0, clean client l
| Hacking | Enemy room targeting accepted; attachment/effect completion remains unverified |
| UI | Native HUD during Tactical/map/store/event/ship modes; enemy-region transparency; BUY/SELL content; rename input and original fonts checked across development revisions |
| Drones | Native equipment/special/global lists deduplicated; actual combat and interior battle-drone state inspected |
| Automated tests | Current prepared source passed 38 Python tests and nine Godot suites; UI/controller/transport checks used actual GPU rendering |
| Automated tests | Current source passed 40 Python tests and focused Vulkan HUD/input checks; the preceding revision passed nine Godot suites with GPU UI/controller/transport checks |
| Desktop graphics | Vulkan rendering and model/UI inspection checked on RTX 4060 Ti 8 GB |
| Save handling | Current desktop-wrapper launch/exit and copied-profile native checks preserved all four original campaign hashes |
| Steam Frame play | Maintainer confirmed playability and substantial partial runs; latest changes need further hardware coverage |
+2
View File
@@ -18,6 +18,7 @@ Start with `CHECK-SETUP.cmd`, or `CHECK-SETUP.cmd --desktop` if testing without
| Lab destination rejected | Use a new empty separate directory outside the installed game. A nonempty unrelated directory is intentionally refused. |
| `Hyperspace.ftl`, loader DLL or ftlman error | Verify the full release folder structure and the ftlman executable/version described in Installation. |
| Resolver reports a missing/ambiguous signature | Use the matching win32/1.6.9 signature directory from Hyperspace source, with all neighboring `.zhl` files. Do not use other people's hook addresses. |
| “Regenerate lab hooks.json ... live native HUD capture” after updating | Close the game and rerun Installation step 4 with the current resolver. The matching signature directory must include `MenuScreen.zhl` and `OptionsScreen.zhl`. Then rerun `CHECK-SETUP.cmd`. |
| Recorded original installation unavailable | The bridge still reads the original `ftl.dat` for newly encountered ships. Restore that location or rebuild the lab/config against the new installation. |
To use a real Python installation outside PATH, set `FTLVR_PYTHON` to its executable before running `SETUP.cmd` (see Installation). These scripts do not use the Microsoft Store alias. Set `FTLVR_NO_PAUSE=1` only when calling the launchers from an automated script that captures their output; otherwise failures remain open so they can be read.
@@ -31,6 +32,7 @@ To use a real Python installation outside PATH, set `FTLVR_PYTHON` to its execut
| Bridge timeout or exits immediately | Read `local_game_data/logs/bridge.log`. Confirm the lab is activated, its executable matches `hooks.json`, Hyperspace exists and extraction is complete. |
| “Bridge already running” | Close the existing client and allow graceful shutdown before retrying. Do not start several sessions against one VR save profile. |
| Black or stale HUD/tactical image | Check `bridge_status.json` for fresh heartbeat/state/capture and errors. Check the logs. Do not judge the live Tactical stream from diagnostic PNGs: PNG previews update only once per second. |
| Ship, pause-menu or Options window appears both on the HUD and above the ship | Update this checkout's source and refresh its configured lab hooks using Installation step 4. Current capture keeps in-run windows only on the floating panel while retaining the status/crew HUD. |
| Pointer missing or controller unresponsive | Confirm both controllers are tracked in SteamVR. Inspect the in-game warning, Help diagram and `xr_input.json` for each hand's tracking/profile/trigger values. Some fallback controller bindings remain untested. |
| Tactical looks slow | Report headset settings and whether the 3D scene, HUD or Tactical capture is slow. The live Tactical stream targets 30 Hz; mono desktop capture measurements are not stereo headset FPS. |
| Poor performance | Close unrelated GPU-intensive programs, record SteamVR resolution/refresh rate and note the encounter type. This alpha still needs physical stereo frame-pacing measurements and broad campaign QA. |
+1 -1
View File
@@ -2,7 +2,7 @@ extends RefCounted
# Follow the headset first. Only the panel's path toward the ship engages the
# world-height stop, so a distant or side-on table never drags the HUD around.
const CLEARANCE := 0.14
const CLEARANCE := 0.08
const HEAD_OFFSET := Vector3(0.0, -0.12, -1.30)
const POSITION_TIME := 0.12
const PANEL_THICKNESS := 0.008
+5 -1
View File
@@ -250,7 +250,11 @@ func _create_hud() -> void:
func _gameplay_hud_mode() -> bool:
if not bool(hud_state.get("ready", demo_mode)) or str(hud_state.get("ui_mode", "")) == "menu":
if not bool(hud_state.get("ready", demo_mode)):
return false
# In-run native windows have a separate world surface. A simultaneous
# native menu flag must not expand the HUD into a second copy of that window.
if str(hud_state.get("ui_mode", "")) == "menu" and not bool(hud_state.get("panel_open", false)):
return false
# Desktop preview still needs the complete screen for its Tactical/map view;
# in VR those views have their own hand/world surfaces with native coordinates.
+1 -1
View File
@@ -61,7 +61,7 @@ def preflight(config, desktop=False):
raise ValueError('Regenerate lab hooks.json with tools/resolve_hooks.py for controller modifiers')
if not all(name in hooks.get('rvas',{}) for name in ('OnTextInput','OnTextEvent','TextInputOnRender','TextInputStart')):
raise ValueError('Regenerate lab hooks.json with tools/resolve_hooks.py for native renaming')
if not all(name in hooks.get('rvas',{}) for name in ('CommandGuiRenderStatic','CommandGuiRenderPause','TabbedWindowOnRender','ChoiceBoxOnRender','MouseControlOnRender','StarMapOnRender')):
if not all(name in hooks.get('rvas',{}) for name in ('CommandGuiRenderStatic','CommandGuiRenderPause','TabbedWindowOnRender','ChoiceBoxOnRender','MouseControlOnRender','StarMapOnRender','MenuScreenOnRender','OptionsScreenOnRender')):
raise ValueError('Regenerate lab hooks.json with tools/resolve_hooks.py for live native HUD capture')
if not marker.get('activated') or not (lab/'FTLGame.exe').is_file() or hashlib.sha1((lab/'FTLGame.exe').read_bytes()).hexdigest() != hooks.get('sha1'):
raise ValueError('Lab is not activated or its executable fingerprint changed')
+2 -1
View File
@@ -79,7 +79,8 @@ def resolve(executable: Path, signatures: Path) -> dict:
# render advances ship, jump or projectile animations.
for class_name,method_names in {'CommandGui':('RenderStatic','RenderPause'),
'TabbedWindow':('OnRender',),'ChoiceBox':('OnRender',),
'MouseControl':('OnRender',),'StarMap':('OnRender',)}.items():
'MouseControl':('OnRender',),'StarMap':('OnRender',),
'MenuScreen':('OnRender',),'OptionsScreen':('OnRender',)}.items():
source=(signatures.parent/(class_name+'.zhl')).read_text()
for signature,name in re.findall(r'"([.0-9a-fA-F?]+)":[^\n]*\n[^\n]*'+class_name+r'::(\w+)\(',source):
if name not in method_names: continue
+3 -1
View File
@@ -129,7 +129,9 @@ def room_pixel(state, ship, room_id):
def full_screen_capture(state):
# Native shops, upgrades, crew and equipment are world panels, never HUDs.
return not state.get('ready') or state.get('ui_mode','menu') == 'menu'
# An in-run window owns its pixels even if the native menu flag also sets
# ui_mode to menu. Initial/hangar screens keep their full headset view.
return not state.get('ready') or (state.get('ui_mode','menu') == 'menu' and not state.get('panel_open'))
def world_gameplay_available(state):
+7
View File
@@ -56,6 +56,13 @@ class BridgeTests(unittest.TestCase):
self.assertTrue(full_screen_capture({'ready':True,'ui_mode':'menu'}))
self.assertFalse(full_screen_capture(dict(base,panel_open=True,panel_kind='shop')))
def test_in_run_modal_window_never_duplicates_on_full_headset_screen(self):
for kind in ('ship', 'window', 'options', 'sell'):
with self.subTest(kind=kind):
self.assertFalse(full_screen_capture({'ready':True,'ui_mode':'menu',
'panel_open':True,'panel_kind':kind}))
self.assertTrue(full_screen_capture({'ready':False,'ui_mode':'menu','panel_open':True}))
def test_enemy_frame_removed_without_touching_player_widgets(self):
pixels=np.full((720,1280,4),255,dtype=np.uint8)
result=remove_enemy_hud(pixels)
+4
View File
@@ -60,6 +60,10 @@ func run() -> void:
scene._position_hud(0.0, true)
check(scene.hud_anchor.blocked and scene.hud_anchor.lift > 0, "Looking down toward the ship must engage the HUD height stop")
_check_clearance(scene, "Looking down must not tunnel the HUD through the ship")
var stopped_ship: AABB = Anchor.transformed_bounds(scene._player_hud_local_bounds(), scene.player_ship.global_transform)
var stopped_panel: AABB = Anchor.panel_bounds(scene.hud_surface.global_transform, scene.hud_surface.surface_size)
var gap: float = stopped_panel.position.y - stopped_ship.end.y
check(gap >= .08 and gap < .10, "The blocked HUD must sit within ten centimetres of the ship while leaving a safe gap")
var clearance_lift: float = scene.hud_anchor.lift
scene.camera.rotation.y = PI
scene._position_hud(1.0 / 90)
+9
View File
@@ -107,6 +107,15 @@ func run() -> void:
scene._position_hud(0.0, true)
check(is_equal_approx(scene.nav_panel.scale.x, 0.6) and scene.hud_surface.get_parent()==scene and scene.hud_surface.source_rect==scene.GAMEPLAY_HUD_RECT,"Gameplay HUD must retain native upper/crew pixels, exclude the bottom strip and use independent world placement")
check(scene.hud_surface.render_order == 100 and scene.panel_theme.get_child(1).material_override.render_priority > scene.pause_label.render_priority and scene.tracking_label.render_priority < 120,"Hand screen must render over all HUD layers, including pause and modifier labels")
var hud_mode_state: Dictionary = scene.hud_state.duplicate(true)
scene.hud_state = {"ready":true,"ui_mode":"menu","panel_open":true}
scene._sync_hud_layout()
check(scene.gameplay_hud and scene.hud_surface.source_rect == scene.GAMEPLAY_HUD_RECT,"An in-run world window must not promote the headset HUD into a second full menu")
scene.hud_state = {"ready":false,"ui_mode":"menu","panel_open":true}
scene._sync_hud_layout()
check(not scene.gameplay_hud and scene.hud_surface.source_rect == Rect2(0,0,1280,720),"Initial and hangar menus must keep their full headset display")
scene.hud_state = hud_mode_state
scene._sync_hud_layout()
check(scene.help_label.get_script().resource_path.ends_with("controller_help.gd"),"Help must use a controller infographic instead of plain text")
check(scene.hover_marker.mesh.radius <= 0.003 and scene.right_laser.mesh.top_radius <= 0.001,"Pointer endpoint must support precise native UI selection")
scene.wheel.global_position = scene.camera.get_camera_transform().origin + Vector3(0.3,-0.5,-0.4)
+10 -1
View File
@@ -36,7 +36,7 @@ class LaunchSetupTests(unittest.TestCase):
names = ("GetShiftState", "GetCtrlState", "ForceAutofireFlag", "OnTextInput",
"OnTextEvent", "TextInputOnRender", "TextInputStart", "CommandGuiRenderStatic",
"CommandGuiRenderPause", "TabbedWindowOnRender", "ChoiceBoxOnRender",
"MouseControlOnRender", "StarMapOnRender")
"MouseControlOnRender", "StarMapOnRender", "MenuScreenOnRender", "OptionsScreenOnRender")
self.hooks = self.lab / "hooks.json"
self.hooks.write_text(json.dumps({"rvas": dict.fromkeys(names, 1),
"sha1": hashlib.sha1((self.lab / "FTLGame.exe").read_bytes()).hexdigest()}))
@@ -63,6 +63,15 @@ class LaunchSetupTests(unittest.TestCase):
def test_shared_preflight_accepts_complete_desktop_setup(self):
self.assertEqual(launch.preflight(self.config, desktop=True)["mode"], "desktop")
def test_old_hooks_require_modal_hud_capture_update(self):
value = json.loads(self.hooks.read_text())
for name in ("MenuScreenOnRender", "OptionsScreenOnRender"):
with self.subTest(name=name):
incomplete = dict(value, rvas={key: address for key, address in value["rvas"].items() if key != name})
self.hooks.write_text(json.dumps(incomplete))
with self.assertRaisesRegex(ValueError, "Regenerate lab hooks.json.*live native HUD capture"):
launch.preflight(self.config, desktop=True)
def test_missing_configuration_explains_setup(self):
with self.assertRaisesRegex(ValueError, "Run SETUP.cmd"):
launch.load_config(self.local / "launcher.json")