Files
dorf/src/system_info.rs
T
popertots 017ddb8047 feat: add distro, kernel version, and display resolution+Hz to system info
Distro parsed from /etc/os-release PRETTY_NAME.
Kernel from uname -r.
Display resolution and refresh rate from xrandr (linux only, N/A elsewhere).
2026-03-20 17:20:29 +00:00

195 lines
5.8 KiB
Rust

use std::env;
use std::fs;
use std::process::Command;
use crate::config::{GameConfig, VsyncMode};
use crate::constants::SEED;
pub fn print_system_info(config: &GameConfig) {
let os = format!("{} {}", env::consts::OS, env::consts::ARCH);
let distro = distro_info();
let kernel = kernel_info();
let cpu = cpu_info();
let gpu = gpu_info();
let (ram_total, ram_free) = mem_info();
let (res, hz) = display_info();
let display = vsync_label(&config.display.vsync);
let radius = config.initial_chunk_radius;
let seed = SEED;
let line_width = 34;
let hline = format!("{:─<width$}", "", width = line_width);
println!();
println!("╔═{hline}═╗");
println!("║{:^width$}║", "DORF SYSTEM", width = line_width + 2);
println!("╠═{hline}═╣");
println!("║ OS: {:<width$}║", os, width = line_width);
println!("║ Distro: {:<width$}║", distro, width = line_width);
println!("║ Kernel: {:<width$}║", kernel, width = line_width);
println!("║ CPU: {:<width$}║", cpu, width = line_width);
println!("║ GPU: {:<width$}║", gpu, width = line_width);
println!(
"║ RAM: {:<width$}║",
format!("{} GB ({} GB free)", ram_total, ram_free),
width = line_width
);
println!(
"║ Display: {:<width$}║",
format!("{} @ {}Hz {}", res, hz, display),
width = line_width
);
println!(
"║ Radius: {:<width$}║",
format!("{} chunks", radius),
width = line_width
);
println!("║ Seed: {:<width$}║", seed, width = line_width);
println!("╚═{hline}═╝");
println!();
}
fn cpu_info() -> String {
#[cfg(target_os = "linux")]
{
let Ok(content) = fs::read_to_string("/proc/cpuinfo") else {
return String::from("Unknown CPU");
};
let model_name = content
.lines()
.find(|l| l.starts_with("model name"))
.and_then(|l| l.split(':').nth(1))
.map(|s| s.trim().to_string())
.unwrap_or_else(|| String::from("Unknown CPU"));
let core_count = content
.lines()
.filter(|l| l.starts_with("processor"))
.count()
.max(1);
format!("{} ({} cores)", model_name, core_count)
}
#[cfg(not(target_os = "linux"))]
{
let cores = env::var("NUMBER_OF_PROCESSORS")
.ok()
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(1);
format!("Unknown CPU ({} cores)", cores)
}
}
fn gpu_info() -> String {
env::var("WEBGPU_ADAPTER_NAME").unwrap_or_else(|_| String::from("Unknown GPU"))
}
fn mem_info() -> (u64, u64) {
#[cfg(target_os = "linux")]
{
let Ok(content) = fs::read_to_string("/proc/meminfo") else {
return (0, 0);
};
let parse_kb = |key: &str| -> u64 {
content
.lines()
.find(|l| l.starts_with(key))
.and_then(|l| {
l.split_whitespace()
.nth(1)
.and_then(|s| s.parse::<u64>().ok())
})
.unwrap_or(0)
};
let total_kb = parse_kb("MemTotal:");
let available_kb = parse_kb("MemAvailable:");
let total_gb = total_kb / 1024 / 1024;
let available_gb = available_kb / 1024 / 1024;
(total_gb, available_gb)
}
#[cfg(not(target_os = "linux"))]
{
(0, 0)
}
}
fn vsync_label(mode: &VsyncMode) -> &'static str {
match mode {
VsyncMode::Vsync => "vsync",
VsyncMode::Mailbox => "mailbox",
VsyncMode::Uncapped => "uncapped",
}
}
fn distro_info() -> String {
#[cfg(target_os = "linux")]
{
if let Ok(content) = fs::read_to_string("/etc/os-release") {
let pretty_name = content
.lines()
.find(|l| l.starts_with("PRETTY_NAME="))
.and_then(|l| l.split('=').nth(1))
.map(|s| s.trim_matches('"').to_string());
if let Some(name) = pretty_name {
return name;
}
}
String::from("Unknown distro")
}
#[cfg(not(target_os = "linux"))]
{
String::from("N/A")
}
}
fn kernel_info() -> String {
#[cfg(target_os = "linux")]
{
if let Ok(output) = Command::new("uname").arg("-r").output() {
if let Ok(kernel) = String::from_utf8(output.stdout) {
return kernel.trim().to_string();
}
}
String::from("Unknown kernel")
}
#[cfg(not(target_os = "linux"))]
{
String::from("N/A")
}
}
fn display_info() -> (String, String) {
#[cfg(target_os = "linux")]
{
if let Ok(output) = Command::new("xrandr").output() {
if let Ok(xr) = String::from_utf8(output.stdout) {
let lines: Vec<&str> = xr.lines().collect();
if let Some(current) = lines.iter().find(|l| l.contains("+*")) {
let parts: Vec<&str> = current.split_whitespace().collect();
let res = parts.get(0).unwrap_or(&"unknown");
let mut hz = String::from("60");
for part in &parts[1..] {
if part.ends_with("Hz") || part.parse::<f32>().is_ok() {
hz = part
.trim_end_matches("Hz*")
.trim_end_matches("Hz")
.to_string();
break;
}
}
return (res.to_string(), hz);
}
}
}
}
#[cfg(not(target_os = "linux"))]
return (String::from("N/A"), String::from("N/A"));
(String::from("unknown"), String::from("?"))
}