feat(simulation): auto-pause sim on implant-fullscreen — inspection substrate (T-970)

D-226 layer 1. World-advancing phases gated on pause: Movement/Storyteller/Knowledge/TickAdvance set-gated via sim_not_paused; Simulation + Economy gated per-system at their registration sites — collect_sound_events and serve_econ_state_query stay unconditioned (transient-buffer clear + paused-allowed query; set-gating Simulation leaked a stale tick-7 footstep into frozen snapshots — caught by golden_suite, fixed without touching the fixture; regression test encodes the bug shape). New PlayerAction::AutoPause/AutoResume + AutoPauseState resource implement Option A reconciliation: auto-resume only fires if auto-pause caused the pause; manual pause and Half rate survive implant open/close. PauseParams SystemParam bundle keeps process_player_input under the 16-param ceiling (BookmarkInputParams precedent). Client: HudGroups.gameplay_occluded now sends AutoPause/AutoResume via send_named_action; 5 gdUnit tests + 7 Rust tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 15:44:56 +02:00
co-authored by Claude Fable 5
parent 672a583e64
commit 6bda9f1697
12 changed files with 844 additions and 11 deletions
+22
View File
@@ -45,6 +45,28 @@ var _active_app: String = "" # currently focused implant app ("" = none)
var _active_mode: Mode = Mode.GAMEPLAY
func _ready() -> void:
# T-970 (D-226 layer 1): auto-pause/auto-resume the sim when a fullscreen
# implant app occludes gameplay. AutoPause/AutoResume are distinct
# PlayerAction variants from the manual Pause/Unpause (Space bar, D-088) —
# the server tracks whether ITS OWN auto-pause caused the current pause
# (AutoPauseState) so a pre-existing manual pause or Half rate survives
# implant open/close untouched (see server/src/simulation/input.rs and
# server/src/simulation/time.rs).
gameplay_occluded.connect(_on_gameplay_occluded_auto_pause)
## Sends AutoPause/AutoResume via SimBridge's outbound queue. Uses
## send_named_action (protocol-level, not bound to an InputMapper.Action
## keybind) — the same mechanism as RequestBookmarkCatalog — since occlusion
## is a UI-state transition, not a physical input.
func _on_gameplay_occluded_auto_pause(occluded: bool) -> void:
if occluded:
SimBridge.send_named_action("AutoPause")
else:
SimBridge.send_named_action("AutoResume")
func register(node: CanvasItem, group: String) -> void:
if not _groups.has(group):
_groups[group] = []