96 lines
2.7 KiB
Rust
96 lines
2.7 KiB
Rust
use anyhow::Result;
|
|
use tracing::info;
|
|
use super::rcon::RconClient;
|
|
|
|
/// Player information from Minecraft RCON.
|
|
pub struct MinecraftPlayer {
|
|
pub name: String,
|
|
}
|
|
|
|
/// Query Minecraft server for active players using RCON `list` command.
|
|
pub async fn get_players(rcon_address: &str, rcon_password: &str) -> Result<(Vec<MinecraftPlayer>, u32)> {
|
|
let mut client = RconClient::connect(rcon_address, rcon_password).await?;
|
|
let response = client.command("list").await?;
|
|
|
|
// Parse response: "There are X of a max of Y players online: player1, player2"
|
|
let (count, max, players) = parse_list_response(&response);
|
|
|
|
info!(
|
|
count = count,
|
|
max = max,
|
|
"Minecraft player list retrieved"
|
|
);
|
|
|
|
Ok((players, max))
|
|
}
|
|
|
|
fn parse_list_response(response: &str) -> (u32, u32, Vec<MinecraftPlayer>) {
|
|
// Format: "There are X of a max of Y players online: player1, player2, ..."
|
|
// Or: "There are X of a max Y players online:"
|
|
let parts: Vec<&str> = response.splitn(2, ':').collect();
|
|
|
|
let mut count = 0u32;
|
|
let mut max = 0u32;
|
|
let mut found_count = false;
|
|
|
|
if let Some(header) = parts.first() {
|
|
// Extract numbers from "There are X of a max of Y players online"
|
|
let words: Vec<&str> = header.split_whitespace().collect();
|
|
for word in words.iter() {
|
|
if let Ok(n) = word.parse::<u32>() {
|
|
if !found_count {
|
|
count = n;
|
|
found_count = true;
|
|
} else {
|
|
max = n;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut players = Vec::new();
|
|
if parts.len() > 1 {
|
|
let player_list = parts[1].trim();
|
|
if !player_list.is_empty() {
|
|
for name in player_list.split(',') {
|
|
let name = name.trim();
|
|
if !name.is_empty() {
|
|
players.push(MinecraftPlayer {
|
|
name: name.to_string(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
(count, max, players)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_parse_list_response() {
|
|
let (count, max, players) = parse_list_response(
|
|
"There are 3 of a max of 20 players online: Steve, Alex, Notch",
|
|
);
|
|
assert_eq!(count, 3);
|
|
assert_eq!(max, 20);
|
|
assert_eq!(players.len(), 3);
|
|
assert_eq!(players[0].name, "Steve");
|
|
assert_eq!(players[1].name, "Alex");
|
|
assert_eq!(players[2].name, "Notch");
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_empty_list() {
|
|
let (count, max, players) = parse_list_response(
|
|
"There are 0 of a max of 20 players online:",
|
|
);
|
|
assert_eq!(count, 0);
|
|
assert_eq!(max, 20);
|
|
assert_eq!(players.len(), 0);
|
|
}
|
|
}
|