Files
source-gamepanel/apps/daemon/src/game/minecraft.rs
T
2026-02-22 00:25:39 +03:00

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);
}
}