[Protocol] Standardize fields (#84)

* [Protocol] Standardize The Ship fields

* [Protocol] Standardize FFOW fields

* [Protocol] Rename Valve's protocol field to protocol_version

* [Protocol] Rename Minecraft's version_protocol field to protocol_version

* [Protocol] Rename Valve's version field to game_version

* [Protocol] Rename Minecraft java version_name to game_version

* [Crate] Reformat RESPONSES.md

* [Protocol] Renamed Minecraft Java players_sample to players

* [Protocol] Rename Quake (1,2,3) version field to game_version

* [Protocol] Rename quake (1 and 2) game_type field to game_mode

* [Protocol] Rename Valve, FFOW, TS game field to game_mode

* [Generics] Rename game field/function to game_mode

* [Protocol] Change players_minimum, _maximum and _bots from those who werent u8 or u32 to u32

* [Protocol] Change instances of player score field type from u32 to i32

* [Crate] Nicer gramar in CHANGELOG

* [Protocol] Apply clippy fixes
This commit is contained in:
CosminPerRam 2023-08-15 20:44:18 +03:00 committed by GitHub
parent 65c56dc196
commit 9d8fb1ba94
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 249 additions and 200 deletions

View file

@ -18,6 +18,58 @@ Crate:
- The enum used for errors, `GDError` has been renamed to `GDErrorKind`. - The enum used for errors, `GDError` has been renamed to `GDErrorKind`.
- `GDError` is now a struct that holds its kind, the source and a backtrace. - `GDError` is now a struct that holds its kind, the source and a backtrace.
Generics:
- Renamed `CommonResponseJson`'s `game` field (and the function) to `game_mode`.
- Changed `players_maximum` and `players_online` (and their functions) types from `u64` to `u32`.
- Changed `score` type (and the function) of player from `u32` to `i32`.
Protocol:
- Valve:
1. Renamed `protocol` to `protocol_version`.
2. Renamed `version` to `game_version`.
3. Renamed `game` to `game_mode`.
4. Changed `score` type of player from `u32` to `i32`.
- GameSpy (1, 2, 3):
1. Renamed `version` to `game_version`.
2. Changed `players_maximum` and `players_online` (and their functions) types from `usize` to `u32`.
- GameSpy 1:
1. Changed `score` type of player from `u32` to `i32`.
- Quake (1, 2):
1. Renamed `game_type` to `game_mode`.
- Minecraft Java
1. Renamed `version_protocol` to `protocol_version`.
2. Renamed `version_name` to `game_version`.
3. Renamed `players_sample` to `players`.
- Minecraft Bedrock
1. Renamed `version_protocol` to `protocol_version`.
- The Ship:
1. Renamed `protocol` to `protocol_version`.
2. Renamed `max_players` to `players_maximum` and changed its type from `u64` to `u32`.
3. Renamed `bots` to `players_bots`. and changed its type from `u64` to `u32`.
4. Renamed `players` to `players_online`.
5. Renamed `players_details` to `players`.
6. Renamed `game` to `game_mode`.
7. Added field `game_version`.
8. Changed `players_bots` type from `Option<u64>` to `Option<u32>`.
9. Changed `score` type of player from `u32` to `i32`.
- Frontlines: Fuel of War:
1. Renamed `game_mode` to `game`.
2. Renamed `version` to `game_version`.
3. Renamed `protocol` to `protocol_version`.
4. Renamed `game` to `game_mode`.
5. Changed `players_maximum` and `players_minimum` types from `usize` to `u32`.
- Just Cause 2: Multiplayer:
1. Renamed `version` to `game_version`.
2. Changed `players_maximum` and `players_minimum` types from `usize` to `u32`.
# 0.3.0 - 18/07/2023 # 0.3.0 - 18/07/2023
### Changes: ### Changes:
Protocols: Protocols:

View file

@ -5,50 +5,50 @@ In the case that a field that performs the same function exists in the current c
# Response table # Response table
| Field | Generic | GameSpy(1) | GameSpy(2) | GameSpy(3) | Minecraft(Java) | Minecraft(Bedrock) | Valve | Quake | Proprietary: FFOW | Proprietary: TheShip | | Field | Generic | GameSpy(1) | GameSpy(2) | GameSpy(3) | Minecraft(Java) | Minecraft(Bedrock) | Valve | Quake | Proprietary: FFOW | Proprietary: TheShip | Proprietary: JC2MP |
| :--------------- | ---------------- | ------------ | ------------ | ------------ | ----------------- | -------------------- | -------- | -------- | -------- | --------- | |:---------------------|------------------|---------------------------|---------------|---------------------------|-----------------------|----------------------|----------------------------------|---------------------------|-------------------|--------------------------|--------------------|
| name | `Option<String>` | `String` | `String` | `String` | | `String` | `String` | `String` | `String` | `String` | | name | `Option<String>` | `String` | `String` | `String` | | `String` | `String` | `String` | `String` | `String` | `String` |
| description | `Option<String>` | | | | `String` | | | | `String` | | | description | `Option<String>` | | | | `String` | | | | `String` | | `String` |
| game | `Option<String>` | `String` (game_type) | | `String` (game_type) | | `Option<GameMode>` (game_mode) | `String` | | `String` (game_mode) | `String` | | game_mode | `Option<String>` | `String` | | `String` | | `Option<GameMode>` | `String` | | `String` | `String` | |
| game_version | `Option<String>` | `String` | | `String` | `String` (version_name) | | `String` (version) | `String` (version) | `String` (version) | `String` (version) | | game_version | `Option<String>` | `String` | | `String` | `String` | | `String` | `String` | `String` | `String` | `String` |
| map | `Option<String>` | `String` | `String` | `String` | | `Option<String>` | `String` | `String` | `String` | `String` | | map | `Option<String>` | `String` | `String` | `String` | | `Option<String>` | `String` | `String` | `String` | `String` | |
| players_maxmimum | `u64` | `usize` | `usize` | `usize` | `u32` | `u32` | `u8` | `u8` | `u8` | `u8` (max_players) | | players_maxmimum | `u32` | `u32` | `u32` | `u32` | `u32` | `u32` | `u8` | `u8` | `u8` | `u8` | `u32` |
| players_online | `u64` | `usize` | `usize` | `usize` | `u32` | `u32` | `u8` | `u8` | `u8` | `u8` (players) | | players_online | `u32` | `u32` | `u32` | `u32` | `u32` | `u32` | `u8` | `u8` | `u8` | `u8` | `u32` |
| players_bots | `Option<u64>` | | | | | | `u8` | | | `u8` (bots) | | players_bots | `Option<u32>` | | | | | | `u8` | | | `u8` | |
| has_password | `Option<bool>` | `bool` | `bool` | `bool` | | | `bool` | | `bool` | `bool` | | has_password | `Option<bool>` | `bool` | `bool` | `bool` | | | `bool` | | `bool` | `bool` | `bool` |
| map_title | | `Option<String>` | | | | | | | | | | players_minimum | | `Option<u8>` | `Option<u8>` | `Option<u8>` | | | | | | | |
| admin_contact | | `Option<String>` | | | | | | | | | | players | | `Vec<Player>` | `Vec<Player>` | `Vec<Player>` | `Option<Vec<Player>>` | | `Option<Vec<ServerPlayer>>` | `Vec<P>` | | `Vec<TheShipPlayer>` | `Vec<Player>` |
| admin_name | | `Option<String>` | | | | | | | | | | tournament | | `bool` | | `bool` | | | | | | | |
| players_minimum | | `Option<u8>` | `Option<u8>` | `Option<u8>` | | | | | | | | unused_entries | | `Hashmap<String, String>` | | `HashMap<String, String>` | | | | `HashMap<String, String>` | | | |
| players | | `Vec<Player>` | `Vec<Player>` | `Vec<Player>` | | | `Option<Vec<ServerPlayer>>` | `Vec<P>` | | `Vec<TheShipPlayer>` (player_details) | | teams | | | `Vec<Team>` | `Vec<Team>` | | | | | | | |
| tournament | | `bool` | |`bool` | | | | | | | | protocol_version | | | | | `i32` | `String` | `u8` | | `u8` | `u8` | |
| unused_entries | | `Hashmap<String, String>` | | `HashMap<String, String>` | | | `Option<ExtraData>` (extra_data) | `HashMap<String, String>` | | | | server_type | | | | | `Server` | `Server` | `Server` | | | `Server` | |
| teams | | | `Vec<Team>` | `Vec<Team>` | | | | | | | | rules | | | | | | | `Option<HashMap<String,String>>` | | | `HashMap<String,String>` | |
| version_protocol | | | | | `i32` | `String` | `u8` (protocol) | | `u8` (protocol) | `u8` (protocol) | | environment_type | | | | | | | `Environment` | | `Environment` | | |
| players_sample | | | | | `Option<Vec<Player>>` | | | | | | | vac_secured | | | | | | | `bool` | | `bool` | `bool` | |
| favicon | | | | | `Option<String>` | | | | | | | map_title | | `Option<String>` | | | | | | | | | |
| previews_chat | | | | | `Option<bool>` | | | | | | | admin_contact | | `Option<String>` | | | | | | | | | |
| enforces_secure_chat | | | | | `Option<bool>` | | | | | | | admin_name | | `Option<String>` | | | | | | | | | |
| server_type | | | | | `Server` | `Server` | `Server` | | | `Server` | | favicon | | | | | `Option<String>` | | | | | | |
| edition | | | | | | `String` | | | | | | previews_chat | | | | | `Option<bool>` | | | | | | |
| id | | | | | | `String` | | | | | | enforces_secure_chat | | | | | `Option<bool>` | | | | | | |
| rules | | | | | | | `Option<HashMap<String,String>>` | | | `HashMap<String,String>` | | edition | | | | | | `String` | | | | | |
| folder | | | | | | | `String` | | | | | id | | | | | | `String` | | | | | |
| appid | | | | | | | `u32` | | | | | the_ship | | | | | | | `Option<TheShip>` | | | | |
| environment_type | | | | | | | `Environment` | | `Environment` | | | is_mod | | | | | | | `bool` | | | | |
| vac_secured | | | | | | | `bool` | | `bool` | `bool` | | extra_data | | | | | | | `Option<ExtraData>` | | | | |
| the_ship | | | | | | | `Option<TheShip>` | | | | | mod_data | | | | | | | `Option<ModData>` | | | | |
| is_mod | | | | | | | `bool` | | | | | folder | | | | | | | `String` | | | | |
| mod_data | | | | | | | `Option<ModData>` | | | | | appid | | | | | | | `u32` | | | | |
| active_mod | | | | | | | | | `String` | | | active_mod | | | | | | | | | `String` | | |
| round | | | | | | | | | `u8` | | | round | | | | | | | | | `u8` | | |
| rounds_maximum | | | | | | | | | `u8` | | | rounds_maximum | | | | | | | | | `u8` | | |
| time_left | | | | | | | | | `u16` | | | time_left | | | | | | | | | `u16` | | |
| port | | | | | | | | | | `Option<u16>` | | port | | | | | | | | | | `Option<u16>` | |
| steam_id | | | | | | | | | | `Option<u64>` | | steam_id | | | | | | | | | | `Option<u64>` | |
| tv_port | | | | | | | | | | `Option<u16>` | | tv_port | | | | | | | | | | `Option<u16>` | |
| tv_name | | | | | | | | | | `Option<String>` | | tv_name | | | | | | | | | | `Option<String>` | |
| keywords | | | | | | | | | | `Option<string>` | | keywords | | | | | | | | | | `Option<string>` | |
| mode | | | | | | | | | | `u8` | | mode | | | | | | | | | | `u8` | |
| witnesses | | | | | | | | | | `u8` | | witnesses | | | | | | | | | | `u8` | |
| duration | | | | | | | | | | `u8` | | duration | | | | | | | | | | `u8` | |

View file

@ -35,7 +35,7 @@ pub fn query(address: &IpAddr, port: Option<u16>) -> GDResult<game::Response> {
} }
if let Some(bat_gamemode) = rules.get("bat_gamemode_s") { if let Some(bat_gamemode) = rules.get("bat_gamemode_s") {
valve_response.info.game = bat_gamemode.clone(); valve_response.info.game_mode = bat_gamemode.clone();
rules.remove("bat_gamemode_s"); rules.remove("bat_gamemode_s");
} }

