diff --git a/Cargo.toml b/Cargo.toml index 60ba981..88a247c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,10 @@ name = "gamedig" version = "0.2.1" edition = "2021" -authors = ["CosminPerRam [https://github.com/CosminPerRam]", "node-GameDig contributors [https://github.com/gamedig/node-gamedig/contributors]"] +authors = [ + "CosminPerRam [https://github.com/CosminPerRam]", + "node-GameDig contributors [https://github.com/gamedig/node-gamedig/contributors]", +] license = "MIT" description = "Check out servers with this." homepage = "https://github.com/gamedig/rust-gamedig" @@ -13,12 +16,14 @@ keywords = ["server", "query", "game", "check", "status"] rust-version = "1.56.1" [features] +default = [] no_games = [] +serde = ["dep:serde", "serde/derive"] [dependencies] byteorder = "1.4.3" - -bzip2-rs = "0.1.2" # for compression +bzip2-rs = "0.1.2" crc32fast = "1.3.2" +serde_json = "1.0.91" -serde_json = "1.0.91" # json to structs +serde = { version = "1.0.155", optional = true } diff --git a/src/games/ts.rs b/src/games/ts.rs index 3d72811..3a6daa7 100644 --- a/src/games/ts.rs +++ b/src/games/ts.rs @@ -3,7 +3,11 @@ use crate::GDResult; use crate::protocols::valve; use crate::protocols::valve::{Server, ServerPlayer, get_optional_extracted_data, SteamApp}; -#[derive(Debug)] +#[cfg (feature = "serde")] +use serde::{Serialize, Deserialize}; + +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct TheShipPlayer { pub name: String, pub score: u32, @@ -24,7 +28,8 @@ impl TheShipPlayer { } } -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq)] pub struct Response { pub protocol: u8, pub name: String, diff --git a/src/protocols/gamespy/types.rs b/src/protocols/gamespy/types.rs index db4ed3e..8fcefeb 100644 --- a/src/protocols/gamespy/types.rs +++ b/src/protocols/gamespy/types.rs @@ -1,7 +1,11 @@ use std::collections::HashMap; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + /// A player’s details. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Player { pub name: String, pub team: u8, @@ -13,11 +17,12 @@ pub struct Player { pub frags: u32, pub deaths: Option, pub health: Option, - pub secret: bool + pub secret: bool, } /// A query response. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Response { pub name: String, pub map: String, @@ -32,5 +37,5 @@ pub struct Response { pub players_minimum: u8, pub players: Vec, pub tournament: bool, - pub unused_entries: HashMap + pub unused_entries: HashMap, } diff --git a/src/protocols/minecraft/types.rs b/src/protocols/minecraft/types.rs index a51f6d7..d596339 100644 --- a/src/protocols/minecraft/types.rs +++ b/src/protocols/minecraft/types.rs @@ -1,45 +1,51 @@ - /* Although its a lightly modified version, this file contains code by Jaiden Bernard (2021-2022 - MIT) from https://github.com/thisjaiden/golden_apple/blob/master/src/lib.rs */ -use crate::GDResult; use crate::bufferer::Bufferer; use crate::GDError::{PacketBad, UnknownEnumCast}; +use crate::GDResult; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; /// The type of Minecraft Server you want to query. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum Server { /// Java Edition. Java, /// Legacy Java. Legacy(LegacyGroup), /// Bedrock Edition. - Bedrock + Bedrock, } /// Legacy Java (Versions) Groups. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum LegacyGroup { /// 1.6 V1_6, /// 1.4 - 1.5 V1_4, /// Beta 1.8 - 1.3 - VB1_8 + VB1_8, } /// Information about a player. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Player { pub name: String, - pub id: String + pub id: String, } /// A Java query response. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct JavaResponse { /// Version name, example: "1.19.2". pub version_name: String, @@ -60,11 +66,12 @@ pub struct JavaResponse { /// Tells if secure chat is enforced (can be missing). pub enforces_secure_chat: Option, /// Tell's the server type. - pub server_type: Server + pub server_type: Server, } /// A Bedrock Edition query response. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct BedrockResponse { /// Server's edition. pub edition: String, @@ -85,7 +92,7 @@ pub struct BedrockResponse { /// Current game mode. pub game_mode: Option, /// Tells the server type. - pub server_type: Server + pub server_type: Server, } impl JavaResponse { @@ -100,15 +107,20 @@ impl JavaResponse { favicon: None, previews_chat: None, enforces_secure_chat: None, - server_type: Server::Bedrock + server_type: Server::Bedrock, } } } -/// A server's game mode (used only by Bedrock servers). -#[derive(Debug)] +/// A server's game mode (used only by Bedrock servers. +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum GameMode { - Survival, Creative, Hardcore, Spectator, Adventure + Survival, + Creative, + Hardcore, + Spectator, + Adventure, } impl GameMode { @@ -119,7 +131,7 @@ impl GameMode { "Hardcore" => Ok(GameMode::Hardcore), "Spectator" => Ok(GameMode::Spectator), "Adventure" => Ok(GameMode::Adventure), - _ => Err(UnknownEnumCast) + _ => Err(UnknownEnumCast), } } } @@ -137,7 +149,7 @@ pub(crate) fn get_varint(buffer: &mut Bufferer) -> GDResult { // The 5th byte is only allowed to have the 4 smallest bits set if i == 4 && (current_byte & 0xf0 != 0) { - return Err(PacketBad) + return Err(PacketBad); } if (current_byte & msb) == 0 { diff --git a/src/protocols/valve/types.rs b/src/protocols/valve/types.rs index 4601251..681de23 100644 --- a/src/protocols/valve/types.rs +++ b/src/protocols/valve/types.rs @@ -1,31 +1,38 @@ use std::collections::HashMap; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + /// The type of the server. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum Server { Dedicated, NonDedicated, - TV + TV, } /// The Operating System that the server is on. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum Environment { Linux, Windows, - Mac + Mac, } /// A query response. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq)] pub struct Response { pub info: ServerInfo, pub players: Option>, - pub rules: Option> + pub rules: Option>, } /// General server information's. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct ServerInfo { /// Protocol used by the server. pub protocol: u8, @@ -62,11 +69,12 @@ pub struct ServerInfo { /// GoldSrc only: Indicates whether the hosted game is a mod. pub is_mod: bool, /// GoldSrc only: If the game is a mod, provide additional data. - pub mod_data: Option + pub mod_data: Option, } /// A server player. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct ServerPlayer { /// Player's name. pub name: String, @@ -81,15 +89,17 @@ pub struct ServerPlayer { } /// Only present for [the ship](https://developer.valvesoftware.com/wiki/The_Ship). -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct TheShip { pub mode: u8, pub witnesses: u8, - pub duration: u8 + pub duration: u8, } /// Some extra data that the server might provide or not. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct ExtraData { /// The server's game port number. pub port: Option, @@ -102,18 +112,19 @@ pub struct ExtraData { /// Keywords that describe the server according to it. pub keywords: Option, /// The server's 64-bit GameID. - pub game_id: Option + pub game_id: Option, } /// Data related to GoldSrc Mod response. -#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct ModData { pub link: String, pub download_link: String, pub version: u32, pub size: u32, pub multiplayer_only: bool, - pub has_own_dll: bool + pub has_own_dll: bool, } pub(crate) type ExtractedData = ( @@ -142,11 +153,12 @@ pub(crate) enum Request { /// Known as `A2S_PLAYERS` Players = 0x55, /// Known as `A2S_RULES` - Rules = 0x56 + Rules = 0x56, } /// Supported steam apps -#[derive(Eq, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum SteamApp { /// Counter-Strike CS, @@ -236,9 +248,9 @@ impl SteamApp { /// Get the specified app as engine. pub fn as_engine(&self) -> Engine { match self { - SteamApp::CS => Engine::GoldSrc(false), //10 - SteamApp::TFC => Engine::GoldSrc(false), //20 - SteamApp::DOD => Engine::GoldSrc(false), //30 + SteamApp::CS => Engine::GoldSrc(false), //10 + SteamApp::TFC => Engine::GoldSrc(false), //20 + SteamApp::DOD => Engine::GoldSrc(false), //30 SteamApp::CSCZ => Engine::GoldSrc(false), //80 SteamApp::CSS => Engine::new_source(240), SteamApp::DODS => Engine::new_source(300), @@ -282,7 +294,8 @@ impl SteamApp { } /// Engine type. -#[derive(Eq, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum Engine { /// A Source game, the argument represents the possible steam app ids, if its **None**, let /// the query find it, if its **Some**, the query fails if the response id is not the first @@ -290,7 +303,7 @@ pub enum Engine { Source(Option<(u32, Option)>), /// A GoldSrc game, the argument indicates whether to enforce /// requesting the obsolete A2S_INFO response or not. - GoldSrc(bool) + GoldSrc(bool), } impl Engine { @@ -306,7 +319,7 @@ impl Engine { /// What data to gather, purely used only with the query function. pub struct GatheringSettings { pub players: bool, - pub rules: bool + pub rules: bool, } impl Default for GatheringSettings { @@ -314,7 +327,7 @@ impl Default for GatheringSettings { fn default() -> Self { Self { players: true, - rules: true + rules: true, } } } @@ -322,19 +335,23 @@ impl Default for GatheringSettings { /// Generic response types that are used by many games, they are the protocol ones, but without the /// unnecessary bits (example: the **The Ship**-only fields). pub mod game { - use std::collections::HashMap; - use crate::protocols::valve::types::get_optional_extracted_data; use super::{Server, ServerPlayer}; + use crate::protocols::valve::types::get_optional_extracted_data; + use std::collections::HashMap; + + #[cfg(feature = "serde")] + use serde::{Deserialize, Serialize}; /// A player's details. - #[derive(Debug)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct Player { /// Player's name. pub name: String, /// Player's score. pub score: u32, /// How long a player has been in the server (seconds). - pub duration: f32 + pub duration: f32, } impl Player { @@ -342,13 +359,14 @@ pub mod game { Self { name: player.name.clone(), score: player.score, - duration: player.duration + duration: player.duration, } } } /// The query response. - #[derive(Debug)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[derive(Debug, Clone, PartialEq)] pub struct Response { /// Protocol used by the server. pub protocol: u8, @@ -387,12 +405,13 @@ pub mod game { /// Keywords that describe the server according to it. pub keywords: Option, /// Server's rules. - pub rules: HashMap + pub rules: HashMap, } impl Response { pub fn new_from_valve_response(response: super::Response) -> Self { - let (port, steam_id, tv_port, tv_name, keywords) = get_optional_extracted_data(response.info.extra_data); + let (port, steam_id, tv_port, tv_name, keywords) = + get_optional_extracted_data(response.info.extra_data); Self { protocol: response.info.protocol, @@ -401,7 +420,12 @@ pub mod game { game: response.info.game, appid: response.info.appid, players_online: response.info.players_online, - players_details: response.players.unwrap_or_default().iter().map(Player::from_valve_response).collect(), + players_details: response + .players + .unwrap_or_default() + .iter() + .map(Player::from_valve_response) + .collect(), players_maximum: response.info.players_maximum, players_bots: response.info.players_bots, server_type: response.info.server_type, @@ -413,7 +437,7 @@ pub mod game { tv_port, tv_name, keywords, - rules: response.rules.unwrap_or_default() + rules: response.rules.unwrap_or_default(), } } }