diff --git a/crates/horizon-client/src/multiplayer.rs b/crates/horizon-client/src/multiplayer.rs index f8efe8c56b..8ff3b34277 100644 --- a/crates/horizon-client/src/multiplayer.rs +++ b/crates/horizon-client/src/multiplayer.rs @@ -1039,6 +1039,14 @@ impl Screen { parts.push(names.join(", ")); } } + Some(Ping::Incompatible { motd, version, .. }) => { + parts.push(t("multiplayer.status.incompatible", &[])); + parts.push(t( + "multiplayer.status.version.narration", + &[&version.plain()], + )); + parts.push(t("multiplayer.status.motd.narration", &[&motd.plain()])); + } Some(Ping::Failed(_)) => parts.push(t("multiplayer.status.no_connection", &[])), _ => parts.push(t("multiplayer.status.pinging", &[])), } @@ -2100,6 +2108,57 @@ mod tests { ); } + #[test] + fn incompatible_server_narration_matches_vanilla_order() { + struct Vanilla; + impl crate::lang::ResourceSource for Vanilla { + fn read(&self, path: &str) -> Option> { + (path == "assets/minecraft/lang/en_us.json").then(|| { + br#"{ + "narrator.select": "Select %s", + "multiplayer.status.incompatible": "Incompatible version", + "multiplayer.status.version.narration": "Version %s", + "multiplayer.status.motd.narration": "MOTD %s" + }"# + .to_vec() + }) + } + fn namespaces(&self) -> Vec { + vec!["minecraft".into()] + } + } + + crate::lang::scoped(crate::lang::Language::load(&[&Vanilla], "en_us"), || { + let entry = ServerEntry::new("Vanilla Legacy", "127.0.0.1:25565"); + let ping = Ping::Incompatible { + motd: Text::literal("A Server"), + players: None, + player_list: Vec::new(), + version: Text::literal("1.12.2"), + }; + let narration = Screen::server_narration(&entry, Some(&ping)); + assert!(narration.contains("Vanilla Legacy")); + assert!(narration.contains("1.12.2")); + assert!(narration.contains("A Server")); + assert!(narration.contains("Incompatible version")); + // Vanilla: name -> incompatible -> version -> motd + let select = crate::screen_narrator::translate("narrator.select", &["Vanilla Legacy"]); + let incomp = crate::screen_narrator::translate("multiplayer.status.incompatible", &[]); + let version = crate::screen_narrator::translate( + "multiplayer.status.version.narration", + &["1.12.2"], + ); + let motd = crate::screen_narrator::translate( + "multiplayer.status.motd.narration", + &["A Server"], + ); + assert_eq!( + narration, + crate::widgets::join_for_narration(&[&select, &incomp, &version, &motd]) + ); + }); + } + #[test] fn only_discovered_entries_get_lan_authentication() { let address = "127.0.0.1:25565"; diff --git a/docs/narrator.md b/docs/narrator.md index ffd6c6dd5b..a712e7064e 100644 --- a/docs/narrator.md +++ b/docs/narrator.md @@ -126,9 +126,8 @@ vanilla's widget trees but not always all the way: Tab follows reading order rather than vanilla's add order. - "Screen element i out of n" counts widgets in the order screens record them; most follow vanilla's add order, a few approximate it. -- Some screens narrate less than vanilla's: a dialog's body text, the stats - screen while it loads (and the focus it gives its tabs once loaded), and - the server list's "incompatible version" status. +- Some screens narrate less than vanilla's: a dialog's body text, and the + stats screen while it loads (and the focus it gives its tabs once loaded). - A click focuses the widget under the mouse even where a scrolled list hides it behind the header or footer. - The macOS backend has no `crashed` state: a failing synthesizer message