Skip to main content

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}