veloren_server/sys/
server_info.rs

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