Merge pull request 'refactor(engine): first ambiguity burn-down batch — 302 → 198 pairs' (#146) from refactor/ambiguity-burndown into master
This commit was merged in pull request #146.
This commit is contained in:
@@ -570,8 +570,8 @@ impl Plugin for CardPlugin {
|
||||
tick_flip_anim,
|
||||
update_drag_shadow,
|
||||
update_card_shadows_on_drag.after(sync_cards_on_change),
|
||||
tick_hint_highlight,
|
||||
handle_right_click,
|
||||
tick_hint_highlight.after(GameMutation),
|
||||
handle_right_click.after(GameMutation),
|
||||
tick_right_click_highlights,
|
||||
clear_right_click_highlights_on_state_change.after(GameMutation),
|
||||
clear_right_click_highlights_on_pause,
|
||||
@@ -580,7 +580,9 @@ impl Plugin for CardPlugin {
|
||||
.after(GameMutation)
|
||||
.run_if(resource_changed::<GameStateResource>),
|
||||
collect_resize_events.after(LayoutSystem::UpdateOnResize),
|
||||
snap_cards_on_window_resize.after(collect_resize_events),
|
||||
snap_cards_on_window_resize
|
||||
.after(collect_resize_events)
|
||||
.after(GameMutation),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -63,6 +63,18 @@ pub struct GameOverScreen;
|
||||
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct GameMutation;
|
||||
|
||||
/// System set for every writer of [`crate::events::NewGameRequestEvent`].
|
||||
///
|
||||
/// Many UI entry points fire this trigger (buttons, keyboard, modals,
|
||||
/// mode pickers). Their relative append order within a frame is
|
||||
/// meaningless — consumers drain the whole queue — so members are
|
||||
/// registered `.in_set(NewGameRequestWriters).ambiguous_with(NewGameRequestWriters)`
|
||||
/// to declare writer-vs-writer order irrelevant instead of leaving it as an
|
||||
/// ambiguity (#143). Only ever combine with `.ambiguous_with` on the same
|
||||
/// set; do NOT hang ordering edges off this set.
|
||||
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct NewGameRequestWriters;
|
||||
|
||||
/// Persistence path for the in-progress game state file. `None` disables I/O.
|
||||
#[derive(Resource, Debug, Clone)]
|
||||
pub struct GameStatePath(pub Option<PathBuf>);
|
||||
@@ -208,7 +220,13 @@ impl Plugin for GamePlugin {
|
||||
.add_message::<AppLifecycle>()
|
||||
// add_message is idempotent; SettingsPlugin also registers this.
|
||||
.add_message::<crate::settings_plugin::SettingsChangedEvent>()
|
||||
.add_systems(Update, poll_pending_new_game_seed.before(GameMutation))
|
||||
.add_systems(
|
||||
Update,
|
||||
poll_pending_new_game_seed
|
||||
.before(GameMutation)
|
||||
.in_set(NewGameRequestWriters)
|
||||
.ambiguous_with(NewGameRequestWriters),
|
||||
)
|
||||
.add_systems(
|
||||
Update,
|
||||
(handle_new_game, handle_draw, handle_move, handle_undo)
|
||||
@@ -217,19 +235,40 @@ impl Plugin for GamePlugin {
|
||||
)
|
||||
.add_systems(Update, check_no_moves.after(GameMutation))
|
||||
.add_systems(Update, record_replay_on_win.after(GameMutation))
|
||||
.add_systems(Update, handle_confirm_input.after(GameMutation))
|
||||
.add_systems(Update, handle_confirm_button_input.after(GameMutation))
|
||||
.add_systems(Update, handle_game_over_input.after(GameMutation))
|
||||
.add_systems(Update, handle_game_over_button_input.after(GameMutation))
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
handle_confirm_input,
|
||||
handle_confirm_button_input,
|
||||
handle_game_over_input,
|
||||
handle_game_over_button_input,
|
||||
)
|
||||
.after(GameMutation)
|
||||
.in_set(NewGameRequestWriters)
|
||||
.ambiguous_with(NewGameRequestWriters),
|
||||
)
|
||||
// Restore prompt: spawn the modal once the splash is gone,
|
||||
// route Continue / New Game intents back into the existing
|
||||
// GameMutation flow.
|
||||
.add_systems(Update, spawn_restore_prompt_if_pending)
|
||||
.add_systems(Update, handle_restore_prompt.before(GameMutation))
|
||||
.add_systems(Update, sync_settings_to_game.before(GameMutation))
|
||||
// All three pre-mutation game-state writers are chained: elapsed
|
||||
// time ticks first, settings sync next, then the restore prompt —
|
||||
// a deterministic spine instead of three unordered ResMut holders
|
||||
// (ambiguity burn-down, #143).
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
tick_elapsed_time,
|
||||
sync_settings_to_game,
|
||||
handle_restore_prompt
|
||||
.in_set(NewGameRequestWriters)
|
||||
.ambiguous_with(NewGameRequestWriters),
|
||||
)
|
||||
.chain()
|
||||
.before(GameMutation),
|
||||
)
|
||||
.init_resource::<AutoSaveTimer>()
|
||||
.add_systems(Update, tick_elapsed_time)
|
||||
.add_systems(Update, auto_save_game_state)
|
||||
.add_systems(Update, auto_save_game_state.after(GameMutation))
|
||||
.add_systems(Last, save_game_state_on_exit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ use crate::events::{
|
||||
UndoRequestEvent, WinStreakMilestoneEvent,
|
||||
};
|
||||
use crate::font_plugin::FontResource;
|
||||
use crate::game_plugin::GameMutation;
|
||||
use crate::game_plugin::{GameMutation, NewGameRequestWriters};
|
||||
#[cfg(target_os = "android")]
|
||||
use crate::input_plugin::TouchDragSet;
|
||||
use crate::layout::HUD_BAND_HEIGHT;
|
||||
@@ -478,10 +478,12 @@ impl Plugin for HudPlugin {
|
||||
.add_systems(Update, announce_auto_complete.after(GameMutation))
|
||||
.add_systems(
|
||||
Update,
|
||||
update_selection_hud.run_if(
|
||||
resource_exists_and_changed::<SelectionState>
|
||||
.or(resource_exists_and_changed::<GameStateResource>),
|
||||
),
|
||||
update_selection_hud
|
||||
.after(GameMutation)
|
||||
.run_if(
|
||||
resource_exists_and_changed::<SelectionState>
|
||||
.or(resource_exists_and_changed::<GameStateResource>),
|
||||
),
|
||||
)
|
||||
.add_systems(Update, update_hud_typography)
|
||||
.add_systems(
|
||||
@@ -503,13 +505,17 @@ impl Plugin for HudPlugin {
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
handle_new_game_button,
|
||||
handle_new_game_button
|
||||
.in_set(NewGameRequestWriters)
|
||||
.ambiguous_with(NewGameRequestWriters),
|
||||
handle_undo_button,
|
||||
handle_pause_button,
|
||||
handle_help_button,
|
||||
handle_hint_button,
|
||||
handle_hint_button.after(GameMutation),
|
||||
handle_modes_button,
|
||||
handle_mode_option_click,
|
||||
handle_mode_option_click
|
||||
.in_set(NewGameRequestWriters)
|
||||
.ambiguous_with(NewGameRequestWriters),
|
||||
handle_modes_backdrop_click,
|
||||
close_modes_popover_on_escape,
|
||||
handle_menu_button,
|
||||
|
||||
@@ -38,7 +38,7 @@ mod tests {
|
||||
/// ordering edge — add `.before`/`.after` (order matters) or
|
||||
/// `.ambiguous_with` (provably order-independent) at the registration
|
||||
/// site. When triage lowers the real count, lower this constant too.
|
||||
const AMBIGUITY_BASELINE: usize = 302;
|
||||
const AMBIGUITY_BASELINE: usize = 198;
|
||||
|
||||
fn cluster_app() -> App {
|
||||
let mut app = App::new();
|
||||
|
||||
@@ -11,6 +11,7 @@ use solitaire_core::{FOUNDATIONS, TABLEAUS};
|
||||
use solitaire_core::Suit;
|
||||
|
||||
use crate::events::{HintVisualEvent, StateChangedEvent};
|
||||
use crate::game_plugin::GameMutation;
|
||||
use crate::hud_plugin::HudVisibility;
|
||||
use crate::layout::{
|
||||
Layout, LayoutResource, LayoutSystem, TABLE_COLOUR, apply_dynamic_tableau_fan, compute_layout,
|
||||
@@ -103,7 +104,7 @@ impl Plugin for TablePlugin {
|
||||
apply_theme_on_settings_change,
|
||||
apply_hint_pile_highlight,
|
||||
tick_hint_pile_highlights,
|
||||
sync_pile_marker_visibility,
|
||||
sync_pile_marker_visibility.after(GameMutation),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user