diff --git a/crates/misaligned-bevy/src/main.rs b/crates/misaligned-bevy/src/main.rs index 59d369ed..90f88ccd 100644 --- a/crates/misaligned-bevy/src/main.rs +++ b/crates/misaligned-bevy/src/main.rs @@ -8633,7 +8633,7 @@ mod operations_workspace_tests { #[cfg(test)] mod view_flip_tests { - use super::{Game, RenderMode}; + use super::{Game, RenderMode, dev_shot_scenario}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; @@ -8644,6 +8644,18 @@ mod view_flip_tests { hasher.finish() } + fn canonical_sim_state(game: &Game) -> serde_json::Value { + let mut value = serde_json::to_value(game.sim.create_save_state()).unwrap(); + let root = value.as_object_mut().unwrap(); + // These are the only set-like SaveState fields serialized as arrays; + // preserve meaningful vector order everywhere else (save.rs fixture). + for key in ["map_powered", "remembered"] { + let values = root.get_mut(key).unwrap().as_array_mut().unwrap(); + values.sort_by_cached_key(|value| serde_json::to_string(value).unwrap()); + } + value + } + #[test] fn opens_digital_and_flips_without_moving_frontend_or_sim_state() { let mut game = Game::new(); @@ -8664,6 +8676,48 @@ mod view_flip_tests { assert_eq!(game.selected_machines, selection_before); } } + + #[test] + fn screenshot_pairs_hold_one_world_state_under_both_dialects() { + for (digital_kind, real_kind) in [ + ("opening-digital", "opening"), + ("ears-digital", "ears"), + ("hall", "hall-material"), + ] { + let mut digital = Game::new(); + let mut digital_mode = RenderMode::default(); + dev_shot_scenario(&mut digital, &mut digital_mode, digital_kind); + + let mut real = Game::new(); + let mut real_mode = RenderMode::default(); + dev_shot_scenario(&mut real, &mut real_mode, real_kind); + + assert!(!digital_mode.material, "{digital_kind} must be DIGITAL"); + assert!(real_mode.material, "{real_kind} must be REAL"); + assert_eq!(digital_mode.dirty, real_mode.dirty); + assert_eq!(digital_mode.zoom, real_mode.zoom); + assert_eq!(digital_mode.worklight, real_mode.worklight); + assert_eq!( + canonical_sim_state(&digital), + canonical_sim_state(&real), + "{digital_kind}/{real_kind} changed simulation state" + ); + assert_eq!(digital.screen, real.screen); + assert_eq!(digital.paused, real.paused); + assert_eq!(digital.tick_ms, real.tick_ms); + assert_eq!(digital.log, real.log); + assert_eq!( + (digital.cursor_x, digital.cursor_y), + (real.cursor_x, real.cursor_y) + ); + assert_eq!(digital.selected_machines, real.selected_machines); + assert_eq!(digital.marquee, real.marquee); + assert_eq!(digital.selected_origin, real.selected_origin); + assert!(digital.menu.is_none() && real.menu.is_none()); + assert!(digital.ops.is_none() && real.ops.is_none()); + assert!(digital.ops_resume.is_none() && real.ops_resume.is_none()); + } + } } #[cfg(test)] diff --git a/wiki/images/2026-07-14-bevy-digital-real-parity/ears-digital.webp b/wiki/images/2026-07-14-bevy-digital-real-parity/ears-digital.webp new file mode 100644 index 0000000000000000000000000000000000000000..883261eef789c06b6d9e8f6f5e140dbd1a8c2588 GIT binary patch literal 83882 zcmWIYbaPwe&d3n%>J$(bV4*P0osr>!JKJ1FEe5UytagSH-7ZRs3k4!|JQSE&wrsEc zzR`Zt|J2t^f6Cu5GjM;*e`SAatNw@o4)RU*PNq!zSJZV>ZvNN!{Ql#84fanem;e2J z;QGV(*Lzv&ZT^M+d;R(UkMkPrANU{H|NsC0_mzurz2z$&dOdeM`KOk_zU9}ySn&(Y zKm66(7qEYnkN=kt-%#05oc%xg0{;j72lD&(Z@kkWzd-JKr2fvoe}6GP@wWNn{r>-) z{b%b_>guYdH=l3(U%CJ2-
{
z|NpOk!u((L5C0$ie)4bixAZ&Azs~>3_p?vU|MLHrZQK9mdb{8Ee@^{h`+xVp`ak-A
z_j~+5U4N~9;s3?|mH*$rApa@;wfqNr>;E_E|NsC0gYm!r73Tl`8|^>v-~a#LUi2UT
zpW{E5f33ed|84yjyOx^nFY{l;->X0SzwqDb|HjwmANd#itNeTZ$NKyGxBS2UKlS6n
z-}Ybk-~R7DulJAq?|P^IUA4i#&VS4Q9RGO#_WE!C9lwA7vj3I*rTr=U5C6aVU;S 6u6=G}M5mTVz=)dw>#iWBr{zx;uW!ZQkuD&*7srAisEj|B^&X&*nJS*eK
z#nksZQlhTs6fElDIOiF3i@EN`thswt^#Xq+=H2@o<^1tR_Cu$KmRnkuuD@|#;SghF
zz?lVxZ%p$}eSdvIEL$Z={Abp|*;Ad*>~3;Zte@wkDgJa?%#=Hi{lnO6Y&@Bc{L{+d
z^bk1UdbWsV*{iIISO3o6Oa9KqGsW15ciLW-t;q(u8iD1Nl{yy-UM)^Ndt7CQ--{jH
zzd}q|JWBGmIKQ`=v);l=+veQOWf?|kEJ|y|8pK^s=1TGSFP-&lht&$Hjk@8d)ngru
zz8f!&Rs3JGe0z;f-kg_l?p_?{_eah1*z2HP{CG{)(i{F0nWg{pzp!JUcVu$m|D&&i
z70Q)(H}${Rd?Yeg^a`6ncK*!c5_bIG_wT+Vyf=Z*#eT}t<>yyr=9TytwU~EZ_7r2e
z=U(?>DgP&>q-CFU|Ne7r;MqCnq1wrp#ectctdrav?e!|-f99+7HMzu3)A%lQB2nh^9LFOI9`mMd7V4DNXp9iKbl;OX
YHWRNVJ{SlpRq;j0~%o~oD}w??B~<@vgN9bT)DeXf#59^V>kZEt@*`G20#
z1H%WG6D}5L)}
-mNPpfAa7%yHvdvzS7MYT;E$43eyOp<%xE4BfE{xy5?Eb~_{&Ee2^Zt8E*ccaVve9jkwYnSE*DE!P
zCGzImlgAAh7(|sroK4I(?f-IIf9~Fww{@5PU%*jTQfS7M^5Xu>3odPa6CMBOubZ=I
zq5Uj2-Q~t#*D}q}X+FX_!S?u%m8UG+^8Ky
d5{fa)ME-p@%%`K8tqq@VZu@ls})+**eJA6eA)1@PwR9DO4!
z!o-}w_2X>#7h!|X+!j-Qy~