mirror of
https://github.com/tribufu/rust-gamedig
synced 2026-05-06 07:17:27 +00:00
Almost completed the valve protocol
This commit is contained in:
parent
8098136d09
commit
c9eb725a51
6 changed files with 135 additions and 43 deletions
|
|
@ -2,13 +2,9 @@
|
|||
use gamedig::TF2;
|
||||
|
||||
fn main() {
|
||||
let response = TF2::query("5.15.202.107", None);
|
||||
let response = TF2::query("91.216.250.10", None);
|
||||
match response {
|
||||
Err(_) => println!("fuck"),
|
||||
Ok(r) => {
|
||||
println!("{:?}", r);
|
||||
|
||||
()
|
||||
}
|
||||
Err(error) => println!("Couldn't query, error: {}", error),
|
||||
Ok(r) => println!("{:?}", r)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use crate::errors::GDError;
|
||||
use crate::protocol::Protocol;
|
||||
use crate::protocols::valve::{Response, ValveProtocol};
|
||||
|
||||
pub struct TF2;
|
||||
|
|
@ -9,6 +8,6 @@ impl TF2 {
|
|||
ValveProtocol::query(address, match port {
|
||||
None => 27015,
|
||||
Some(port) => port
|
||||
})
|
||||
}, false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
mod errors;
|
||||
mod protocol;
|
||||
mod protocols;
|
||||
mod utils;
|
||||
pub mod games;
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
use crate::errors::GDError;
|
||||
|
||||
pub trait Protocol {
|
||||
type Response;
|
||||
|
||||
fn query(address: &str, port: u16) -> Result<Self::Response, GDError>;
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
use std::net::UdpSocket;
|
||||
use crate::errors::GDError;
|
||||
use crate::protocol::Protocol;
|
||||
use crate::utils::{combine_two_u8, complete_address, concat_u8, find_null_in_array};
|
||||
use crate::utils::{combine_two_u8, complete_address, concat_u8, find_null_in_array, get_u64_from_buf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Server {
|
||||
|
|
@ -31,7 +30,27 @@ pub struct Response {
|
|||
pub server_type: Server,
|
||||
pub environment_type: Environment,
|
||||
pub has_password: bool,
|
||||
pub vac_secured: bool
|
||||
pub vac_secured: bool,
|
||||
pub the_ship: Option<TheShip>,
|
||||
pub version: String,
|
||||
pub extra_data: Option<ExtraData>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TheShip {
|
||||
pub mode: u8,
|
||||
pub witnesses: u8,
|
||||
pub duration: u8
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExtraData {
|
||||
pub port: Option<u16>,
|
||||
pub steam_id: Option<u64>,
|
||||
pub tv_port: Option<u16>,
|
||||
pub tv_name: Option<String>,
|
||||
pub keywords: Option<String>,
|
||||
pub game_id: Option<u64>
|
||||
}
|
||||
|
||||
pub enum Request {
|
||||
|
|
@ -43,6 +62,8 @@ pub struct ValveProtocol {
|
|||
complete_address: String
|
||||
}
|
||||
|
||||
static default_packet_size: usize = 256;
|
||||
|
||||
impl ValveProtocol {
|
||||
fn new(address: &str, port: u16) -> Self {
|
||||
Self {
|
||||
|
|
@ -85,53 +106,129 @@ impl ValveProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
impl Protocol for ValveProtocol {
|
||||
type Response = Response;
|
||||
|
||||
fn query(address: &str, port: u16) -> Result<Response, GDError> {
|
||||
impl ValveProtocol {
|
||||
pub(crate) fn query(address: &str, port: u16, has_the_ship: bool) -> Result<Response, GDError> {
|
||||
let client = ValveProtocol::new(address, port);
|
||||
|
||||
client.do_request(Request::A2sInfo(None), None);
|
||||
let mut buf = client.receive();
|
||||
let mut buf = client.receive_with_size(default_packet_size);
|
||||
|
||||
if buf[4] == 0x41 {
|
||||
client.do_request(Request::A2sInfo(Some([buf[5], buf[6], buf[7], buf[8]])), None);
|
||||
buf = client.receive_with_size(default_packet_size);
|
||||
}
|
||||
|
||||
buf = client.receive_with_size(256);
|
||||
println!("{:x?}", &buf);
|
||||
|
||||
let name_nul_pos = find_null_in_array(&mut buf);
|
||||
let map_nul_pos = name_nul_pos + 1 + find_null_in_array(&mut buf[name_nul_pos + 1..]);
|
||||
let folder_nul_pos = map_nul_pos + 1 + find_null_in_array(&mut buf[map_nul_pos + 1..]);
|
||||
let game_nul_pos = folder_nul_pos + 1 + find_null_in_array(&mut buf[folder_nul_pos + 1..]);
|
||||
let name_null_pos = find_null_in_array(&mut buf);
|
||||
let map_null_pos = name_null_pos + 1 + find_null_in_array(&mut buf[name_null_pos + 1..]);
|
||||
let folder_null_pos = map_null_pos + 1 + find_null_in_array(&mut buf[map_null_pos + 1..]);
|
||||
let game_null_pos = folder_null_pos + 1 + find_null_in_array(&mut buf[folder_null_pos + 1..]);
|
||||
|
||||
let server_type = match buf[game_nul_pos + 6] as char {
|
||||
let server_type = match buf[game_null_pos + 6] as char {
|
||||
'd' => Server::Dedicated,
|
||||
'l' => Server::NonDedicated,
|
||||
_ => Server::SourceTV
|
||||
};
|
||||
|
||||
let environment_type = match buf[game_nul_pos + 7] as char {
|
||||
let environment_type = match buf[game_null_pos + 7] as char {
|
||||
'l' => Environment::Linux,
|
||||
'w' => Environment::Windows,
|
||||
_ => Environment::Mac
|
||||
};
|
||||
|
||||
let mut the_ship_index = game_null_pos + 10;
|
||||
let the_ship = match has_the_ship {
|
||||
false => None,
|
||||
true => {
|
||||
let ship = TheShip {
|
||||
mode: buf[the_ship_index],
|
||||
witnesses: buf[the_ship_index + 1],
|
||||
duration: buf[the_ship_index + 2]
|
||||
};
|
||||
the_ship_index = the_ship_index + 3;
|
||||
Some(ship)
|
||||
}
|
||||
};
|
||||
|
||||
let version_null_pos = the_ship_index + find_null_in_array(&mut buf[the_ship_index..]);
|
||||
let extra_data = match buf.get(version_null_pos + 1) {
|
||||
None => None,
|
||||
Some(value) => {
|
||||
let mut last_edf_position = version_null_pos + 2;
|
||||
let edf_port = match (value & 0x80) > 0 {
|
||||
false => None,
|
||||
true => {
|
||||
let p = combine_two_u8(buf[last_edf_position + 1], buf[last_edf_position]);
|
||||
last_edf_position = last_edf_position + 2;
|
||||
Some(p)
|
||||
}
|
||||
};
|
||||
|
||||
let steam_id = match (value & 0x10) > 0 { //doesnt work?
|
||||
false => None,
|
||||
true => {
|
||||
let p = get_u64_from_buf(&buf[last_edf_position..]);
|
||||
last_edf_position = last_edf_position + 8;
|
||||
Some(p)
|
||||
}
|
||||
};
|
||||
|
||||
let (tv_port, tv_name) = match (value & 0x40) > 0 {
|
||||
false => (None, None),
|
||||
true => {
|
||||
let port = combine_two_u8(buf[last_edf_position + 1], buf[last_edf_position]);
|
||||
last_edf_position = last_edf_position + 2;
|
||||
let tv_name_null_pos = last_edf_position + find_null_in_array(&buf[last_edf_position..]);
|
||||
let tv_name = String::from_utf8(Vec::from(&buf[last_edf_position..tv_name_null_pos])).expect("cacat");
|
||||
last_edf_position = tv_name_null_pos + 1;
|
||||
(Some(port), Some(tv_name))
|
||||
}
|
||||
};
|
||||
|
||||
let keywords = match (value & 0x20) > 0 {
|
||||
false => None,
|
||||
true => {
|
||||
let kws_null_pos = last_edf_position + find_null_in_array(&buf[last_edf_position..]);
|
||||
let kws = String::from_utf8(Vec::from(&buf[last_edf_position..kws_null_pos])).expect("cacat");
|
||||
last_edf_position = kws_null_pos + 1;
|
||||
Some(kws)
|
||||
}
|
||||
};
|
||||
|
||||
let game_id = match (value & 0x01) > 0 {
|
||||
false => None,
|
||||
true => Some(get_u64_from_buf(&buf[last_edf_position..]))
|
||||
};
|
||||
|
||||
Some(ExtraData {
|
||||
port: edf_port,
|
||||
steam_id,
|
||||
tv_port,
|
||||
tv_name,
|
||||
keywords,
|
||||
game_id
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Response {
|
||||
protocol: buf[5],
|
||||
name: String::from_utf8(Vec::from(&mut buf[6..name_nul_pos])).expect("cacat"),
|
||||
map: String::from_utf8(Vec::from(&mut buf[name_nul_pos + 1..map_nul_pos])).expect("cacat"),
|
||||
folder: String::from_utf8(Vec::from(&mut buf[map_nul_pos + 1..folder_nul_pos])).expect("cacat"),
|
||||
game: String::from_utf8(Vec::from(&mut buf[folder_nul_pos + 1..game_nul_pos])).expect("cacat"),
|
||||
id: combine_two_u8(buf[game_nul_pos + 2], buf[game_nul_pos + 1]),
|
||||
players: buf[game_nul_pos + 3],
|
||||
max_players: buf[game_nul_pos + 4],
|
||||
bots: buf[game_nul_pos + 5],
|
||||
name: String::from_utf8(Vec::from(&mut buf[6..name_null_pos])).expect("cacat"),
|
||||
map: String::from_utf8(Vec::from(&mut buf[name_null_pos + 1..map_null_pos])).expect("cacat"),
|
||||
folder: String::from_utf8(Vec::from(&mut buf[map_null_pos + 1..folder_null_pos])).expect("cacat"),
|
||||
game: String::from_utf8(Vec::from(&mut buf[folder_null_pos + 1..game_null_pos])).expect("cacat"),
|
||||
id: combine_two_u8(buf[game_null_pos + 2], buf[game_null_pos + 1]),
|
||||
players: buf[game_null_pos + 3],
|
||||
max_players: buf[game_null_pos + 4],
|
||||
bots: buf[game_null_pos + 5],
|
||||
server_type,
|
||||
environment_type,
|
||||
has_password: buf[game_nul_pos + 8] == 1,
|
||||
vac_secured: buf[game_nul_pos + 9] != 0
|
||||
has_password: buf[game_null_pos + 8] == 1,
|
||||
vac_secured: buf[game_null_pos + 9] != 0,
|
||||
the_ship,
|
||||
version: String::from_utf8(Vec::from(&mut buf[the_ship_index..version_null_pos])).expect("cacat"),
|
||||
extra_data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
src/utils.rs
10
src/utils.rs
|
|
@ -16,5 +16,13 @@ pub fn complete_address(address: &str, port: u16) -> String {
|
|||
}
|
||||
|
||||
pub fn combine_two_u8(high: u8, low: u8) -> u16 {
|
||||
((high as u16) << 8) | low as u16
|
||||
u16::from_be_bytes([high, low])
|
||||
}
|
||||
|
||||
pub fn combine_eight_u8(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8) -> u64 {
|
||||
u64::from_be_bytes([a, b, c, d, e, f, g, h])
|
||||
}
|
||||
|
||||
pub fn get_u64_from_buf(buf: &[u8]) -> u64 {
|
||||
combine_eight_u8(buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0])
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue