1use std::io::Cursor;
2#[cfg(not(feature = "async"))]
3use std::net::ToSocketAddrs;
4
5#[cfg(feature = "async")]
6use tokio::net::ToSocketAddrs;
7
8use byteorder::{LittleEndian, ReadBytesExt};
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13use crate::errors::{Error, Result};
14use crate::{A2SClient, ReadCString};
15
16const PLAYER_REQUEST: [u8; 5] = [0xff, 0xff, 0xff, 0xff, 0x55];
17
18#[derive(Debug, Clone)]
19#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
20pub struct Player {
21 pub index: u8,
24
25 pub name: String,
27
28 pub score: i32,
30
31 pub duration: f32,
33
34 pub the_ship: Option<TheShipPlayer>,
36}
37
38#[derive(Debug, Clone)]
39#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
40pub struct TheShipPlayer {
41 pub deaths: u32,
42
43 pub money: u32,
44}
45
46impl Player {
47 pub fn from_cursor(mut data: Cursor<Vec<u8>>, app_id: u16) -> Result<Vec<Self>> {
48 if data.read_u8()? != 0x44 {
49 return Err(Error::InvalidResponse);
50 }
51
52 let player_count = data.read_u8()?;
53
54 let mut players: Vec<Self> = Vec::with_capacity(player_count as usize);
55
56 for _ in 0..player_count {
57 players.push(Self {
58 index: data.read_u8()?,
59 name: data.read_cstring()?,
60 score: data.read_i32::<LittleEndian>()?,
61 duration: data.read_f32::<LittleEndian>()?,
62 the_ship: {
63 if app_id == 2400 {
64 Some(TheShipPlayer {
65 deaths: data.read_u32::<LittleEndian>()?,
66 money: data.read_u32::<LittleEndian>()?,
67 })
68 } else {
69 None
70 }
71 },
72 })
73 }
74
75 Ok(players)
76 }
77}
78
79impl A2SClient {
80 #[cfg(feature = "async")]
81 pub async fn players<A: ToSocketAddrs>(&self, addr: A) -> Result<Vec<Player>> {
82 let data = self.do_challenge_request(addr, &PLAYER_REQUEST).await?;
83 Player::from_cursor(Cursor::new(data), self.app_id)
84 }
85
86 #[cfg(not(feature = "async"))]
87 pub fn players<A: ToSocketAddrs>(&self, addr: A) -> Result<Vec<Player>> {
88 let data = self.do_challenge_request(addr, &PLAYER_REQUEST)?;
89 Player::from_cursor(Cursor::new(data), self.app_id)
90 }
91}