102 lines
3.0 KiB
Rust
102 lines
3.0 KiB
Rust
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;
|
|
}
|
|
}
|
|
} |