refactor(engine): ambiguity burn-down batch 2 — SettingsResource cleared, 198 → 171
Test / test (pull_request) Successful in 28m7s
Test / test (pull_request) Successful in 28m7s
New SettingsMutation set: the per-frame settings mutators (handle_volume_keys → record_window_geometry_changes → persist_window_geometry_after_debounce) run as a deterministic chain ordered before GameMutation, so every reader already after GameMutation observes the current frame's settings transitively. The four readers outside that ordering (modal enter-speed chain, focus-ring pulse, HUD avatar, and the game plugin's pre-mutation chain) are ordered after the set explicitly. SettingsResource ambiguities: 21 → 0. Baseline ratchets 198 → 171. Refs #143 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -265,6 +265,7 @@ impl Plugin for GamePlugin {
|
|||||||
.ambiguous_with(NewGameRequestWriters),
|
.ambiguous_with(NewGameRequestWriters),
|
||||||
)
|
)
|
||||||
.chain()
|
.chain()
|
||||||
|
.after(crate::settings_plugin::SettingsMutation)
|
||||||
.before(GameMutation),
|
.before(GameMutation),
|
||||||
)
|
)
|
||||||
.init_resource::<AutoSaveTimer>()
|
.init_resource::<AutoSaveTimer>()
|
||||||
|
|||||||
@@ -473,7 +473,13 @@ impl Plugin for HudPlugin {
|
|||||||
apply_hud_visibility.before(LayoutSystem::UpdateOnResize),
|
apply_hud_visibility.before(LayoutSystem::UpdateOnResize),
|
||||||
)
|
)
|
||||||
.add_systems(Update, restore_hud_on_modal)
|
.add_systems(Update, restore_hud_on_modal)
|
||||||
.add_systems(Update, (update_hud_avatar, handle_avatar_button))
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
update_hud_avatar.after(crate::settings_plugin::SettingsMutation),
|
||||||
|
handle_avatar_button,
|
||||||
|
),
|
||||||
|
)
|
||||||
.add_systems(Update, update_won_previously.after(GameMutation))
|
.add_systems(Update, update_won_previously.after(GameMutation))
|
||||||
.add_systems(Update, announce_auto_complete.after(GameMutation))
|
.add_systems(Update, announce_auto_complete.after(GameMutation))
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ mod tests {
|
|||||||
/// ordering edge — add `.before`/`.after` (order matters) or
|
/// ordering edge — add `.before`/`.after` (order matters) or
|
||||||
/// `.ambiguous_with` (provably order-independent) at the registration
|
/// `.ambiguous_with` (provably order-independent) at the registration
|
||||||
/// site. When triage lowers the real count, lower this constant too.
|
/// site. When triage lowers the real count, lower this constant too.
|
||||||
const AMBIGUITY_BASELINE: usize = 198;
|
const AMBIGUITY_BASELINE: usize = 171;
|
||||||
|
|
||||||
fn cluster_app() -> App {
|
fn cluster_app() -> App {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
|
|||||||
@@ -79,6 +79,14 @@ pub struct PendingWindowGeometry {
|
|||||||
#[derive(Message, Debug, Clone)]
|
#[derive(Message, Debug, Clone)]
|
||||||
pub struct SettingsChangedEvent(pub Settings);
|
pub struct SettingsChangedEvent(pub Settings);
|
||||||
|
|
||||||
|
/// System set for the systems that mutate [`SettingsResource`] every frame
|
||||||
|
/// (hotkeys and window-geometry persistence). Ordered before
|
||||||
|
/// [`crate::game_plugin::GameMutation`]; readers of settings should sit
|
||||||
|
/// after this set (directly, or transitively via `.after(GameMutation)`)
|
||||||
|
/// so they observe the current frame's settings deterministically (#143).
|
||||||
|
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SettingsMutation;
|
||||||
|
|
||||||
/// Marker on the root Settings panel entity.
|
/// Marker on the root Settings panel entity.
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
pub struct SettingsPanel;
|
pub struct SettingsPanel;
|
||||||
@@ -372,15 +380,31 @@ impl Plugin for SettingsPlugin {
|
|||||||
// also runs cleanly under `MinimalPlugins` (tests).
|
// also runs cleanly under `MinimalPlugins` (tests).
|
||||||
.add_message::<WindowResized>()
|
.add_message::<WindowResized>()
|
||||||
.add_message::<WindowMoved>()
|
.add_message::<WindowMoved>()
|
||||||
|
// Settings changes land before game logic runs: the mutator
|
||||||
|
// chain (volume keys → geometry record → geometry persist) is a
|
||||||
|
// deterministic spine, and the whole set precedes GameMutation so
|
||||||
|
// every reader already ordered after GameMutation sees this
|
||||||
|
// frame's settings transitively (ambiguity burn-down, #143).
|
||||||
|
.configure_sets(
|
||||||
|
Update,
|
||||||
|
SettingsMutation.before(crate::game_plugin::GameMutation),
|
||||||
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
handle_volume_keys,
|
handle_volume_keys,
|
||||||
|
record_window_geometry_changes,
|
||||||
|
persist_window_geometry_after_debounce,
|
||||||
|
)
|
||||||
|
.chain()
|
||||||
|
.in_set(SettingsMutation),
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
toggle_settings_screen,
|
toggle_settings_screen,
|
||||||
scroll_settings_panel,
|
scroll_settings_panel,
|
||||||
crate::ui_modal::touch_scroll_panel::<SettingsPanelScrollable>,
|
crate::ui_modal::touch_scroll_panel::<SettingsPanelScrollable>,
|
||||||
record_window_geometry_changes,
|
|
||||||
persist_window_geometry_after_debounce,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ impl Plugin for UiFocusPlugin {
|
|||||||
clear_hud_focus_on_unhover,
|
clear_hud_focus_on_unhover,
|
||||||
handle_focus_keys,
|
handle_focus_keys,
|
||||||
update_focus_overlay,
|
update_focus_overlay,
|
||||||
pulse_focus_overlay,
|
pulse_focus_overlay.after(crate::settings_plugin::SettingsMutation),
|
||||||
)
|
)
|
||||||
.chain(),
|
.chain(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -695,7 +695,8 @@ impl Plugin for UiModalPlugin {
|
|||||||
advance_modal_enter,
|
advance_modal_enter,
|
||||||
paint_modal_buttons,
|
paint_modal_buttons,
|
||||||
)
|
)
|
||||||
.chain(),
|
.chain()
|
||||||
|
.after(crate::settings_plugin::SettingsMutation),
|
||||||
);
|
);
|
||||||
// Click-outside-to-dismiss is independent of the open
|
// Click-outside-to-dismiss is independent of the open
|
||||||
// animation chain — it reads `just_pressed(Left)` and runs
|
// animation chain — it reads `just_pressed(Left)` and runs
|
||||||
|
|||||||
Reference in New Issue
Block a user