veloren_server/sys/
server_info.rs

1use common::{
2    comp::Player,
3    util::{GIT_HASH, GIT_TIMESTAMP},
4};
5use common_ecs::{Origin, Phase, System};
6use specs::{Join, Read, ReadStorage};
7use tracing::warn;
8use veloren_query_server::proto::ServerInfo;
9
10use crate::{Settings, Tick, client::Client};
11
12// Update the server stats every 60 ticks
13const INFO_SEND_INTERVAL: u64 = 60;
14
15#[derive(Default)]
16pub struct Sys;
17
18impl<'a> System<'a> for Sys {
19    type SystemData = (
20        Read<'a, Tick>,
21        Read<'a, Settings>,
22        Option<Read<'a, tokio::sync::watch::Sender<ServerInfo>>>,
23        ReadStorage<'a, Player>,
24        ReadStorage<'a, Client>,
25    );
26
27    const NAME: &'static str = "server_info";
28    const ORIGIN: Origin = Origin::Server;
29    const PHASE: Phase = Phase::Create;
30
31    fn run(
32        _job: &mut common_ecs::Job<Self>,
33        (tick, settings, sender, players, clients): Self::SystemData,
34    ) {
35        if let Some(sender) = sender.as_ref()
36            && tick.0 % INFO_SEND_INTERVAL == 0
37        {
38            let count = (&players, &clients)
39                .join()
40                // Hide silent spectators from the player count
41                .filter(|(_, client)| client.client_type.emit_login_events())
42                .count()
43                .try_into()
44                .unwrap_or(u16::MAX);
45            if let Err(e) = sender.send(ServerInfo {
46                git_hash: *GIT_HASH,
47                git_timestamp: *GIT_TIMESTAMP,
48                players_count: count,
49                player_cap: settings.max_players,
50                battlemode: settings.gameplay.battle_mode.into(),
51            }) {
52                warn!(?e, "Failed to send server info to the query server");
53            }
54        }
55    }
56}