rust-mc-status 3.0.0

High-performance asynchronous Rust library for querying Minecraft server status (Java & Bedrock)
Documentation
//! [`BedrockServerStatus`] — typed wrapper around a Bedrock Edition ping result.
//!
//! Returned by [`McClient::bedrock`](crate::McClient::bedrock) and
//! [`ping_bedrock`](crate::ping_bedrock). Wraps a [`ServerStatus`] and exposes
//! Bedrock-specific accessors so callers don't need to match on [`ServerData`].

use std::fmt;

use serde::Serialize;

use crate::models::{ServerStatus, ServerData};
use crate::core::fmt::strip_formatting;
use super::ext::StatusExt;

/// Typed wrapper around a Bedrock Edition [`ServerStatus`].
///
/// Implements [`StatusExt`] for common fields and [`serde::Serialize`] via
/// `#[serde(transparent)]` — serialises identically to the inner
/// [`ServerStatus`].
///
/// # Example
///
/// ```rust,no_run
/// use rust_mc_status::{McClient, StatusExt};
///
/// # #[tokio::main] async fn main() -> Result<(), rust_mc_status::McError> {
/// let client = McClient::builder().build();
/// let s = client.bedrock("geo.hivebedrock.network").await?;
///
/// println!("Edition  : {}", s.edition());
/// println!("Version  : {}", s.version());
/// println!("Players  : {}", s.display_players());
/// println!("MOTD     : {}", s.motd_clean());
/// println!("MOTD2    : {}", s.motd2_clean());
/// println!("GameMode : {}", s.game_mode());
/// println!("Cached   : {}", s.is_cached());
/// # Ok(()) }
/// ```
#[derive(Serialize)]
#[serde(transparent)]
pub struct BedrockServerStatus(pub(crate) ServerStatus);

impl BedrockServerStatus {
    /// Primary MOTD / server name as returned by the server.
    ///
    /// May contain `§`-color codes. Use [`motd_clean`](Self::motd_clean) to
    /// strip them.
    pub fn motd(&self) -> &str {
        match &self.0.data {
            ServerData::Bedrock(b) => &b.motd,
            _ => "",
        }
    }

    /// Primary MOTD with all Minecraft `§`-formatting codes removed and
    /// whitespace normalised.
    pub fn motd_clean(&self) -> String {
        strip_formatting(self.motd())
    }

    /// Secondary MOTD / subtitle shown below the server name (raw).
    ///
    /// May contain `§`-color codes. Use [`motd2_clean`](Self::motd2_clean) to
    /// strip them. Empty string when not provided.
    pub fn motd2(&self) -> &str {
        match &self.0.data {
            ServerData::Bedrock(b) => &b.motd2,
            _ => "",
        }
    }

    /// Secondary MOTD with all Minecraft `§`-formatting codes removed.
    pub fn motd2_clean(&self) -> String {
        strip_formatting(self.motd2())
    }

    /// Edition identifier, typically `"MCPE"` for phone/console Bedrock or
    /// `"MCEE"` for Education Edition.
    pub fn edition(&self) -> &str {
        match &self.0.data {
            ServerData::Bedrock(b) => &b.edition,
            _ => "",
        }
    }

    /// Human-readable game version string, e.g. `"1.21.50"`.
    pub fn version(&self) -> &str {
        match &self.0.data {
            ServerData::Bedrock(b) => &b.version,
            _ => "",
        }
    }

    /// Number of players currently online.
    pub fn players_online(&self) -> u32 {
        match &self.0.data {
            ServerData::Bedrock(b) => b.online_players,
            _ => 0,
        }
    }

    /// Server player capacity.
    pub fn players_max(&self) -> u32 {
        match &self.0.data {
            ServerData::Bedrock(b) => b.max_players,
            _ => 0,
        }
    }

    /// Current game mode, e.g. `"Survival"` or `"Creative"`.
    pub fn game_mode(&self) -> &str {
        match &self.0.data {
            ServerData::Bedrock(b) => &b.game_mode,
            _ => "",
        }
    }

    /// `true` if this result was served from the response cache.
    ///
    /// Cached responses have `latency_ms() == 0.0` and reflect the server
    /// state at the time of the original ping.
    #[inline]
    pub fn is_cached(&self) -> bool {
        self.0.cached
    }

    /// Access the underlying [`ServerStatus`] directly.
    ///
    /// Use this to access `dns`, `meta`, or to match on
    /// [`ServerData::Bedrock`](crate::ServerData::Bedrock) for the full
    /// [`BedrockStatus`](crate::BedrockStatus).
    pub fn raw(&self) -> &ServerStatus {
        &self.0
    }
}

impl StatusExt for BedrockServerStatus {
    fn latency_ms(&self) -> f64  { self.0.latency }
    fn ip(&self) -> &str         { &self.0.ip }
    fn hostname(&self) -> &str   { &self.0.hostname }
    fn port(&self) -> u16        { self.0.port }
    fn is_online(&self) -> bool  { self.0.online }
    fn display_players(&self) -> String {
        format!("{}/{}", self.players_online(), self.players_max())
    }
}

impl fmt::Display for BedrockServerStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f, "{} [{}] [{} ms] {}/{}{}",
            self.hostname(),
            self.edition(),
            self.latency_ms() as u32,
            self.players_online(),
            self.players_max(),
            self.motd_clean(),
        )
    }
}

impl fmt::Debug for BedrockServerStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BedrockServerStatus")
            .field("hostname",   &self.hostname())
            .field("ip",         &self.ip())
            .field("port",       &self.port())
            .field("latency_ms", &self.latency_ms())
            .field("cached",     &self.is_cached())
            .field("edition",    &self.edition())
            .field("version",    &self.version())
            .field("players",    &self.display_players())
            .field("game_mode",  &self.game_mode())
            .field("motd",       &self.motd_clean())
            .finish()
    }
}