diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index 522a30b..e7c7efe 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs @@ -176,6 +176,25 @@ fn collect_server_stats( } } +/// Emits one measurement window's diagnostics to the log. +/// +/// A dedicated server is headless and has no statistics panel to read, so the same snapshot pushed to clients is also reported locally. The cadence is the measurement window rather than the tick, which keeps the line rare enough to leave the log readable while still surfacing a rate collapse within a second. +fn report_statistics(stats: &ServerStats) { + info!( + tps = stats.measured_tps, + mean_tick_ms = stats.mean_tick_ms, + max_tick_ms = stats.max_tick_ms, + budget_percent = stats.tick_budget_percent, + chunks = stats.loaded_chunks, + in_flight = stats.chunks_in_flight, + clients = stats.connected_clients, + entities = stats.entities, + players = stats.players, + uptime_secs = stats.uptime_secs, + "simulation status" + ); +} + /// Runs the authoritative simulation loop forever, at the fixed cadence given by [`TICK_PERIOD`]. fn run_simulation(world: &mut World, network: &NetworkServer) -> ! { // Chunk diffs are computed against an all-air baseline so each delivered payload is self-contained: the client renders only server-owned content and has no generator to reconstruct a worldgen baseline. Allocated once and shared across every delivery. @@ -243,6 +262,7 @@ fn run_simulation(world: &mut World, network: &NetworkServer) -> ! { // Diagnostics are pushed on the authority stream once per measurement window, not per tick: the figures describe the window, and per-tick delivery would be pure waste. if let Some(window) = meter.take_window(tick_start + elapsed) { let stats = collect_server_stats(world, &window, clients.len(), started_at); + report_statistics(&stats); for client in clients.values() { client.send_stats(stats); }