diff --git a/examples/watch.rs b/examples/watch.rs new file mode 100644 index 0000000..1222643 --- /dev/null +++ b/examples/watch.rs @@ -0,0 +1,102 @@ +use mcquery::Query; +use std::{ + io::{ + Result, + Error, + ErrorKind, + }, + time::Duration, + env::args, +}; + +#[tokio::main] +async fn main() -> Result<()> { + // get address + let address = args() + .nth(1).unwrap(); + + // initialize buffer + let mut buffer = vec![ + 0; + args().nth(2) + .unwrap_or("1024".to_owned()) + .parse().map_err(|e| Error::new(ErrorKind::InvalidInput, e))? + ]; + + // get initial status + let mut response = match Query::get_full(address.clone(), Duration::from_secs(3), &mut buffer).await? { + Query::Full(r) => r, + _ => unreachable!() + }; + + // running v + println!("{} running {} v{}", + address, + response.software.unwrap_or("Minecraft".to_owned()), + response.kv["version"] + ); + + // MOTD + println!("{}", response.kv["hostname"]); + + // Players (/): + println!("Players ({:>width$}/{}): {}", + response.kv["numplayers"], + response.kv["maxplayers"], + response.players.join(" "), + width=response.kv["maxplayers"].len() + ); + + // update status every second + let mut interval = tokio::time::interval(Duration::from_secs(10)); + loop { + interval.tick().await; + + // get the new status + let new_response = match Query::get_full(address.clone(), Duration::from_secs(3), &mut buffer).await? { + Query::Full(r) => r, + _ => unreachable!() + }; + + // initialize player joining/leaving log + let mut player_log = Vec::<(String, bool)>::new(); + + // reference buffer + let mut player_ref = response.players.clone(); + + // figure out player joining/leaving sequence from order in response + { + let mut i = 0; + loop { + if i >= new_response.players.len() { + player_log.extend(player_ref.drain(new_response.players.len()..).map(|p| (p, false))); + break; + } else if i == player_ref.len() { + player_ref.push(new_response.players[i].clone()); + player_log.push((new_response.players[i].clone(), true)); + } else if player_ref[i] == new_response.players[i] { + i += 1; + } else if player_ref.len() > i { + player_log.push((player_ref.remove(i), false)); + } + } + } + + // if data is correct, print player joining/leaving log + if player_ref == new_response.players { + for (player, online) in player_log { + println!("{} {} the game", player, if online { + "joined" + } else { + "left" + }); + } + } else { + eprintln!("Error when parsing player joining/leaving"); + } + + if response.players != new_response.players { + response = new_response; + } + } +} \ No newline at end of file