From 3725a3df5e28ff868f9791fec75a4270860774e2 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 25 Feb 2026 15:43:53 +0100 Subject: [PATCH] =?UTF-8?q?fix(client):=20address=20PR=20#70=20review=20?= =?UTF-8?q?=E2=80=94=20event=20leak,=20quit=20flush,=20notification=20colo?= =?UTF-8?q?r?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - input_mapper.gd: call set_input_as_handled() before early return on empty game_id so F5/F6 events don't propagate to other handlers - session_manager.gd: defer scene change by one frame after buffering quit-save so SimBridge._process() flushes the outbound buffer - monologue_display.gd: tag queued notifications with is_notification flag so drain path routes to _show_notification_line (correct color) instead of _show_line (lattice-profile fallback color) Co-Authored-By: Claude Opus 4.6 --- client/scripts/autoloads/input_mapper.gd | 1 + client/scripts/autoloads/session_manager.gd | 11 ++++++++++- client/ui/monologue_display.gd | 15 +++++++++++++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/client/scripts/autoloads/input_mapper.gd b/client/scripts/autoloads/input_mapper.gd index f947d61b8..6128d4b4d 100644 --- a/client/scripts/autoloads/input_mapper.gd +++ b/client/scripts/autoloads/input_mapper.gd @@ -128,6 +128,7 @@ func _unhandled_input(event: InputEvent) -> void: if action == Action.SAVE_GAME or action == Action.LOAD_GAME: var game_id := GameState.current_game_id if game_id.is_empty(): + get_viewport().set_input_as_handled() return # No active session — ignore save/load entry["action_data"] = {"path": "user://saves/" + game_id + "/quicksave.sav"} input_queue.append(entry) diff --git a/client/scripts/autoloads/session_manager.gd b/client/scripts/autoloads/session_manager.gd index 5b719b8ef..87bd3c90d 100644 --- a/client/scripts/autoloads/session_manager.gd +++ b/client/scripts/autoloads/session_manager.gd @@ -85,6 +85,8 @@ func quit_to_menu() -> void: func _do_quit_to_menu() -> void: _cleanup_quit_dialog() # #554: Trigger quicksave before navigating to menu. + # send_input() buffers the command — defer scene change by one frame so + # SimBridge._process() flushes the outbound buffer before teardown. if not GameState.current_game_id.is_empty(): var path := "user://saves/" + GameState.current_game_id + "/quicksave.sav" SimBridge.send_input({ @@ -92,7 +94,14 @@ func _do_quit_to_menu() -> void: "timestamp_msec": Time.get_ticks_msec(), "action_data": {"path": path}, }) - GameState.current_game_id = "" + GameState.current_game_id = "" + _navigate_to_menu.call_deferred() + else: + GameState.current_game_id = "" + get_tree().change_scene_to_file(MENU_SCENE) + + +func _navigate_to_menu() -> void: get_tree().change_scene_to_file(MENU_SCENE) diff --git a/client/ui/monologue_display.gd b/client/ui/monologue_display.gd index 0b9eacba8..37a52844d 100644 --- a/client/ui/monologue_display.gd +++ b/client/ui/monologue_display.gd @@ -64,7 +64,10 @@ func _process(delta: float) -> void: var now := float(Time.get_ticks_msec()) if now >= _next_fade_in_msec: var next: Dictionary = _queue.pop_front() - _show_line(next.text, next.duration, next.priority, next.is_urgent, next.lattice_profile) + if next.get("is_notification", false): + _show_notification_line(next.text) + else: + _show_line(next.text, next.duration, next.priority, next.is_urgent, next.lattice_profile) # Display a monologue line. @@ -82,7 +85,15 @@ func show_notification(text: String) -> void: if _visible.size() < MAX_VISIBLE and now >= _next_fade_in_msec: _show_notification_line(text) else: - _enqueue(text, _NOTIFICATION_DURATION, 1, false, "") + var entry := {text = text, duration = _NOTIFICATION_DURATION, priority = 1, is_urgent = false, lattice_profile = "", is_notification = true} + if _queue.size() < MAX_QUEUE: + _queue.append(entry) + _queue.sort_custom(func(a: Dictionary, b: Dictionary) -> bool: return a.priority > b.priority) + else: + var lowest := _lowest_priority_idx() + if 1 >= _queue[lowest].priority: + _queue[lowest] = entry + _queue.sort_custom(func(a: Dictionary, b: Dictionary) -> bool: return a.priority > b.priority) func show_monologue(text: String, duration: float, priority: int = 2, is_urgent: bool = false) -> void: