rust_mc_status/status/bedrock.rs
1//! [`BedrockServerStatus`] — typed wrapper around a Bedrock Edition ping result.
2//!
3//! Returned by [`McClient::bedrock`](crate::McClient::bedrock) and
4//! [`ping_bedrock`](crate::ping_bedrock). Wraps a [`ServerStatus`] and exposes
5//! Bedrock-specific accessors so callers don't need to match on [`ServerData`].
6
7use std::fmt;
8
9use serde::Serialize;
10
11use crate::models::{ServerStatus, ServerData};
12use crate::core::fmt::strip_formatting;
13use super::ext::StatusExt;
14
15/// Typed wrapper around a Bedrock Edition [`ServerStatus`].
16///
17/// Implements [`StatusExt`] for common fields and [`serde::Serialize`] via
18/// `#[serde(transparent)]` — serialises identically to the inner
19/// [`ServerStatus`].
20///
21/// # Example
22///
23/// ```rust,no_run
24/// use rust_mc_status::{McClient, StatusExt};
25///
26/// # #[tokio::main] async fn main() -> Result<(), rust_mc_status::McError> {
27/// let client = McClient::builder().build();
28/// let s = client.bedrock("geo.hivebedrock.network").await?;
29///
30/// println!("Edition : {}", s.edition());
31/// println!("Version : {}", s.version());
32/// println!("Players : {}", s.display_players());
33/// println!("MOTD : {}", s.motd_clean());
34/// println!("MOTD2 : {}", s.motd2_clean());
35/// println!("GameMode : {}", s.game_mode());
36/// println!("Cached : {}", s.is_cached());
37/// # Ok(()) }
38/// ```
39#[derive(Serialize)]
40#[serde(transparent)]
41pub struct BedrockServerStatus(pub(crate) ServerStatus);
42
43impl BedrockServerStatus {
44 /// Primary MOTD / server name as returned by the server.
45 ///
46 /// May contain `§`-color codes. Use [`motd_clean`](Self::motd_clean) to
47 /// strip them.
48 pub fn motd(&self) -> &str {
49 match &self.0.data {
50 ServerData::Bedrock(b) => &b.motd,
51 _ => "",
52 }
53 }
54
55 /// Primary MOTD with all Minecraft `§`-formatting codes removed and
56 /// whitespace normalised.
57 pub fn motd_clean(&self) -> String {
58 strip_formatting(self.motd())
59 }
60
61 /// Secondary MOTD / subtitle shown below the server name (raw).
62 ///
63 /// May contain `§`-color codes. Use [`motd2_clean`](Self::motd2_clean) to
64 /// strip them. Empty string when not provided.
65 pub fn motd2(&self) -> &str {
66 match &self.0.data {
67 ServerData::Bedrock(b) => &b.motd2,
68 _ => "",
69 }
70 }
71
72 /// Secondary MOTD with all Minecraft `§`-formatting codes removed.
73 pub fn motd2_clean(&self) -> String {
74 strip_formatting(self.motd2())
75 }
76
77 /// Edition identifier, typically `"MCPE"` for phone/console Bedrock or
78 /// `"MCEE"` for Education Edition.
79 pub fn edition(&self) -> &str {
80 match &self.0.data {
81 ServerData::Bedrock(b) => &b.edition,
82 _ => "",
83 }
84 }
85
86 /// Human-readable game version string, e.g. `"1.21.50"`.
87 pub fn version(&self) -> &str {
88 match &self.0.data {
89 ServerData::Bedrock(b) => &b.version,
90 _ => "",
91 }
92 }
93
94 /// Number of players currently online.
95 pub fn players_online(&self) -> u32 {
96 match &self.0.data {
97 ServerData::Bedrock(b) => b.online_players,
98 _ => 0,
99 }
100 }
101
102 /// Server player capacity.
103 pub fn players_max(&self) -> u32 {
104 match &self.0.data {
105 ServerData::Bedrock(b) => b.max_players,
106 _ => 0,
107 }
108 }
109
110 /// Current game mode, e.g. `"Survival"` or `"Creative"`.
111 pub fn game_mode(&self) -> &str {
112 match &self.0.data {
113 ServerData::Bedrock(b) => &b.game_mode,
114 _ => "",
115 }
116 }
117
118 /// `true` if this result was served from the response cache.
119 ///
120 /// Cached responses have `latency_ms() == 0.0` and reflect the server
121 /// state at the time of the original ping.
122 #[inline]
123 pub fn is_cached(&self) -> bool {
124 self.0.cached
125 }
126
127 /// Access the underlying [`ServerStatus`] directly.
128 ///
129 /// Use this to access `dns`, `meta`, or to match on
130 /// [`ServerData::Bedrock`](crate::ServerData::Bedrock) for the full
131 /// [`BedrockStatus`](crate::BedrockStatus).
132 pub fn raw(&self) -> &ServerStatus {
133 &self.0
134 }
135}
136
137impl StatusExt for BedrockServerStatus {
138 fn latency_ms(&self) -> f64 { self.0.latency }
139 fn ip(&self) -> &str { &self.0.ip }
140 fn hostname(&self) -> &str { &self.0.hostname }
141 fn port(&self) -> u16 { self.0.port }
142 fn is_online(&self) -> bool { self.0.online }
143 fn display_players(&self) -> String {
144 format!("{}/{}", self.players_online(), self.players_max())
145 }
146}
147
148impl fmt::Display for BedrockServerStatus {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 write!(
151 f, "{} [{}] [{} ms] {}/{} — {}",
152 self.hostname(),
153 self.edition(),
154 self.latency_ms() as u32,
155 self.players_online(),
156 self.players_max(),
157 self.motd_clean(),
158 )
159 }
160}
161
162impl fmt::Debug for BedrockServerStatus {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 f.debug_struct("BedrockServerStatus")
165 .field("hostname", &self.hostname())
166 .field("ip", &self.ip())
167 .field("port", &self.port())
168 .field("latency_ms", &self.latency_ms())
169 .field("cached", &self.is_cached())
170 .field("edition", &self.edition())
171 .field("version", &self.version())
172 .field("players", &self.display_players())
173 .field("game_mode", &self.game_mode())
174 .field("motd", &self.motd_clean())
175 .finish()
176 }
177}