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

+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")