use std::{env, io::Cursor, net::TcpStream}; use minecraft_protocol::{types::VarInt, v1_18::{serverbound::Handshake, PROTOCOL_VERSION}, PacketContent}; use log::debug; struct Packet where T: PacketContent, { packet_id: VarInt, content: T, } impl Packet where T: PacketContent, { fn read_from(reader: &mut R) -> Result 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(&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::().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 = 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") ); } } } }