mcquery-rs/examples/watch.rs

102 lines
3.0 KiB
Rust
Raw Permalink Normal View History

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!()
};
// <address:port> running <software> v<version>
println!("{} running {} v{}",
address,
response.software.unwrap_or("Minecraft".to_owned()),
response.kv["version"]
);
// MOTD
println!("{}", response.kv["hostname"]);
// Players (<online>/<max>): <player+>
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;
}
}
}