View file

@ -13,17 +13,17 @@ use std::net::{IpAddr, SocketAddr};
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Response { pub struct Response {
/// Protocol used by the server. /// Protocol used by the server.
pub protocol: u8, pub protocol_version: u8,
/// Name of the server. /// Name of the server.
pub name: String, pub name: String,
/// Map name. /// Map name.
pub active_mod: String, pub active_mod: String,
/// Running game mode. /// Running game mode.
pub game_mode: String, pub game_mode: String,
/// The version that the server is running on.
pub game_version: String,
/// Description of the server. /// Description of the server.
pub description: String, pub description: String,
/// The version that the server is running on.
pub version: String,
/// Current map. /// Current map.
pub map: String, pub map: String,
/// Number of players on the server. /// Number of players on the server.
@ -50,13 +50,13 @@ impl CommonResponse for Response {
fn as_original(&self) -> GenericResponse { GenericResponse::FFOW(self) } fn as_original(&self) -> GenericResponse { GenericResponse::FFOW(self) }
fn name(&self) -> Option<&str> { Some(&self.name) } fn name(&self) -> Option<&str> { Some(&self.name) }
fn game(&self) -> Option<&str> { Some(&self.game_mode) } fn game_mode(&self) -> Option<&str> { Some(&self.game_mode) }
fn description(&self) -> Option<&str> { Some(&self.description) } fn description(&self) -> Option<&str> { Some(&self.description) }
fn game_version(&self) -> Option<&str> { Some(&self.version) } fn game_version(&self) -> Option<&str> { Some(&self.game_version) }
fn map(&self) -> Option<&str> { Some(&self.map) } fn map(&self) -> Option<&str> { Some(&self.map) }
fn has_password(&self) -> Option<bool> { Some(self.has_password) } fn has_password(&self) -> Option<bool> { Some(self.has_password) }
fn players_maximum(&self) -> u64 { self.players_maximum.into() } fn players_maximum(&self) -> u32 { self.players_maximum.into() }
fn players_online(&self) -> u64 { self.players_online.into() } fn players_online(&self) -> u32 { self.players_online.into() }
} }
pub fn query(address: &IpAddr, port: Option<u16>) -> GDResult<Response> { query_with_timeout(address, port, None) } pub fn query(address: &IpAddr, port: Option<u16>) -> GDResult<Response> { query_with_timeout(address, port, None) }
@ -79,13 +79,13 @@ pub fn query_with_timeout(
let mut buffer = Buffer::<LittleEndian>::new(&data); let mut buffer = Buffer::<LittleEndian>::new(&data);
let protocol = buffer.read::<u8>()?; let protocol_version = buffer.read::<u8>()?;
let name = buffer.read_string::<Utf8Decoder>(None)?; let name = buffer.read_string::<Utf8Decoder>(None)?;
let map = buffer.read_string::<Utf8Decoder>(None)?; let map = buffer.read_string::<Utf8Decoder>(None)?;
let active_mod = buffer.read_string::<Utf8Decoder>(None)?; let active_mod = buffer.read_string::<Utf8Decoder>(None)?;
let game_mode = buffer.read_string::<Utf8Decoder>(None)?; let game_mode = buffer.read_string::<Utf8Decoder>(None)?;
let description = buffer.read_string::<Utf8Decoder>(None)?; let description = buffer.read_string::<Utf8Decoder>(None)?;
let version = buffer.read_string::<Utf8Decoder>(None)?; let game_version = buffer.read_string::<Utf8Decoder>(None)?;
buffer.move_cursor(2)?; buffer.move_cursor(2)?;
let players_online = buffer.read::<u8>()?; let players_online = buffer.read::<u8>()?;
let players_maximum = buffer.read::<u8>()?; let players_maximum = buffer.read::<u8>()?;
@ -99,12 +99,12 @@ pub fn query_with_timeout(
let time_left = buffer.read::<u16>()?; let time_left = buffer.read::<u16>()?;
Ok(Response { Ok(Response {
protocol, protocol_version,
name, name,
active_mod, active_mod,
game_mode, game_mode,
game_version,
description, description,
version,
map, map,
players_online, players_online,
players_maximum, players_maximum,

View file

@ -27,28 +27,24 @@ impl CommonPlayer for Player {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Response { pub struct Response {
version: String, game_version: String,
description: String, description: String,
name: String, name: String,
has_password: bool, has_password: bool,
players: Vec<Player>, players: Vec<Player>,
players_maximum: usize, players_maximum: u32,
players_online: usize, players_online: u32,
} }
impl CommonResponse for Response { impl CommonResponse for Response {
fn as_original(&self) -> GenericResponse { GenericResponse::JC2MP(self) } fn as_original(&self) -> GenericResponse { GenericResponse::JC2MP(self) }
fn game_version(&self) -> Option<&str> { Some(&self.version) } fn game_version(&self) -> Option<&str> { Some(&self.game_version) }
fn description(&self) -> Option<&str> { Some(&self.description) } fn description(&self) -> Option<&str> { Some(&self.description) }
fn name(&self) -> Option<&str> { Some(&self.name) } fn name(&self) -> Option<&str> { Some(&self.name) }
fn has_password(&self) -> Option<bool> { Some(self.has_password) } fn has_password(&self) -> Option<bool> { Some(self.has_password) }
fn players_maximum(&self) -> u64 { fn players_maximum(&self) -> u32 { self.players_maximum }
// If usize doesn't fit in u64 silently return 0 as this is extremely unlikely fn players_online(&self) -> u32 { self.players_online }
// for a player count
self.players_maximum.try_into().unwrap_or(0)
}
fn players_online(&self) -> u64 { self.players_online.try_into().unwrap_or(0) }
fn players(&self) -> Option<Vec<&dyn crate::protocols::types::CommonPlayer>> { fn players(&self) -> Option<Vec<&dyn crate::protocols::types::CommonPlayer>> {
Some( Some(
@ -113,10 +109,10 @@ pub fn query_with_timeout(
false => reported_players, false => reported_players,
} }
} }
}; } as u32;
Ok(Response { Ok(Response {
version: server_vars game_version: server_vars
.remove("version") .remove("version")
.ok_or(GDErrorKind::PacketBad)?, .ok_or(GDErrorKind::PacketBad)?,
description: server_vars description: server_vars

View file

@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, PartialOrd)] #[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct TheShipPlayer { pub struct TheShipPlayer {
pub name: String, pub name: String,
pub score: u32, pub score: i32,
pub duration: f32, pub duration: f32,
pub deaths: u32, pub deaths: u32,
pub money: u32, pub money: u32,
@ -39,24 +39,24 @@ impl CommonPlayer for TheShipPlayer {
fn as_original(&self) -> GenericPlayer { GenericPlayer::TheShip(self) } fn as_original(&self) -> GenericPlayer { GenericPlayer::TheShip(self) }
fn name(&self) -> &str { &self.name } fn name(&self) -> &str { &self.name }
fn score(&self) -> Option<u32> { Some(self.score) } fn score(&self) -> Option<i32> { Some(self.score) }
} }
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Response { pub struct Response {
pub protocol: u8, pub protocol_version: u8,
pub name: String, pub name: String,
pub map: String, pub map: String,
pub game: String, pub game_mode: String,
pub players: u8, pub game_version: String,
pub players_details: Vec<TheShipPlayer>, pub players: Vec<TheShipPlayer>,
pub max_players: u8, pub players_online: u8,
pub bots: u8, pub players_maximum: u8,
pub players_bots: u8,
pub server_type: Server, pub server_type: Server,
pub has_password: bool, pub has_password: bool,
pub vac_secured: bool, pub vac_secured: bool,
pub version: String,
pub port: Option<u16>, pub port: Option<u16>,
pub steam_id: Option<u64>, pub steam_id: Option<u64>,
pub tv_port: Option<u16>, pub tv_port: Option<u16>,
@ -73,15 +73,15 @@ impl CommonResponse for Response {
fn name(&self) -> Option<&str> { Some(&self.name) } fn name(&self) -> Option<&str> { Some(&self.name) }
fn map(&self) -> Option<&str> { Some(&self.map) } fn map(&self) -> Option<&str> { Some(&self.map) }
fn game(&self) -> Option<&str> { Some(&self.game) } fn game_mode(&self) -> Option<&str> { Some(&self.game_mode) }
fn players_maximum(&self) -> u64 { self.max_players.into() } fn players_maximum(&self) -> u32 { self.players_maximum.into() }
fn players_online(&self) -> u64 { self.players.into() } fn players_online(&self) -> u32 { self.players_online.into() }
fn players_bots(&self) -> Option<u64> { Some(self.bots.into()) } fn players_bots(&self) -> Option<u32> { Some(self.players_bots.into()) }
fn has_password(&self) -> Option<bool> { Some(self.has_password) } fn has_password(&self) -> Option<bool> { Some(self.has_password) }
fn players(&self) -> Option<Vec<&dyn CommonPlayer>> { fn players(&self) -> Option<Vec<&dyn CommonPlayer>> {
Some( Some(
self.players_details self.players
.iter() .iter()
.map(|p| p as &dyn CommonPlayer) .map(|p| p as &dyn CommonPlayer)
.collect(), .collect(),
@ -96,23 +96,23 @@ impl Response {
let the_unwrapped_ship = response.info.the_ship.unwrap(); let the_unwrapped_ship = response.info.the_ship.unwrap();
Self { Self {
protocol: response.info.protocol, protocol_version: response.info.protocol_version,
name: response.info.name, name: response.info.name,
map: response.info.map, map: response.info.map,
game: response.info.game, game_mode: response.info.game_mode,
players: response.info.players_online, game_version: response.info.game_version,
players_details: response players_online: response.info.players_online,
players: response
.players .players
.unwrap() .unwrap()
.iter() .iter()
.map(TheShipPlayer::new_from_valve_player) .map(TheShipPlayer::new_from_valve_player)
.collect(), .collect(),
max_players: response.info.players_maximum, players_maximum: response.info.players_maximum,
bots: response.info.players_bots, players_bots: response.info.players_bots,
server_type: response.info.server_type, server_type: response.info.server_type,
has_password: response.info.has_password, has_password: response.info.has_password,
vac_secured: response.info.vac_secured, vac_secured: response.info.vac_secured,
version: response.info.version,
port, port,
steam_id, steam_id,
tv_port, tv_port,

View file

@ -87,8 +87,8 @@ fn get_server_values(
Ok(server_values) Ok(server_values)
} }
fn extract_players(server_vars: &mut HashMap<String, String>, players_maximum: usize) -> GDResult<Vec<Player>> { fn extract_players(server_vars: &mut HashMap<String, String>, players_maximum: u32) -> GDResult<Vec<Player>> {
let mut players_data: Vec<HashMap<String, String>> = Vec::with_capacity(players_maximum); let mut players_data: Vec<HashMap<String, String>> = Vec::with_capacity(players_maximum as usize);
server_vars.retain(|key, value| { server_vars.retain(|key, value| {
let split: Vec<&str> = key.split('_').collect(); let split: Vec<&str> = key.split('_').collect();
@ -201,7 +201,7 @@ pub fn query_vars(
pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) -> GDResult<Response> { pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) -> GDResult<Response> {
let mut server_vars = query_vars(address, timeout_settings)?; let mut server_vars = query_vars(address, timeout_settings)?;
let players_maximum = server_vars let players_maximum: u32 = server_vars
.remove("maxplayers") .remove("maxplayers")
.ok_or(GDErrorKind::PacketBad)? .ok_or(GDErrorKind::PacketBad)?
.parse() .parse()
@ -226,14 +226,14 @@ pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) ->
.remove("AdminName") .remove("AdminName")
.or_else(|| server_vars.remove("admin")), .or_else(|| server_vars.remove("admin")),
has_password: has_password(&mut server_vars)?, has_password: has_password(&mut server_vars)?,
game_type: server_vars game_mode: server_vars
.remove("gametype") .remove("gametype")
.ok_or(GDErrorKind::PacketBad)?, .ok_or(GDErrorKind::PacketBad)?,
game_version: server_vars game_version: server_vars
.remove("gamever") .remove("gamever")
.ok_or(GDErrorKind::PacketBad)?, .ok_or(GDErrorKind::PacketBad)?,
players_maximum, players_maximum,
players_online: players.len(), players_online: players.len() as u32,
players_minimum, players_minimum,
players, players,
tournament: server_vars tournament: server_vars

View file

@ -18,7 +18,7 @@ pub struct Player {
pub face: String, pub face: String,
pub skin: String, pub skin: String,
pub mesh: String, pub mesh: String,
pub score: u32, pub score: i32,
pub deaths: Option<u32>, pub deaths: Option<u32>,
pub health: Option<u32>, pub health: Option<u32>,
pub secret: bool, pub secret: bool,
@ -28,7 +28,7 @@ impl CommonPlayer for Player {
fn as_original(&self) -> GenericPlayer { GenericPlayer::Gamespy(VersionedPlayer::One(self)) } fn as_original(&self) -> GenericPlayer { GenericPlayer::Gamespy(VersionedPlayer::One(self)) }
fn name(&self) -> &str { &self.name } fn name(&self) -> &str { &self.name }
fn score(&self) -> Option<u32> { Some(self.score) } fn score(&self) -> Option<i32> { Some(self.score) }
} }
/// A query response. /// A query response.
@ -41,10 +41,10 @@ pub struct Response {
pub admin_contact: Option<String>, pub admin_contact: Option<String>,
pub admin_name: Option<String>, pub admin_name: Option<String>,
pub has_password: bool, pub has_password: bool,
pub game_type: String, pub game_mode: String,
pub game_version: String, pub game_version: String,
pub players_maximum: usize, pub players_maximum: u32,
pub players_online: usize, pub players_online: u32,
pub players_minimum: Option<u8>, pub players_minimum: Option<u8>,
pub players: Vec<Player>, pub players: Vec<Player>,
pub tournament: bool, pub tournament: bool,
@ -57,10 +57,10 @@ impl CommonResponse for Response {
fn name(&self) -> Option<&str> { Some(&self.name) } fn name(&self) -> Option<&str> { Some(&self.name) }
fn map(&self) -> Option<&str> { Some(&self.map) } fn map(&self) -> Option<&str> { Some(&self.map) }
fn has_password(&self) -> Option<bool> { Some(self.has_password) } fn has_password(&self) -> Option<bool> { Some(self.has_password) }
fn game(&self) -> Option<&str> { Some(&self.game_type) } fn game_mode(&self) -> Option<&str> { Some(&self.game_mode) }
fn game_version(&self) -> Option<&str> { Some(&self.game_version) } fn game_version(&self) -> Option<&str> { Some(&self.game_version) }
fn players_maximum(&self) -> u64 { self.players_maximum.try_into().unwrap_or(0) } fn players_maximum(&self) -> u32 { self.players_maximum }
fn players_online(&self) -> u64 { self.players_online.try_into().unwrap_or(0) } fn players_online(&self) -> u32 { self.players_online }
fn players(&self) -> Option<Vec<&dyn CommonPlayer>> { fn players(&self) -> Option<Vec<&dyn CommonPlayer>> {
Some( Some(

View file

@ -358,7 +358,7 @@ pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) ->
None => None, None => None,
Some(v) => Some(v.parse::<u8>().map_err(|e| TypeParse.context(e))?), Some(v) => Some(v.parse::<u8>().map_err(|e| TypeParse.context(e))?),
}; };
let players_online = match server_vars.remove("numplayers") { let players_online: u32 = match server_vars.remove("numplayers") {
None => players.len(), None => players.len(),
Some(v) => { Some(v) => {
let reported_players = v.parse().map_err(|e| TypeParse.context(e))?; let reported_players = v.parse().map_err(|e| TypeParse.context(e))?;
@ -367,7 +367,7 @@ pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) ->
false => reported_players, false => reported_players,
} }
} }
}; } as u32;
Ok(Response { Ok(Response {
name: server_vars name: server_vars
@ -377,7 +377,7 @@ pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) ->
.remove("mapname") .remove("mapname")
.ok_or(GDErrorKind::PacketBad)?, .ok_or(GDErrorKind::PacketBad)?,
has_password: has_password(&mut server_vars)?, has_password: has_password(&mut server_vars)?,
game_type: server_vars game_mode: server_vars
.remove("gametype") .remove("gametype")
.ok_or(GDErrorKind::PacketBad)?, .ok_or(GDErrorKind::PacketBad)?,
game_version: server_vars game_version: server_vars

View file

@ -24,7 +24,7 @@ impl CommonPlayer for Player {
} }
fn name(&self) -> &str { &self.name } fn name(&self) -> &str { &self.name }
fn score(&self) -> Option<u32> { Some(self.score.try_into().unwrap_or(0)) } fn score(&self) -> Option<i32> { Some(self.score) }
} }
/// A team's details /// A team's details
@ -42,10 +42,10 @@ pub struct Response {
pub name: String, pub name: String,
pub map: String, pub map: String,
pub has_password: bool, pub has_password: bool,
pub game_type: String, pub game_mode: String,
pub game_version: String, pub game_version: String,
pub players_maximum: usize, pub players_maximum: u32,
pub players_online: usize, pub players_online: u32,
pub players_minimum: Option<u8>, pub players_minimum: Option<u8>,
pub players: Vec<Player>, pub players: Vec<Player>,
pub teams: Vec<Team>, pub teams: Vec<Team>,
@ -59,10 +59,10 @@ impl CommonResponse for Response {
fn name(&self) -> Option<&str> { Some(&self.name) } fn name(&self) -> Option<&str> { Some(&self.name) }
fn map(&self) -> Option<&str> { Some(&self.map) } fn map(&self) -> Option<&str> { Some(&self.map) }
fn has_password(&self) -> Option<bool> { Some(self.has_password) } fn has_password(&self) -> Option<bool> { Some(self.has_password) }
fn game(&self) -> Option<&str> { Some(&self.game_type) } fn game_mode(&self) -> Option<&str> { Some(&self.game_mode) }
fn game_version(&self) -> Option<&str> { Some(&self.game_version) } fn game_version(&self) -> Option<&str> { Some(&self.game_version) }
fn players_maximum(&self) -> u64 { self.players_maximum.try_into().unwrap_or(0) } fn players_maximum(&self) -> u32 { self.players_maximum }
fn players_online(&self) -> u64 { self.players_online.try_into().unwrap_or(0) } fn players_online(&self) -> u32 { self.players_online }
fn players(&self) -> Option<Vec<&dyn CommonPlayer>> { fn players(&self) -> Option<Vec<&dyn CommonPlayer>> {
Some( Some(

View file

@ -173,10 +173,10 @@ pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) ->
false => reported_players, false => reported_players,
} }
} }
}; } as u32;
let players_minimum = match server_vars.remove("minplayers") { let players_minimum = match server_vars.remove("minplayers") {
None => None, None => None,
Some(v) => Some(v.parse::<u8>().map_err(|e| TypeParse.context(e))?), Some(v) => Some(v.parse::<u32>().map_err(|e| TypeParse.context(e))?),
}; };
Ok(Response { Ok(Response {

View file

@ -27,7 +27,7 @@ impl CommonPlayer for Player {
fn as_original(&self) -> GenericPlayer { GenericPlayer::Gamespy(VersionedPlayer::Two(self)) } fn as_original(&self) -> GenericPlayer { GenericPlayer::Gamespy(VersionedPlayer::Two(self)) }
fn name(&self) -> &str { &self.name } fn name(&self) -> &str { &self.name }
fn score(&self) -> Option<u32> { Some(self.score.into()) } fn score(&self) -> Option<i32> { Some(self.score.into()) }
} }
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -37,9 +37,9 @@ pub struct Response {
pub map: String, pub map: String,
pub has_password: bool, pub has_password: bool,
pub teams: Vec<Team>, pub teams: Vec<Team>,
pub players_maximum: usize, pub players_maximum: u32,
pub players_online: usize, pub players_online: u32,
pub players_minimum: Option<u8>, pub players_minimum: Option<u32>,
pub players: Vec<Player>, pub players: Vec<Player>,
pub unused_entries: HashMap<String, String>, pub unused_entries: HashMap<String, String>,
} }
@ -50,8 +50,8 @@ impl CommonResponse for Response {
fn name(&self) -> Option<&str> { Some(&self.name) } fn name(&self) -> Option<&str> { Some(&self.name) }
fn map(&self) -> Option<&str> { Some(&self.map) } fn map(&self) -> Option<&str> { Some(&self.map) }
fn has_password(&self) -> Option<bool> { Some(self.has_password) } fn has_password(&self) -> Option<bool> { Some(self.has_password) }
fn players_maximum(&self) -> u64 { self.players_maximum.try_into().unwrap_or(0) } fn players_maximum(&self) -> u32 { self.players_maximum }
fn players_online(&self) -> u64 { self.players_online.try_into().unwrap_or(0) } fn players_online(&self) -> u32 { self.players_online }
fn players(&self) -> Option<Vec<&dyn CommonPlayer>> { fn players(&self) -> Option<Vec<&dyn CommonPlayer>> {
Some( Some(

View file

@ -83,7 +83,7 @@ impl Bedrock {
edition: status[0].to_string(), edition: status[0].to_string(),
name: status[1].to_string(), name: status[1].to_string(),
version_name: status[3].to_string(), version_name: status[3].to_string(),
version_protocol: status[2].to_string(), protocol_version: status[2].to_string(),
players_maximum: status[5].parse().map_err(|e| TypeParse.context(e))?, players_maximum: status[5].parse().map_err(|e| TypeParse.context(e))?,
players_online: status[4].parse().map_err(|e| TypeParse.context(e))?, players_online: status[4].parse().map_err(|e| TypeParse.context(e))?,
id: status.get(6).map(|v| v.to_string()), id: status.get(6).map(|v| v.to_string()),

View file

@ -96,11 +96,11 @@ impl Java {
let json_response = get_string(&mut buffer)?; let json_response = get_string(&mut buffer)?;
let value_response: Value = serde_json::from_str(&json_response).map_err(|e| JsonParse.context(e))?; let value_response: Value = serde_json::from_str(&json_response).map_err(|e| JsonParse.context(e))?;
let version_name = value_response["version"]["name"] let game_version = value_response["version"]["name"]
.as_str() .as_str()
.ok_or(PacketBad)? .ok_or(PacketBad)?
.to_string(); .to_string();
let version_protocol = value_response["version"]["protocol"] let protocol_version = value_response["version"]["protocol"]
.as_i64() .as_i64()
.ok_or(PacketBad)? as i32; .ok_or(PacketBad)? as i32;
@ -108,7 +108,7 @@ impl Java {
let online_players = value_response["players"]["online"] let online_players = value_response["players"]["online"]
.as_u64() .as_u64()
.ok_or(PacketBad)? as u32; .ok_or(PacketBad)? as u32;
let sample_players: Option<Vec<Player>> = match value_response["players"]["sample"].is_null() { let players: Option<Vec<Player>> = match value_response["players"]["sample"].is_null() {
true => None, true => None,
false => { false => {
Some({ Some({
@ -130,11 +130,11 @@ impl Java {
}; };
Ok(JavaResponse { Ok(JavaResponse {
version_name, game_version,
version_protocol, protocol_version,
players_maximum: max_players, players_maximum: max_players,
players_online: online_players, players_online: online_players,
players_sample: sample_players, players,
description: value_response["description"].to_string(), description: value_response["description"].to_string(),
favicon: value_response["favicon"].as_str().map(str::to_string), favicon: value_response["favicon"].as_str().map(str::to_string),
previews_chat: value_response["previewsChat"].as_bool(), previews_chat: value_response["previewsChat"].as_bool(),

View file

@ -51,11 +51,11 @@ impl LegacyBV1_8 {
let max_players = split[2].parse().map_err(|e| PacketBad.context(e))?; let max_players = split[2].parse().map_err(|e| PacketBad.context(e))?;
Ok(JavaResponse { Ok(JavaResponse {
version_name: "Beta 1.8+".to_string(), game_version: "Beta 1.8+".to_string(),
version_protocol: -1, protocol_version: -1,
players_maximum: max_players, players_maximum: max_players,
players_online: online_players, players_online: online_players,
players_sample: None, players: None,
description, description,
favicon: None, favicon: None,
previews_chat: None, previews_chat: None,

View file

@ -54,11 +54,11 @@ impl LegacyV1_4 {
let max_players = split[2].parse().map_err(|e| PacketBad.context(e))?; let max_players = split[2].parse().map_err(|e| PacketBad.context(e))?;
Ok(JavaResponse { Ok(JavaResponse {
version_name: "1.4+".to_string(), game_version: "1.4+".to_string(),
version_protocol: -1, protocol_version: -1,
players_maximum: max_players, players_maximum: max_players,
players_online: online_players, players_online: online_players,
players_sample: None, players: None,
description, description,
favicon: None, favicon: None,
previews_chat: None, previews_chat: None,

View file

@ -52,11 +52,11 @@ impl LegacyV1_6 {
pub(crate) fn get_response(buffer: &mut Buffer<BigEndian>) -> GDResult<JavaResponse> { pub(crate) fn get_response(buffer: &mut Buffer<BigEndian>) -> GDResult<JavaResponse> {
// This is a specific order! // This is a specific order!
let version_protocol = buffer let protocol_version = buffer
.read_string::<Utf16Decoder<BigEndian>>(None)? .read_string::<Utf16Decoder<BigEndian>>(None)?
.parse() .parse()
.map_err(|e| PacketBad.context(e))?; .map_err(|e| PacketBad.context(e))?;
let version_name = buffer.read_string::<Utf16Decoder<BigEndian>>(None)?; let game_version = buffer.read_string::<Utf16Decoder<BigEndian>>(None)?;
let description = buffer.read_string::<Utf16Decoder<BigEndian>>(None)?; let description = buffer.read_string::<Utf16Decoder<BigEndian>>(None)?;
let online_players = buffer let online_players = buffer
.read_string::<Utf16Decoder<BigEndian>>(None)? .read_string::<Utf16Decoder<BigEndian>>(None)?
@ -68,11 +68,11 @@ impl LegacyV1_6 {
.map_err(|e| PacketBad.context(e))?; .map_err(|e| PacketBad.context(e))?;
Ok(JavaResponse { Ok(JavaResponse {
version_name, game_version,
version_protocol, protocol_version,
players_maximum: max_players, players_maximum: max_players,
players_online: online_players, players_online: online_players,
players_sample: None, players: None,
description, description,
favicon: None, favicon: None,
previews_chat: None, previews_chat: None,

View file

@ -66,16 +66,16 @@ pub enum VersionedResponse<'a> {
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct JavaResponse { pub struct JavaResponse {
/// Version name, example: "1.19.2". /// Version name, example: "1.19.2".
pub version_name: String, pub game_version: String,
/// Version protocol, example: 760 (for 1.19.2). Note that for versions /// Protocol version, example: 760 (for 1.19.1 or 1.19.2).
/// below 1.6 this field is always -1. /// Note that for versions below 1.6 this field is always -1.
pub version_protocol: i32, pub protocol_version: i32,
/// Number of server capacity. /// Number of server capacity.
pub players_maximum: u32, pub players_maximum: u32,
/// Number of online players. /// Number of online players.
pub players_online: u32, pub players_online: u32,
/// Some online players (can be missing). /// Some online players (can be missing).
pub players_sample: Option<Vec<Player>>, pub players: Option<Vec<Player>>,
/// Server's description or MOTD. /// Server's description or MOTD.
pub description: String, pub description: String,
/// The favicon (can be missing). /// The favicon (can be missing).
@ -92,12 +92,12 @@ impl CommonResponse for JavaResponse {
fn as_original(&self) -> GenericResponse { GenericResponse::Minecraft(VersionedResponse::Java(self)) } fn as_original(&self) -> GenericResponse { GenericResponse::Minecraft(VersionedResponse::Java(self)) }
fn description(&self) -> Option<&str> { Some(&self.description) } fn description(&self) -> Option<&str> { Some(&self.description) }
fn players_maximum(&self) -> u64 { self.players_maximum.into() } fn players_maximum(&self) -> u32 { self.players_maximum }
fn players_online(&self) -> u64 { self.players_online.into() } fn players_online(&self) -> u32 { self.players_online }
fn game_version(&self) -> Option<&str> { Some(&self.version_name) } fn game_version(&self) -> Option<&str> { Some(&self.game_version) }
fn players(&self) -> Option<Vec<&dyn CommonPlayer>> { fn players(&self) -> Option<Vec<&dyn CommonPlayer>> {
self.players_sample self.players
.as_ref() .as_ref()
.map(|players| players.iter().map(|p| p as &dyn CommonPlayer).collect()) .map(|players| players.iter().map(|p| p as &dyn CommonPlayer).collect())
} }
@ -113,8 +113,8 @@ pub struct BedrockResponse {
pub name: String, pub name: String,
/// Version name, example: "1.19.40". /// Version name, example: "1.19.40".
pub version_name: String, pub version_name: String,
/// Version protocol, example: 760 (for 1.19.2). /// Protocol version, example: 760 (for 1.19.2).
pub version_protocol: String, pub protocol_version: String,
/// Maximum number of players the server reports it can hold. /// Maximum number of players the server reports it can hold.
pub players_maximum: u32, pub players_maximum: u32,
/// Number of players on the server. /// Number of players on the server.
@ -135,18 +135,18 @@ impl CommonResponse for BedrockResponse {
fn name(&self) -> Option<&str> { Some(&self.name) } fn name(&self) -> Option<&str> { Some(&self.name) }
fn map(&self) -> Option<&str> { self.map.as_deref() } fn map(&self) -> Option<&str> { self.map.as_deref() }
fn game_version(&self) -> Option<&str> { Some(&self.version_name) } fn game_version(&self) -> Option<&str> { Some(&self.version_name) }
fn players_maximum(&self) -> u64 { self.players_maximum.into() } fn players_maximum(&self) -> u32 { self.players_maximum }
fn players_online(&self) -> u64 { self.players_online.into() } fn players_online(&self) -> u32 { self.players_online }
} }
impl JavaResponse { impl JavaResponse {
pub fn from_bedrock_response(response: BedrockResponse) -> Self { pub fn from_bedrock_response(response: BedrockResponse) -> Self {
Self { Self {
version_name: response.version_name, game_version: response.version_name,
version_protocol: 0, protocol_version: 0,
players_maximum: response.players_maximum, players_maximum: response.players_maximum,
players_online: response.players_online, players_online: response.players_online,
players_sample: None, players: None,
description: response.name, description: response.name,
favicon: None, favicon: None,
previews_chat: None, previews_chat: None,

View file

@ -118,7 +118,7 @@ pub(crate) fn client_query<Client: QuakeClient>(
.parse() .parse()
.map_err(|e| TypeParse.context(e))?, .map_err(|e| TypeParse.context(e))?,
players, players,
version: server_vars game_version: server_vars
.remove("version") .remove("version")
.or(server_vars.remove("*version")), .or(server_vars.remove("*version")),
unused_entries: server_vars, unused_entries: server_vars,

View file

@ -33,7 +33,7 @@ impl CommonPlayer for Player {
fn as_original(&self) -> GenericPlayer { GenericPlayer::QuakeOne(self) } fn as_original(&self) -> GenericPlayer { GenericPlayer::QuakeOne(self) }
fn name(&self) -> &str { &self.name } fn name(&self) -> &str { &self.name }
fn score(&self) -> Option<u32> { Some(self.score.into()) } fn score(&self) -> Option<i32> { Some(self.score.into()) }
} }
pub(crate) struct QuakeOne; pub(crate) struct QuakeOne;

View file

@ -32,7 +32,7 @@ impl CommonPlayer for Player {
fn name(&self) -> &str { &self.name } fn name(&self) -> &str { &self.name }
fn score(&self) -> Option<u32> { Some(self.score.try_into().unwrap_or(0)) } fn score(&self) -> Option<i32> { Some(self.score) }
} }
pub(crate) struct QuakeTwo; pub(crate) struct QuakeTwo;

View file

@ -22,7 +22,7 @@ pub struct Response<P> {
/// Maximum number of players the server reports it can hold. /// Maximum number of players the server reports it can hold.
pub players_maximum: u8, pub players_maximum: u8,
/// The server version. /// The server version.
pub version: Option<String>, pub game_version: Option<String>,
/// Other server entries that weren't used. /// Other server entries that weren't used.
pub unused_entries: HashMap<String, String>, pub unused_entries: HashMap<String, String>,
} }
@ -35,10 +35,10 @@ impl<P: QuakePlayerType> CommonResponse for Response<P> {
fn as_original(&self) -> GenericResponse { GenericResponse::Quake(P::version(self)) } fn as_original(&self) -> GenericResponse { GenericResponse::Quake(P::version(self)) }
fn name(&self) -> Option<&str> { Some(&self.name) } fn name(&self) -> Option<&str> { Some(&self.name) }
fn game_version(&self) -> Option<&str> { self.version.as_deref() } fn game_version(&self) -> Option<&str> { self.game_version.as_deref() }
fn map(&self) -> Option<&str> { Some(&self.map) } fn map(&self) -> Option<&str> { Some(&self.map) }
fn players_maximum(&self) -> u64 { self.players_maximum.into() } fn players_maximum(&self) -> u32 { self.players_maximum.into() }
fn players_online(&self) -> u64 { self.players_online.into() } fn players_online(&self) -> u32 { self.players_online.into() }
fn players(&self) -> Option<Vec<&dyn CommonPlayer>> { fn players(&self) -> Option<Vec<&dyn CommonPlayer>> {
Some( Some(

View file

@ -66,7 +66,7 @@ pub trait CommonResponse {
CommonResponseJson { CommonResponseJson {
name: self.name(), name: self.name(),
description: self.description(), description: self.description(),
game: self.game(), game_mode: self.game_mode(),
game_version: self.game_version(), game_version: self.game_version(),
has_password: self.has_password(), has_password: self.has_password(),
map: self.map(), map: self.map(),
@ -84,17 +84,17 @@ pub trait CommonResponse {
/// Description of the server /// Description of the server
fn description(&self) -> Option<&str> { None } fn description(&self) -> Option<&str> { None }
/// Name of the current game or game mode /// Name of the current game or game mode
fn game(&self) -> Option<&str> { None } fn game_mode(&self) -> Option<&str> { None }
/// Version of the game being run on the server /// Version of the game being run on the server
fn game_version(&self) -> Option<&str> { None } fn game_version(&self) -> Option<&str> { None }
/// The current map name /// The current map name
fn map(&self) -> Option<&str> { None } fn map(&self) -> Option<&str> { None }
/// Maximum number of players allowed to connect /// Maximum number of players allowed to connect
fn players_maximum(&self) -> u64; fn players_maximum(&self) -> u32;
/// Number of players currently connected /// Number of players currently connected
fn players_online(&self) -> u64; fn players_online(&self) -> u32;
/// Number of bots currently connected /// Number of bots currently connected
fn players_bots(&self) -> Option<u64> { None } fn players_bots(&self) -> Option<u32> { None }
/// Whether the server requires a password to join /// Whether the server requires a password to join
fn has_password(&self) -> Option<bool> { None } fn has_password(&self) -> Option<bool> { None }
/// Currently connected players /// Currently connected players
@ -106,12 +106,12 @@ pub trait CommonResponse {
pub struct CommonResponseJson<'a> { pub struct CommonResponseJson<'a> {
pub name: Option<&'a str>, pub name: Option<&'a str>,
pub description: Option<&'a str>, pub description: Option<&'a str>,
pub game: Option<&'a str>, pub game_mode: Option<&'a str>,
pub game_version: Option<&'a str>, pub game_version: Option<&'a str>,
pub map: Option<&'a str>, pub map: Option<&'a str>,
pub players_maximum: u64, pub players_maximum: u32,
pub players_online: u64, pub players_online: u32,
pub players_bots: Option<u64>, pub players_bots: Option<u32>,
pub has_password: Option<bool>, pub has_password: Option<bool>,
pub players: Option<Vec<CommonPlayerJson<'a>>>, pub players: Option<Vec<CommonPlayerJson<'a>>>,
} }
@ -131,14 +131,14 @@ pub trait CommonPlayer {
/// Player name /// Player name
fn name(&self) -> &str; fn name(&self) -> &str;
/// Player score /// Player score
fn score(&self) -> Option<u32> { None } fn score(&self) -> Option<i32> { None }
} }
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct CommonPlayerJson<'a> { pub struct CommonPlayerJson<'a> {
pub name: &'a str, pub name: &'a str,
pub score: Option<u32>, pub score: Option<i32>,
} }
/// Timeout settings for socket operations /// Timeout settings for socket operations

View file

@ -211,7 +211,7 @@ impl ValveProtocol {
let name = buffer.read_string::<Utf8Decoder>(None)?; let name = buffer.read_string::<Utf8Decoder>(None)?;
let map = buffer.read_string::<Utf8Decoder>(None)?; let map = buffer.read_string::<Utf8Decoder>(None)?;
let folder = buffer.read_string::<Utf8Decoder>(None)?; let folder = buffer.read_string::<Utf8Decoder>(None)?;
let game = buffer.read_string::<Utf8Decoder>(None)?; let game_mode = buffer.read_string::<Utf8Decoder>(None)?;
let players = buffer.read()?; let players = buffer.read()?;
let max_players = buffer.read()?; let max_players = buffer.read()?;
let protocol = buffer.read()?; let protocol = buffer.read()?;
@ -245,11 +245,11 @@ impl ValveProtocol {
let bots = buffer.read::<u8>()?; let bots = buffer.read::<u8>()?;
Ok(ServerInfo { Ok(ServerInfo {
protocol, protocol_version: protocol,
name, name,
map, map,
folder, folder,
game, game_mode,
appid: 0, // not present in the obsolete response appid: 0, // not present in the obsolete response
players_online: players, players_online: players,
players_maximum: max_players, players_maximum: max_players,
@ -259,7 +259,7 @@ impl ValveProtocol {
has_password, has_password,
vac_secured, vac_secured,
the_ship: None, the_ship: None,
version: "".to_string(), // a version field only for the mod game_version: "".to_string(), // a version field only for the mod
extra_data: None, extra_data: None,
is_mod, is_mod,
mod_data, mod_data,
@ -281,7 +281,7 @@ impl ValveProtocol {
let name = buffer.read_string::<Utf8Decoder>(None)?; let name = buffer.read_string::<Utf8Decoder>(None)?;
let map = buffer.read_string::<Utf8Decoder>(None)?; let map = buffer.read_string::<Utf8Decoder>(None)?;
let folder = buffer.read_string::<Utf8Decoder>(None)?; let folder = buffer.read_string::<Utf8Decoder>(None)?;
let game = buffer.read_string::<Utf8Decoder>(None)?; let game_mode = buffer.read_string::<Utf8Decoder>(None)?;
let mut appid = buffer.read::<u16>()? as u32; let mut appid = buffer.read::<u16>()? as u32;
let players = buffer.read()?; let players = buffer.read()?;
let max_players = buffer.read()?; let max_players = buffer.read()?;
@ -300,7 +300,7 @@ impl ValveProtocol {
}) })
} }
}; };
let version = buffer.read_string::<Utf8Decoder>(None)?; let game_version = buffer.read_string::<Utf8Decoder>(None)?;
let extra_data = match buffer.read::<u8>() { let extra_data = match buffer.read::<u8>() {
Err(_) => None, Err(_) => None,
Ok(value) => { Ok(value) => {
@ -339,11 +339,11 @@ impl ValveProtocol {
}; };
Ok(ServerInfo { Ok(ServerInfo {
protocol, protocol_version: protocol,
name, name,
map, map,
folder, folder,
game, game_mode,
appid, appid,
players_online: players, players_online: players,
players_maximum: max_players, players_maximum: max_players,
@ -353,7 +353,7 @@ impl ValveProtocol {
has_password, has_password,
vac_secured, vac_secured,
the_ship, the_ship,
version, game_version,
extra_data, extra_data,
is_mod: false, is_mod: false,
mod_data: None, mod_data: None,
@ -436,7 +436,6 @@ fn get_response(
let mut client = ValveProtocol::new(address, timeout_settings)?; let mut client = ValveProtocol::new(address, timeout_settings)?;
let info = client.get_server_info(&engine)?; let info = client.get_server_info(&engine)?;
let protocol = info.protocol;
if let Engine::Source(Some(appids)) = &engine { if let Engine::Source(Some(appids)) = &engine {
let mut is_specified_id = false; let mut is_specified_id = false;
@ -454,6 +453,8 @@ fn get_response(
} }
} }
let protocol = info.protocol_version;
Ok(Response { Ok(Response {
info, info,
players: match gather_settings.players { players: match gather_settings.players {

View file

@ -61,12 +61,12 @@ impl CommonResponse for Response {
fn as_original(&self) -> GenericResponse { GenericResponse::Valve(self) } fn as_original(&self) -> GenericResponse { GenericResponse::Valve(self) }
fn name(&self) -> Option<&str> { Some(&self.info.name) } fn name(&self) -> Option<&str> { Some(&self.info.name) }
fn game(&self) -> Option<&str> { Some(&self.info.game) } fn game_mode(&self) -> Option<&str> { Some(&self.info.game_mode) }
fn game_version(&self) -> Option<&str> { Some(&self.info.version) } fn game_version(&self) -> Option<&str> { Some(&self.info.game_version) }
fn map(&self) -> Option<&str> { Some(&self.info.map) } fn map(&self) -> Option<&str> { Some(&self.info.map) }
fn players_maximum(&self) -> u64 { self.info.players_maximum.into() } fn players_maximum(&self) -> u32 { self.info.players_maximum.into() }
fn players_online(&self) -> u64 { self.info.players_online.into() } fn players_online(&self) -> u32 { self.info.players_online.into() }
fn players_bots(&self) -> Option<u64> { Some(self.info.players_bots.into()) } fn players_bots(&self) -> Option<u32> { Some(self.info.players_bots.into()) }
fn has_password(&self) -> Option<bool> { Some(self.info.has_password) } fn has_password(&self) -> Option<bool> { Some(self.info.has_password) }
fn players(&self) -> Option<Vec<&dyn CommonPlayer>> { fn players(&self) -> Option<Vec<&dyn CommonPlayer>> {
@ -81,15 +81,15 @@ impl CommonResponse for Response {
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ServerInfo { pub struct ServerInfo {
/// Protocol used by the server. /// Protocol used by the server.
pub protocol: u8, pub protocol_version: u8,
/// Name of the server. /// Name of the server.
pub name: String, pub name: String,
/// Map name. /// Map name.
pub map: String, pub map: String,
/// Name of the folder containing the game files. /// Name of the folder containing the game files.
pub folder: String, pub folder: String,
/// The name of the game. /// The server-declared name of the game/game mode.
pub game: String, pub game_mode: String,
/// [Steam Application ID](https://developer.valvesoftware.com/wiki/Steam_Application_ID) of game. /// [Steam Application ID](https://developer.valvesoftware.com/wiki/Steam_Application_ID) of game.
pub appid: u32, pub appid: u32,
/// Number of players on the server. /// Number of players on the server.
@ -109,7 +109,7 @@ pub struct ServerInfo {
/// [The ship](https://developer.valvesoftware.com/wiki/The_Ship) extra data /// [The ship](https://developer.valvesoftware.com/wiki/The_Ship) extra data
pub the_ship: Option<TheShip>, pub the_ship: Option<TheShip>,
/// Version of the game installed on the server. /// Version of the game installed on the server.
pub version: String, pub game_version: String,
/// Some extra data that the server might provide or not. /// Some extra data that the server might provide or not.
pub extra_data: Option<ExtraData>, pub extra_data: Option<ExtraData>,
/// GoldSrc only: Indicates whether the hosted game is a mod. /// GoldSrc only: Indicates whether the hosted game is a mod.
@ -125,7 +125,7 @@ pub struct ServerPlayer {
/// Player's name. /// Player's name.
pub name: String, pub name: String,
/// General score. /// General score.
pub score: u32, pub score: i32,
/// How long a player has been in the server (seconds). /// How long a player has been in the server (seconds).
pub duration: f32, pub duration: f32,
/// Only for [the ship](https://developer.valvesoftware.com/wiki/The_Ship): deaths count /// Only for [the ship](https://developer.valvesoftware.com/wiki/The_Ship): deaths count
@ -137,7 +137,7 @@ pub struct ServerPlayer {
impl CommonPlayer for ServerPlayer { impl CommonPlayer for ServerPlayer {
fn as_original(&self) -> GenericPlayer { GenericPlayer::Valve(self) } fn as_original(&self) -> GenericPlayer { GenericPlayer::Valve(self) }
fn name(&self) -> &str { &self.name } fn name(&self) -> &str { &self.name }
fn score(&self) -> Option<u32> { Some(self.score) } fn score(&self) -> Option<i32> { Some(self.score) }
} }
/// Only present for [the ship](https://developer.valvesoftware.com/wiki/The_Ship). /// Only present for [the ship](https://developer.valvesoftware.com/wiki/The_Ship).
@ -447,7 +447,7 @@ pub mod game {
/// Player's name. /// Player's name.
pub name: String, pub name: String,
/// Player's score. /// Player's score.
pub score: u32, pub score: i32,
/// How long a player has been in the server (seconds). /// How long a player has been in the server (seconds).
pub duration: f32, pub duration: f32,
} }
@ -511,10 +511,10 @@ pub mod game {
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 { Self {
protocol: response.info.protocol, protocol: response.info.protocol_version,
name: response.info.name, name: response.info.name,
map: response.info.map, map: response.info.map,
game: response.info.game, game: response.info.game_mode,
appid: response.info.appid, appid: response.info.appid,
players_online: response.info.players_online, players_online: response.info.players_online,
players_details: response players_details: response
@ -528,7 +528,7 @@ pub mod game {
server_type: response.info.server_type, server_type: response.info.server_type,
has_password: response.info.has_password, has_password: response.info.has_password,
vac_secured: response.info.vac_secured, vac_secured: response.info.vac_secured,
version: response.info.version, version: response.info.game_version,
port, port,
steam_id, steam_id,
tv_port, tv_port,