[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`.
- `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
### Changes:
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
| Field | Generic | GameSpy(1) | GameSpy(2) | GameSpy(3) | Minecraft(Java) | Minecraft(Bedrock) | Valve | Quake | Proprietary: FFOW | Proprietary: TheShip |
| :--------------- | ---------------- | ------------ | ------------ | ------------ | ----------------- | -------------------- | -------- | -------- | -------- | --------- |
| name | `Option<String>` | `String` | `String` | `String` | | `String` | `String` | `String` | `String` | `String` |
| description | `Option<String>` | | | | `String` | | | | `String` | |
| game | `Option<String>` | `String` (game_type) | | `String` (game_type) | | `Option<GameMode>` (game_mode) | `String` | | `String` (game_mode) | `String` |
| game_version | `Option<String>` | `String` | | `String` | `String` (version_name) | | `String` (version) | `String` (version) | `String` (version) | `String` (version) |
| 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_online | `u64` | `usize` | `usize` | `usize` | `u32` | `u32` | `u8` | `u8` | `u8` | `u8` (players) |
| players_bots | `Option<u64>` | | | | | | `u8` | | | `u8` (bots) |
| has_password | `Option<bool>` | `bool` | `bool` | `bool` | | | `bool` | | `bool` | `bool` |
| map_title | | `Option<String>` | | | | | | | | |
| admin_contact | | `Option<String>` | | | | | | | | |
| admin_name | | `Option<String>` | | | | | | | | |
| players_minimum | | `Option<u8>` | `Option<u8>` | `Option<u8>` | | | | | | |
| players | | `Vec<Player>` | `Vec<Player>` | `Vec<Player>` | | | `Option<Vec<ServerPlayer>>` | `Vec<P>` | | `Vec<TheShipPlayer>` (player_details) |
| tournament | | `bool` | |`bool` | | | | | | |
| unused_entries | | `Hashmap<String, String>` | | `HashMap<String, String>` | | | `Option<ExtraData>` (extra_data) | `HashMap<String, String>` | | |
| teams | | | `Vec<Team>` | `Vec<Team>` | | | | | | |
| version_protocol | | | | | `i32` | `String` | `u8` (protocol) | | `u8` (protocol) | `u8` (protocol) |
| players_sample | | | | | `Option<Vec<Player>>` | | | | | |
| favicon | | | | | `Option<String>` | | | | | |
| previews_chat | | | | | `Option<bool>` | | | | | |
| enforces_secure_chat | | | | | `Option<bool>` | | | | | |
| server_type | | | | | `Server` | `Server` | `Server` | | | `Server` |
| edition | | | | | | `String` | | | | |
| id | | | | | | `String` | | | | |
| rules | | | | | | | `Option<HashMap<String,String>>` | | | `HashMap<String,String>` |
| folder | | | | | | | `String` | | | |
| appid | | | | | | | `u32` | | | |
| environment_type | | | | | | | `Environment` | | `Environment` | |
| vac_secured | | | | | | | `bool` | | `bool` | `bool` |
| the_ship | | | | | | | `Option<TheShip>` | | | |
| is_mod | | | | | | | `bool` | | | |
| mod_data | | | | | | | `Option<ModData>` | | | |
| active_mod | | | | | | | | | `String` | |
| round | | | | | | | | | `u8` | |
| rounds_maximum | | | | | | | | | `u8` | |
| time_left | | | | | | | | | `u16` | |
| port | | | | | | | | | | `Option<u16>` |
| steam_id | | | | | | | | | | `Option<u64>` |
| tv_port | | | | | | | | | | `Option<u16>` |
| tv_name | | | | | | | | | | `Option<String>` |
| keywords | | | | | | | | | | `Option<string>` |
| mode | | | | | | | | | | `u8` |
| witnesses | | | | | | | | | | `u8` |
| duration | | | | | | | | | | `u8` |
| 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` | `String` |
| description | `Option<String>` | | | | `String` | | | | `String` | | `String` |
| game_mode | `Option<String>` | `String` | | `String` | | `Option<GameMode>` | `String` | | `String` | `String` | |
| game_version | `Option<String>` | `String` | | `String` | `String` | | `String` | `String` | `String` | `String` | `String` |
| map | `Option<String>` | `String` | `String` | `String` | | `Option<String>` | `String` | `String` | `String` | `String` | |
| players_maxmimum | `u32` | `u32` | `u32` | `u32` | `u32` | `u32` | `u8` | `u8` | `u8` | `u8` | `u32` |
| players_online | `u32` | `u32` | `u32` | `u32` | `u32` | `u32` | `u8` | `u8` | `u8` | `u8` | `u32` |
| players_bots | `Option<u32>` | | | | | | `u8` | | | `u8` | |
| has_password | `Option<bool>` | `bool` | `bool` | `bool` | | | `bool` | | `bool` | `bool` | `bool` |
| players_minimum | | `Option<u8>` | `Option<u8>` | `Option<u8>` | | | | | | | |
| players | | `Vec<Player>` | `Vec<Player>` | `Vec<Player>` | `Option<Vec<Player>>` | | `Option<Vec<ServerPlayer>>` | `Vec<P>` | | `Vec<TheShipPlayer>` | `Vec<Player>` |
| tournament | | `bool` | | `bool` | | | | | | | |
| unused_entries | | `Hashmap<String, String>` | | `HashMap<String, String>` | | | | `HashMap<String, String>` | | | |
| teams | | | `Vec<Team>` | `Vec<Team>` | | | | | | | |
| protocol_version | | | | | `i32` | `String` | `u8` | | `u8` | `u8` | |
| server_type | | | | | `Server` | `Server` | `Server` | | | `Server` | |
| rules | | | | | | | `Option<HashMap<String,String>>` | | | `HashMap<String,String>` | |
| environment_type | | | | | | | `Environment` | | `Environment` | | |
| vac_secured | | | | | | | `bool` | | `bool` | `bool` | |
| map_title | | `Option<String>` | | | | | | | | | |
| admin_contact | | `Option<String>` | | | | | | | | | |
| admin_name | | `Option<String>` | | | | | | | | | |
| favicon | | | | | `Option<String>` | | | | | | |
| previews_chat | | | | | `Option<bool>` | | | | | | |
| enforces_secure_chat | | | | | `Option<bool>` | | | | | | |
| edition | | | | | | `String` | | | | | |
| id | | | | | | `String` | | | | | |
| the_ship | | | | | | | `Option<TheShip>` | | | | |
| is_mod | | | | | | | `bool` | | | | |
| extra_data | | | | | | | `Option<ExtraData>` | | | | |
| mod_data | | | | | | | `Option<ModData>` | | | | |
| folder | | | | | | | `String` | | | | |
| appid | | | | | | | `u32` | | | | |
| active_mod | | | | | | | | | `String` | | |
| round | | | | | | | | | `u8` | | |
| rounds_maximum | | | | | | | | | `u8` | | |
| time_left | | | | | | | | | `u16` | | |
| port | | | | | | | | | | `Option<u16>` | |
| steam_id | | | | | | | | | | `Option<u64>` | |
| tv_port | | | | | | | | | | `Option<u16>` | |
| tv_name | | | | | | | | | | `Option<String>` | |
| keywords | | | | | | | | | | `Option<string>` | |
| mode | | | | | | | | | | `u8` | |
| witnesses | | | | | | | | | | `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") {
valve_response.info.game = bat_gamemode.clone();
valve_response.info.game_mode = bat_gamemode.clone();
rules.remove("bat_gamemode_s");
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -358,7 +358,7 @@ pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) ->
None => None,
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(),
Some(v) => {
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,
}
}
};
} as u32;
Ok(Response {
name: server_vars
@ -377,7 +377,7 @@ pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) ->
.remove("mapname")
.ok_or(GDErrorKind::PacketBad)?,
has_password: has_password(&mut server_vars)?,
game_type: server_vars
game_mode: server_vars
.remove("gametype")
.ok_or(GDErrorKind::PacketBad)?,
game_version: server_vars

View file

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

View file

@ -173,10 +173,10 @@ pub fn query(address: &SocketAddr, timeout_settings: Option<TimeoutSettings>) ->
false => reported_players,
}
}
};
} as u32;
let players_minimum = match server_vars.remove("minplayers") {
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 {

View file

@ -27,7 +27,7 @@ impl CommonPlayer for Player {
fn as_original(&self) -> GenericPlayer { GenericPlayer::Gamespy(VersionedPlayer::Two(self)) }
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))]
@ -37,9 +37,9 @@ pub struct Response {
pub map: String,
pub has_password: bool,
pub teams: Vec<Team>,
pub players_maximum: usize,
pub players_online: usize,
pub players_minimum: Option<u8>,
pub players_maximum: u32,
pub players_online: u32,
pub players_minimum: Option<u32>,
pub players: Vec<Player>,
pub unused_entries: HashMap<String, String>,
}
@ -50,8 +50,8 @@ impl CommonResponse for Response {
fn name(&self) -> Option<&str> { Some(&self.name) }
fn map(&self) -> Option<&str> { Some(&self.map) }
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_online(&self) -> u64 { self.players_online.try_into().unwrap_or(0) }
fn players_maximum(&self) -> u32 { self.players_maximum }
fn players_online(&self) -> u32 { self.players_online }
fn players(&self) -> Option<Vec<&dyn CommonPlayer>> {
Some(

View file

@ -83,7 +83,7 @@ impl Bedrock {
edition: status[0].to_string(),
name: status[1].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_online: status[4].parse().map_err(|e| TypeParse.context(e))?,
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 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()
.ok_or(PacketBad)?
.to_string();
let version_protocol = value_response["version"]["protocol"]
let protocol_version = value_response["version"]["protocol"]
.as_i64()
.ok_or(PacketBad)? as i32;
@ -108,7 +108,7 @@ impl Java {
let online_players = value_response["players"]["online"]
.as_u64()
.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,
false => {
Some({
@ -130,11 +130,11 @@ impl Java {
};
Ok(JavaResponse {
version_name,
version_protocol,
game_version,
protocol_version,
players_maximum: max_players,
players_online: online_players,
players_sample: sample_players,
players,
description: value_response["description"].to_string(),
favicon: value_response["favicon"].as_str().map(str::to_string),
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))?;
Ok(JavaResponse {
version_name: "Beta 1.8+".to_string(),
version_protocol: -1,
game_version: "Beta 1.8+".to_string(),
protocol_version: -1,
players_maximum: max_players,
players_online: online_players,
players_sample: None,
players: None,
description,
favicon: 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))?;
Ok(JavaResponse {
version_name: "1.4+".to_string(),
version_protocol: -1,
game_version: "1.4+".to_string(),
protocol_version: -1,
players_maximum: max_players,
players_online: online_players,
players_sample: None,
players: None,
description,
favicon: None,
previews_chat: None,

View file

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

View file

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

View file

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

View file

@ -33,7 +33,7 @@ impl CommonPlayer for Player {
fn as_original(&self) -> GenericPlayer { GenericPlayer::QuakeOne(self) }
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;

View file

@ -32,7 +32,7 @@ impl CommonPlayer for Player {
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;

View file

@ -22,7 +22,7 @@ pub struct Response<P> {
/// Maximum number of players the server reports it can hold.
pub players_maximum: u8,
/// The server version.
pub version: Option<String>,
pub game_version: Option<String>,
/// Other server entries that weren't used.
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 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 players_maximum(&self) -> u64 { self.players_maximum.into() }
fn players_online(&self) -> u64 { self.players_online.into() }
fn players_maximum(&self) -> u32 { self.players_maximum.into() }
fn players_online(&self) -> u32 { self.players_online.into() }
fn players(&self) -> Option<Vec<&dyn CommonPlayer>> {
Some(

View file

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

View file

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

View file

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