diff --git a/Cargo.lock b/Cargo.lock index 296b1a7f49..4ba2c9fb92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7103,6 +7103,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "veloren-query-server" +version = "0.1.0" +dependencies = [ + "protocol", + "tokio", + "tracing", + "tracing-subscriber", +] + [[package]] name = "veloren-rtsim" version = "0.10.0" @@ -7171,6 +7181,7 @@ dependencies = [ "veloren-common-state", "veloren-common-systems", "veloren-network", + "veloren-query-server", "veloren-rtsim", "veloren-server-agent", "veloren-world", @@ -7224,16 +7235,6 @@ dependencies = [ "veloren-world", ] -[[package]] -name = "veloren-server-query" -version = "0.1.0" -dependencies = [ - "protocol", - "tokio", - "tracing", - "tracing-subscriber", -] - [[package]] name = "veloren-voxygen" version = "0.16.0" diff --git a/common/query_server/Cargo.toml b/common/query_server/Cargo.toml index 271cbe7f9d..097a4a7b33 100644 --- a/common/query_server/Cargo.toml +++ b/common/query_server/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "veloren-server-query" +name = "veloren-query-server" version = "0.1.0" authors = ["crabman ", "XVar "] edition = "2021" diff --git a/server/Cargo.toml b/server/Cargo.toml index 5b180d2f9a..23ba5bd05c 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -18,6 +18,7 @@ default = ["worldgen", "plugins", "persistent_world", "simd"] [dependencies] common = { package = "veloren-common", path = "../common" } common-base = { package = "veloren-common-base", path = "../common/base" } +veloren-query-server = { package = "veloren-query-server", path = "../common/query_server", features = ["server"] } common-ecs = { package = "veloren-common-ecs", path = "../common/ecs" } common-state = { package = "veloren-common-state", path = "../common/state" } common-systems = { package = "veloren-common-systems", path = "../common/systems" } diff --git a/server/src/lib.rs b/server/src/lib.rs index 332b2275d6..58a4959883 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -124,6 +124,7 @@ use test_world::{IndexOwned, World}; use tokio::runtime::Runtime; use tracing::{debug, error, info, trace, warn}; use vek::*; +use veloren_query_server::server::QueryServer; pub use world::{civ::WorldCivStage, sim::WorldSimStage, WorldGenerateStage}; use crate::{ @@ -597,6 +598,28 @@ impl Server { } } + if let Some(addr) = settings.query_address { + use veloren_query_server::proto::ServerInfo; + + let (query_server_info_tx, query_server_info_rx) = + tokio::sync::watch::channel(ServerInfo { + git_hash: *sys::server_info::GIT_HASH, + players_count: 0, + player_cap: settings.max_players, + battlemode: settings.gameplay.battle_mode.into(), + }); + let mut query_server = QueryServer::new(addr, query_server_info_rx); + let query_server_metrics = Arc::new(tokio::sync::RwLock::new( + veloren_query_server::server::Metrics::default(), + )); + let query_server_metrics2 = Arc::clone(&query_server_metrics); + runtime.spawn(async move { + _ = query_server.run(query_server_metrics2).await; + }); + state.ecs_mut().insert(query_server_info_tx); + state.ecs_mut().insert(query_server_metrics); + } + runtime.block_on(network.listen(ListenAddr::Mpsc(14004)))?; let connection_handler = ConnectionHandler::new(network, &runtime); diff --git a/server/src/settings.rs b/server/src/settings.rs index 880df37062..efb2013dfb 100644 --- a/server/src/settings.rs +++ b/server/src/settings.rs @@ -67,6 +67,20 @@ impl ServerBattleMode { } } +impl From for veloren_query_server::proto::ServerBattleMode { + fn from(value: ServerBattleMode) -> Self { + use veloren_query_server::proto::ServerBattleMode as QueryBattleMode; + + match value { + ServerBattleMode::Global(mode) => match mode { + BattleMode::PvP => QueryBattleMode::GlobalPvP, + BattleMode::PvE => QueryBattleMode::GlobalPvE, + }, + ServerBattleMode::PerPlayer { .. } => QueryBattleMode::PerPlayer, + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Protocol { Quic { @@ -163,6 +177,7 @@ impl CalendarMode { pub struct Settings { pub gameserver_protocols: Vec, pub auth_server_address: Option, + pub query_address: Option, pub max_players: u16, pub world_seed: u32, pub server_name: String, @@ -204,6 +219,7 @@ impl Default for Settings { }, ], auth_server_address: Some("https://auth.veloren.net".into()), + query_address: Some(SocketAddr::from((Ipv4Addr::UNSPECIFIED, 14006))), world_seed: DEFAULT_WORLD_SEED, server_name: "Veloren Server".into(), max_players: 100, diff --git a/server/src/sys/mod.rs b/server/src/sys/mod.rs index f53c62fa71..cf9276fae3 100644 --- a/server/src/sys/mod.rs +++ b/server/src/sys/mod.rs @@ -11,6 +11,7 @@ pub mod object; pub mod persistence; pub mod pets; pub mod sentinel; +pub mod server_info; pub mod subscription; pub mod teleporter; pub mod terrain; diff --git a/server/src/sys/server_info.rs b/server/src/sys/server_info.rs new file mode 100644 index 0000000000..fd01ec8a70 --- /dev/null +++ b/server/src/sys/server_info.rs @@ -0,0 +1,47 @@ +use common_ecs::{Origin, Phase, System}; +use lazy_static::lazy_static; +use specs::{Read, ReadStorage}; +use veloren_query_server::proto::ServerInfo; + +use crate::{client::Client, Settings, Tick}; + +// Update the server stats every 60 ticks +const INFO_SEND_INTERVAL: u64 = 60; + +lazy_static! { + pub static ref GIT_HASH: [char; 10] = common::util::GIT_HASH[..10] + .chars() + .collect::>() + .try_into() + .unwrap_or_default(); +} + +#[derive(Default)] +pub struct Sys; + +impl<'a> System<'a> for Sys { + type SystemData = ( + Read<'a, Tick>, + Read<'a, Settings>, + Read<'a, Option>>, + ReadStorage<'a, Client>, + ); + + const NAME: &'static str = "server_info"; + const ORIGIN: Origin = Origin::Server; + const PHASE: Phase = Phase::Create; + + fn run(_job: &mut common_ecs::Job, (tick, settings, sender, clients): Self::SystemData) { + if let Some(sender) = sender.as_ref() + && tick.0 % INFO_SEND_INTERVAL == 0 + { + let count = clients.count().try_into().unwrap_or(u16::MAX); + _ = sender.send(ServerInfo { + git_hash: *GIT_HASH, + players_count: count, + player_cap: settings.max_players, + battlemode: settings.gameplay.battle_mode.into(), + }); + } + } +}