170 lines
4.7 KiB
Rust
170 lines
4.7 KiB
Rust
|
use std::{env, io::Cursor, net::TcpStream};
|
||
|
|
||
|
use minecraft_protocol::{types::VarInt, v1_18::{serverbound::Handshake, PROTOCOL_VERSION}, PacketContent};
|
||
|
|
||
|
use log::debug;
|
||
|
|
||
|
struct Packet<T>
|
||
|
where
|
||
|
T: PacketContent,
|
||
|
{
|
||
|
packet_id: VarInt,
|
||
|
content: T,
|
||
|
}
|
||
|
|
||
|
impl<T> Packet<T>
|
||
|
where
|
||
|
T: PacketContent,
|
||
|
{
|
||
|
fn read_from<R>(reader: &mut R) -> Result<Self, minecraft_protocol::Error>
|
||
|
where
|
||
|
R: std::io::Read,
|
||
|
{
|
||
|
let mut packet = Vec::new();
|
||
|
let mut buffer = [0u8; 8092];
|
||
|
|
||
|
let size = reader.read(&mut buffer).unwrap();
|
||
|
|
||
|
let packet_size = {
|
||
|
let mut cursor = Cursor::new(&buffer);
|
||
|
let packet_size = VarInt::read_from(&mut cursor).unwrap();
|
||
|
packet.extend_from_slice(&buffer[cursor.position() as usize..size]);
|
||
|
packet_size
|
||
|
};
|
||
|
|
||
|
while packet.len() < packet_size.0 as usize {
|
||
|
let size = reader.read(&mut buffer).unwrap();
|
||
|
packet.extend_from_slice(&buffer[0..size]);
|
||
|
}
|
||
|
|
||
|
let mut cursor = Cursor::new(&packet);
|
||
|
let packet_id = VarInt::read_from(&mut cursor).unwrap();
|
||
|
|
||
|
let content = T::read_from(&mut cursor)?;
|
||
|
|
||
|
Ok(Packet { packet_id, content })
|
||
|
}
|
||
|
|
||
|
fn write_to<W>(&self, writer: &mut W) -> Result<(), minecraft_protocol::Error>
|
||
|
where
|
||
|
W: std::io::Write,
|
||
|
{
|
||
|
let mut write_buffer = Cursor::new(Vec::new());
|
||
|
self.packet_id.write_to(&mut write_buffer)?;
|
||
|
self.content.write_to(&mut write_buffer)?;
|
||
|
|
||
|
let write_buffer = write_buffer.get_ref();
|
||
|
|
||
|
VarInt(write_buffer.len() as i32).write_to(writer)?;
|
||
|
writer.write_all(write_buffer)?;
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
||
|
let mut args = env::args().skip(1);
|
||
|
|
||
|
let address = if let Some(ad) = args.next() {
|
||
|
ad
|
||
|
} else {
|
||
|
panic!("missing server address")
|
||
|
};
|
||
|
|
||
|
let port = if let Some(port) = args.next() {
|
||
|
port.parse::<u16>().expect("failed to get port")
|
||
|
} else {
|
||
|
25565
|
||
|
};
|
||
|
|
||
|
ping(&address, port);
|
||
|
}
|
||
|
|
||
|
fn ping(address: &str, port: u16) {
|
||
|
let mut stream = TcpStream::connect(format!("{}:{}", address, port)).unwrap();
|
||
|
|
||
|
{
|
||
|
debug!("writting ...");
|
||
|
|
||
|
let packet = Packet {
|
||
|
packet_id: VarInt(0x00),
|
||
|
content: Handshake {
|
||
|
protocol_version: VarInt(PROTOCOL_VERSION),
|
||
|
server_address: String::from(address),
|
||
|
server_port: port,
|
||
|
next_state: VarInt(1),
|
||
|
},
|
||
|
};
|
||
|
packet.write_to(&mut stream).unwrap();
|
||
|
|
||
|
let packet = Packet {
|
||
|
packet_id: VarInt(0x00),
|
||
|
content: (),
|
||
|
};
|
||
|
packet.write_to(&mut stream).unwrap();
|
||
|
}
|
||
|
|
||
|
let ping_value: serde_json::Value = {
|
||
|
debug!("reading ...");
|
||
|
|
||
|
let p: Packet<String> = Packet::read_from(&mut stream).unwrap();
|
||
|
log::trace!("{}", p.content);
|
||
|
|
||
|
serde_json::from_str(&p.content).expect("failed to decode as json")
|
||
|
};
|
||
|
|
||
|
debug!("{:#?}", ping_value);
|
||
|
|
||
|
println!("result for {}:{}", address, port);
|
||
|
let ping_value = ping_value.as_object().unwrap();
|
||
|
if let Some(version) = ping_value.get("version").and_then(|s| s.as_object()) {
|
||
|
println!(
|
||
|
"\tversion: {} ({})",
|
||
|
version
|
||
|
.get("name")
|
||
|
.and_then(|m| m.as_str())
|
||
|
.expect("failed to get version name"),
|
||
|
version
|
||
|
.get("protocol")
|
||
|
.and_then(|m| m.as_i64())
|
||
|
.expect("failed to get protocol")
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if let Some(description) = ping_value.get("description") {
|
||
|
println!(
|
||
|
"\tdescription : {}",
|
||
|
description.get("text").unwrap().as_str().unwrap()
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if let Some(players) = ping_value.get("players").and_then(|o| o.as_object()) {
|
||
|
println!("\tplayers");
|
||
|
println!(
|
||
|
"\t\tnumbers : {}/{}",
|
||
|
players
|
||
|
.get("online")
|
||
|
.and_then(|m| m.as_i64())
|
||
|
.expect("failed to get online players count"),
|
||
|
players
|
||
|
.get("max")
|
||
|
.and_then(|m| m.as_i64())
|
||
|
.expect("failed to get max player")
|
||
|
);
|
||
|
|
||
|
if let Some(sample) = players.get("sample").and_then(|s| s.as_array()) {
|
||
|
println!("\t\tsample:");
|
||
|
for player in sample {
|
||
|
println!(
|
||
|
"\t\t\t- {}",
|
||
|
player
|
||
|
.get("name")
|
||
|
.and_then(|m| m.as_str())
|
||
|
.expect("failed to get name of player")
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|