Merge pull request 'refactor(engine): ambiguity burn-down batch 3 — board paint chain (171 → 47)' (#148) from refactor/ambiguity-board-visuals into master
This commit was merged in pull request #148.
This commit is contained in:
@@ -533,6 +533,17 @@ fn should_apply_resize(now_secs: f32, last_applied_secs: f32) -> bool {
|
|||||||
/// Renders cards by reading `GameStateResource` on `StateChangedEvent`.
|
/// Renders cards by reading `GameStateResource` on `StateChangedEvent`.
|
||||||
pub struct CardPlugin;
|
pub struct CardPlugin;
|
||||||
|
|
||||||
|
/// System set for everything that paints the board: card sprites, pile
|
||||||
|
/// markers, shadows, highlights, badges. Members mutate `Sprite` /
|
||||||
|
/// `Transform` on board entities and run as a deterministic chain (see the
|
||||||
|
/// registration in [`CardPlugin`]'s `build`); table-plugin marker painters
|
||||||
|
/// order themselves after this set. UI-domain systems that touch `Sprite`/
|
||||||
|
/// `Transform` on non-board entities (HUD text pulses, modal cards) declare
|
||||||
|
/// `.ambiguous_with(BoardVisuals)` instead — the entity domains are
|
||||||
|
/// disjoint by design (#143).
|
||||||
|
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct BoardVisuals;
|
||||||
|
|
||||||
impl Plugin for CardPlugin {
|
impl Plugin for CardPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
// PostStartup ensures TablePlugin's Startup system has inserted
|
// PostStartup ensures TablePlugin's Startup system has inserted
|
||||||
@@ -558,35 +569,45 @@ impl Plugin for CardPlugin {
|
|||||||
update_stock_empty_indicator_startup,
|
update_stock_empty_indicator_startup,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
// Layout recompute (UpdateOnResize) always precedes board
|
||||||
|
// painting, and the painters run as ONE deterministic chain in
|
||||||
|
// data-flow order: layout refinement → card authority → anims →
|
||||||
|
// shadows → highlights → indicators → resize snapping → labels.
|
||||||
|
// Every painter mutates card/marker Sprite+Transform, so without
|
||||||
|
// the chain each pair is a scheduler ambiguity (#143). All
|
||||||
|
// members are cheap and mostly change-gated; sequential
|
||||||
|
// execution is not a cost that matters here.
|
||||||
|
.configure_sets(
|
||||||
|
Update,
|
||||||
|
LayoutSystem::UpdateOnResize.before(BoardVisuals),
|
||||||
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
update_tableau_fan_frac
|
update_tableau_fan_frac,
|
||||||
.after(GameMutation)
|
resync_cards_on_settings_change,
|
||||||
.before(sync_cards_on_change),
|
sync_cards_on_change,
|
||||||
sync_cards_on_change.after(GameMutation),
|
start_flip_anim,
|
||||||
resync_cards_on_settings_change.before(sync_cards_on_change),
|
|
||||||
start_flip_anim.after(GameMutation),
|
|
||||||
tick_flip_anim,
|
tick_flip_anim,
|
||||||
update_drag_shadow,
|
update_drag_shadow,
|
||||||
update_card_shadows_on_drag.after(sync_cards_on_change),
|
update_card_shadows_on_drag,
|
||||||
tick_hint_highlight.after(GameMutation),
|
handle_right_click,
|
||||||
handle_right_click.after(GameMutation),
|
|
||||||
tick_right_click_highlights,
|
tick_right_click_highlights,
|
||||||
clear_right_click_highlights_on_state_change.after(GameMutation),
|
clear_right_click_highlights_on_state_change,
|
||||||
clear_right_click_highlights_on_pause,
|
clear_right_click_highlights_on_pause,
|
||||||
update_stock_empty_indicator.after(GameMutation),
|
tick_hint_highlight,
|
||||||
|
update_stock_empty_indicator,
|
||||||
update_stock_count_badge
|
update_stock_count_badge
|
||||||
.after(GameMutation)
|
|
||||||
.run_if(resource_changed::<GameStateResource>),
|
.run_if(resource_changed::<GameStateResource>),
|
||||||
collect_resize_events.after(LayoutSystem::UpdateOnResize),
|
collect_resize_events,
|
||||||
snap_cards_on_window_resize
|
snap_cards_on_window_resize,
|
||||||
.after(collect_resize_events)
|
resize_android_corner_labels,
|
||||||
|
)
|
||||||
|
.chain()
|
||||||
|
.in_set(BoardVisuals)
|
||||||
.after(GameMutation),
|
.after(GameMutation),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
app.add_systems(Update, resize_android_corner_labels);
|
|
||||||
app.add_systems(PostUpdate, rebuild_card_entity_index);
|
app.add_systems(PostUpdate, rebuild_card_entity_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ use crate::time_attack_plugin::TimeAttackResource;
|
|||||||
use crate::ui_focus::{FocusGroup, Focusable};
|
use crate::ui_focus::{FocusGroup, Focusable};
|
||||||
use crate::ui_modal::ModalScrim;
|
use crate::ui_modal::ModalScrim;
|
||||||
use crate::ui_theme::SPACE_2;
|
use crate::ui_theme::SPACE_2;
|
||||||
|
use crate::ui_theme::UiTextFx;
|
||||||
use crate::ui_theme::{
|
use crate::ui_theme::{
|
||||||
ACCENT_PRIMARY, ACCENT_SECONDARY, BG_ELEVATED, BG_ELEVATED_HI, BG_ELEVATED_PRESSED,
|
ACCENT_PRIMARY, ACCENT_SECONDARY, BG_ELEVATED, BG_ELEVATED_HI, BG_ELEVATED_PRESSED,
|
||||||
BG_HUD_BAND, BORDER_SUBTLE, HighContrastBorder, MOTION_SCORE_PULSE_SECS,
|
BG_HUD_BAND, BORDER_SUBTLE, HighContrastBorder, MOTION_SCORE_PULSE_SECS,
|
||||||
@@ -500,13 +501,19 @@ impl Plugin for HudPlugin {
|
|||||||
advance_score_floater,
|
advance_score_floater,
|
||||||
)
|
)
|
||||||
.chain()
|
.chain()
|
||||||
.after(GameMutation),
|
.after(GameMutation)
|
||||||
|
.in_set(UiTextFx)
|
||||||
|
.ambiguous_with(UiTextFx)
|
||||||
|
.ambiguous_with(crate::card_plugin::BoardVisuals),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(start_streak_flourish, advance_streak_flourish)
|
(start_streak_flourish, advance_streak_flourish)
|
||||||
.chain()
|
.chain()
|
||||||
.after(GameMutation),
|
.after(GameMutation)
|
||||||
|
.in_set(UiTextFx)
|
||||||
|
.ambiguous_with(UiTextFx)
|
||||||
|
.ambiguous_with(crate::card_plugin::BoardVisuals),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
|
|||||||
@@ -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 = 171;
|
const AMBIGUITY_BASELINE: usize = 47;
|
||||||
|
|
||||||
fn cluster_app() -> App {
|
fn cluster_app() -> App {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
|
|||||||
@@ -101,10 +101,17 @@ impl Plugin for TablePlugin {
|
|||||||
(
|
(
|
||||||
on_safe_area_changed.before(LayoutSystem::UpdateOnResize),
|
on_safe_area_changed.before(LayoutSystem::UpdateOnResize),
|
||||||
on_window_resized.in_set(LayoutSystem::UpdateOnResize),
|
on_window_resized.in_set(LayoutSystem::UpdateOnResize),
|
||||||
|
// Marker painters: deterministic chain after the card
|
||||||
|
// paint pipeline — markers and cards share Sprite/
|
||||||
|
// Transform access (#143).
|
||||||
|
(
|
||||||
apply_theme_on_settings_change,
|
apply_theme_on_settings_change,
|
||||||
apply_hint_pile_highlight,
|
apply_hint_pile_highlight,
|
||||||
tick_hint_pile_highlights,
|
tick_hint_pile_highlights,
|
||||||
sync_pile_marker_visibility.after(GameMutation),
|
sync_pile_marker_visibility.after(GameMutation),
|
||||||
|
)
|
||||||
|
.chain()
|
||||||
|
.after(crate::card_plugin::BoardVisuals),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,7 +149,11 @@ 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.after(crate::settings_plugin::SettingsMutation),
|
pulse_focus_overlay
|
||||||
|
.after(crate::settings_plugin::SettingsMutation)
|
||||||
|
.in_set(crate::ui_theme::UiTextFx)
|
||||||
|
.ambiguous_with(crate::ui_theme::UiTextFx)
|
||||||
|
.ambiguous_with(crate::card_plugin::BoardVisuals),
|
||||||
)
|
)
|
||||||
.chain(),
|
.chain(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -696,7 +696,10 @@ impl Plugin for UiModalPlugin {
|
|||||||
paint_modal_buttons,
|
paint_modal_buttons,
|
||||||
)
|
)
|
||||||
.chain()
|
.chain()
|
||||||
.after(crate::settings_plugin::SettingsMutation),
|
.after(crate::settings_plugin::SettingsMutation)
|
||||||
|
.in_set(crate::ui_theme::UiTextFx)
|
||||||
|
.ambiguous_with(crate::ui_theme::UiTextFx)
|
||||||
|
.ambiguous_with(crate::card_plugin::BoardVisuals),
|
||||||
);
|
);
|
||||||
// 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
|
||||||
|
|||||||
@@ -698,3 +698,12 @@ mod tests {
|
|||||||
assert_eq!(scaled_duration(0.18, AnimSpeed::Instant), 0.0);
|
assert_eq!(scaled_duration(0.18, AnimSpeed::Instant), 0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// System set for text/UI visual effects that animate `Transform`/`Sprite`
|
||||||
|
/// on chrome entities (HUD score pulse, streak flourish, modal enter, focus
|
||||||
|
/// ring). These never touch board entities, so members are declared
|
||||||
|
/// `.ambiguous_with(BoardVisuals)` and `.ambiguous_with(UiTextFx)` — the
|
||||||
|
/// entity domains are disjoint by construction and relative order within a
|
||||||
|
/// frame is invisible (#143).
|
||||||
|
#[derive(bevy::ecs::schedule::SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct UiTextFx;
|
||||||
|
|||||||
Reference in New Issue
Block a user