From db9991ce6df81c8b34f7c737611d890b884aa5a1 Mon Sep 17 00:00:00 2001 From: ccgauche Date: Mon, 1 Mar 2021 22:24:02 +0100 Subject: [PATCH] Adressed all comments --- common/sys/src/plugin/module.rs | 4 + plugin/rt/src/lib.rs | 4 + server/src/lib.rs | 154 ++++++++++++++++++++++++++++-- server/src/sys/mod.rs | 1 - server/src/sys/msg/mod.rs | 3 +- server/src/sys/msg/register.rs | 160 -------------------------------- 6 files changed, 155 insertions(+), 171 deletions(-) delete mode 100644 server/src/sys/msg/register.rs diff --git a/common/sys/src/plugin/module.rs b/common/sys/src/plugin/module.rs index ecc27b07a1..2bf7ca3dec 100644 --- a/common/sys/src/plugin/module.rs +++ b/common/sys/src/plugin/module.rs @@ -157,6 +157,7 @@ impl PreparedEventQuery { pub fn get_function_name(&self) -> &str { &self.function_name } } +/// This function split a u128 in two u64 encoding them as le bytes pub fn from_u128(i: u128) -> (u64, u64) { let i = i.to_le_bytes(); ( @@ -165,14 +166,17 @@ pub fn from_u128(i: u128) -> (u64, u64) { ) } +/// This function merge two u64 encoded as le in one u128 pub fn to_u128(a: u64, b: u64) -> u128 { let a = a.to_le_bytes(); let b = b.to_le_bytes(); u128::from_le_bytes([a, b].concat().try_into().unwrap()) } +/// This function encode a u64 into a i64 using le bytes pub fn to_i64(i: u64) -> i64 { i64::from_le_bytes(i.to_le_bytes()) } +/// This function decode a i64 into a u64 using le bytes pub fn from_i64(i: i64) -> u64 { u64::from_le_bytes(i.to_le_bytes()) } // This function is not public because this function should not be used without diff --git a/plugin/rt/src/lib.rs b/plugin/rt/src/lib.rs index 78e1990395..82ef453eb4 100644 --- a/plugin/rt/src/lib.rs +++ b/plugin/rt/src/lib.rs @@ -61,6 +61,7 @@ where bincode::deserialize(slice).map_err(|_| "Failed to deserialize function input") } +/// This function split a u128 in two u64 encoding them as le bytes pub fn from_u128(i: u128) -> (u64, u64) { let i = i.to_le_bytes(); ( @@ -69,14 +70,17 @@ pub fn from_u128(i: u128) -> (u64, u64) { ) } +/// This function merge two u64 encoded as le in one u128 pub fn to_u128(a: u64, b: u64) -> u128 { let a = a.to_le_bytes(); let b = b.to_le_bytes(); u128::from_le_bytes([a, b].concat().try_into().unwrap()) } +/// This function encode a u64 into a i64 using le bytes pub fn to_i64(i: u64) -> i64 { i64::from_le_bytes(i.to_le_bytes()) } +/// This function decode a i64 into a u64 using le bytes pub fn from_i64(i: i64) -> u64 { u64::from_le_bytes(i.to_le_bytes()) } static mut VEC: Vec = vec![]; diff --git a/server/src/lib.rs b/server/src/lib.rs index 70e0d1995c..3a41445bca 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -58,7 +58,7 @@ use common::{ assets::AssetExt, cmd::ChatCommand, comp, - comp::{item::MaterialStatManifest, CharacterAbility}, + comp::{item::MaterialStatManifest, Admin, CharacterAbility, Player, Stats}, event::{EventBus, ServerEvent}, recipe::default_recipe_book, resources::TimeOfDay, @@ -68,22 +68,30 @@ use common::{ }; use common_net::{ msg::{ - ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg, WorldMapMsg, + CharacterInfo, ClientRegister, ClientType, DisconnectReason, PlayerInfo, PlayerListUpdate, + RegisterError, ServerGeneral, ServerInfo, ServerInit, ServerMsg, ServerRegisterAnswer, + WorldMapMsg, }, sync::WorldSyncExt, }; #[cfg(feature = "plugins")] use common_sys::plugin::PluginMgr; use common_sys::state::State; -use metrics::{PhysicsMetrics, StateTickMetrics, TickMetrics}; +use hashbrown::HashMap; +use metrics::{PhysicsMetrics, PlayerMetrics, StateTickMetrics, TickMetrics}; use network::{Network, Pid, ProtocolAddr}; use persistence::{ character_loader::{CharacterLoader, CharacterLoaderResponseKind}, character_updater::CharacterUpdater, }; +use plugin_api::Uid; use prometheus::Registry; use prometheus_hyper::Server as PrometheusServer; -use specs::{join::Join, Builder, Entity as EcsEntity, RunNow, SystemData, WorldExt}; +use specs::{ + join::Join, + shred::{Fetch, FetchMut}, + Builder, Entity as EcsEntity, RunNow, SystemData, WorldExt, WriteStorage, +}; use std::{ i32, ops::{Deref, DerefMut}, @@ -195,7 +203,6 @@ impl Server { state.ecs_mut().insert(sys::EntitySyncTimer::default()); state.ecs_mut().insert(sys::GeneralMsgTimer::default()); state.ecs_mut().insert(sys::PingMsgTimer::default()); - state.ecs_mut().insert(sys::RegisterMsgTimer::default()); state .ecs_mut() .insert(sys::CharacterScreenMsgTimer::default()); @@ -507,7 +514,7 @@ impl Server { // (e.g. run before controller system) //TODO: run in parallel sys::msg::general::Sys.run_now(&self.state.ecs()); - sys::msg::register::register_run(self.state_mut().ecs_mut()); + self.register_run(); sys::msg::character_screen::Sys.run_now(&self.state.ecs()); sys::msg::in_game::Sys.run_now(&self.state.ecs()); sys::msg::ping::Sys.run_now(&self.state.ecs()); @@ -711,7 +718,6 @@ impl Server { let state = self.state.ecs(); (state.read_resource::().nanos + state.read_resource::().nanos - + state.read_resource::().nanos + state.read_resource::().nanos + state.read_resource::().nanos) as i64 }; @@ -917,6 +923,139 @@ impl Server { self.state.cleanup(); } + fn handle_register_msg( + world: &specs::World, + player_list: &HashMap, + new_players: &mut Vec, + entity: specs::Entity, + client: &Client, + player_metrics: &Fetch<'_, PlayerMetrics>, + login_provider: &mut FetchMut<'_, LoginProvider>, + admins: &mut WriteStorage<'_, Admin>, + players: &mut WriteStorage<'_, Player>, + editable_settings: &Fetch<'_, EditableSettings>, + msg: ClientRegister, + ) -> Result<(), crate::error::Error> { + let plugin_mgr = world.read_resource::(); + let (username, uuid) = match login_provider.try_login( + &msg.token_or_username, + world, + &plugin_mgr, + &*editable_settings.admins, + &*editable_settings.whitelist, + &*editable_settings.banlist, + ) { + Err(err) => { + client.send(ServerRegisterAnswer::Err(err))?; + return Ok(()); + }, + Ok((username, uuid)) => (username, uuid), + }; + + let player = Player::new(username, uuid); + let is_admin = editable_settings.admins.contains(&uuid); + + if !player.is_valid() { + // Invalid player + client.send(ServerRegisterAnswer::Err(RegisterError::InvalidCharacter))?; + return Ok(()); + } + + if !players.contains(entity) { + // Add Player component to this client + let _ = players.insert(entity, player); + player_metrics.players_connected.inc(); + + // Give the Admin component to the player if their name exists in + // admin list + if is_admin { + let _ = admins.insert(entity, Admin); + } + + // Tell the client its request was successful. + client.send(ServerRegisterAnswer::Ok(()))?; + + // Send initial player list + client.send(ServerGeneral::PlayerListUpdate(PlayerListUpdate::Init( + player_list.clone(), + )))?; + + // Add to list to notify all clients of the new player + new_players.push(entity); + } + + Ok(()) + } + + pub fn register_run(&mut self) { + let world = self.state_mut().ecs_mut(); + let entities = world.entities(); + let player_metrics = world.read_resource::(); + let uids = world.read_storage::(); + let clients = world.read_storage::(); + let mut players = world.write_storage::(); + let stats = world.read_storage::(); + let mut login_provider = world.write_resource::(); + let mut admins = world.write_storage::(); + let editable_settings = world.read_resource::(); + + // Player list to send new players. + let player_list = (&uids, &players, stats.maybe(), admins.maybe()) + .join() + .map(|(uid, player, stats, admin)| { + (*uid, PlayerInfo { + is_online: true, + is_admin: admin.is_some(), + player_alias: player.alias.clone(), + character: stats.map(|stats| CharacterInfo { + name: stats.name.clone(), + }), + }) + }) + .collect::>(); + // List of new players to update player lists of all clients. + let mut new_players = Vec::new(); + + for (entity, client) in (&entities, &clients).join() { + let _ = sys::msg::try_recv_all(client, 0, |client, msg| { + Server::handle_register_msg( + &world, + &player_list, + &mut new_players, + entity, + client, + &player_metrics, + &mut login_provider, + &mut admins, + &mut players, + &editable_settings, + msg, + ) + }); + } + + // Handle new players. + // Tell all clients to add them to the player list. + for entity in new_players { + if let (Some(uid), Some(player)) = (uids.get(entity), players.get(entity)) { + let mut lazy_msg = None; + for (_, client) in (&players, &clients).join() { + if lazy_msg.is_none() { + lazy_msg = Some(client.prepare(ServerGeneral::PlayerListUpdate( + PlayerListUpdate::Add(*uid, PlayerInfo { + player_alias: player.alias.clone(), + is_online: true, + is_admin: admins.get(entity).is_some(), + character: None, // new players will be on character select. + }), + ))); + } + lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg)); + } + } + } + } + fn initialize_client( &mut self, client: crate::connection_handler::IncomingClient, @@ -1033,7 +1172,6 @@ impl Server { } else { #[cfg(feature = "plugins")] { - use common::uid::Uid; let plugin_manager = self.state.ecs().read_resource::(); let rs = plugin_manager.execute_event( self.state.ecs(), diff --git a/server/src/sys/mod.rs b/server/src/sys/mod.rs index d784ec5c18..649c52114b 100644 --- a/server/src/sys/mod.rs +++ b/server/src/sys/mod.rs @@ -19,7 +19,6 @@ use std::{ pub type EntitySyncTimer = SysTimer; pub type GeneralMsgTimer = SysTimer; pub type PingMsgTimer = SysTimer; -pub type RegisterMsgTimer = SysTimer; pub type CharacterScreenMsgTimer = SysTimer; pub type InGameMsgTimer = SysTimer; pub type SentinelTimer = SysTimer; diff --git a/server/src/sys/msg/mod.rs b/server/src/sys/msg/mod.rs index 0242d83794..e50d09ca90 100644 --- a/server/src/sys/msg/mod.rs +++ b/server/src/sys/msg/mod.rs @@ -2,14 +2,13 @@ pub mod character_screen; pub mod general; pub mod in_game; pub mod ping; -pub mod register; use crate::client::Client; use serde::de::DeserializeOwned; /// handles all send msg and calls a handle fn /// Aborts when a error occurred returns cnt of successful msg otherwise -pub(in crate::sys::msg) fn try_recv_all( +pub(crate) fn try_recv_all( client: &Client, stream_id: u8, mut f: F, diff --git a/server/src/sys/msg/register.rs b/server/src/sys/msg/register.rs deleted file mode 100644 index fc807662d6..0000000000 --- a/server/src/sys/msg/register.rs +++ /dev/null @@ -1,160 +0,0 @@ -use crate::{ - client::Client, login_provider::LoginProvider, metrics::PlayerMetrics, EditableSettings, -}; -use common::{ - comp::{Admin, Player, Stats}, - span, - uid::Uid, -}; -use common_net::msg::{ - CharacterInfo, ClientRegister, PlayerInfo, PlayerListUpdate, RegisterError, ServerGeneral, - ServerRegisterAnswer, -}; -use common_sys::plugin::PluginMgr; -use hashbrown::HashMap; -use specs::{ - shred::{Fetch, FetchMut}, - Join, World, WorldExt, WriteStorage, -}; - -#[allow(clippy::too_many_arguments)] -fn handle_register_msg( - world: &World, - player_list: &HashMap, - new_players: &mut Vec, - entity: specs::Entity, - client: &Client, - player_metrics: &Fetch<'_, PlayerMetrics>, - login_provider: &mut FetchMut<'_, LoginProvider>, - admins: &mut WriteStorage<'_, Admin>, - players: &mut WriteStorage<'_, Player>, - editable_settings: &Fetch<'_, EditableSettings>, - msg: ClientRegister, -) -> Result<(), crate::error::Error> { - let plugin_mgr = world.read_resource::(); - let (username, uuid) = match login_provider.try_login( - &msg.token_or_username, - world, - &plugin_mgr, - &*editable_settings.admins, - &*editable_settings.whitelist, - &*editable_settings.banlist, - ) { - Err(err) => { - client.send(ServerRegisterAnswer::Err(err))?; - return Ok(()); - }, - Ok((username, uuid)) => (username, uuid), - }; - - let player = Player::new(username, uuid); - let is_admin = editable_settings.admins.contains(&uuid); - - if !player.is_valid() { - // Invalid player - client.send(ServerRegisterAnswer::Err(RegisterError::InvalidCharacter))?; - return Ok(()); - } - - if !players.contains(entity) { - // Add Player component to this client - let _ = players.insert(entity, player); - player_metrics.players_connected.inc(); - - // Give the Admin component to the player if their name exists in - // admin list - if is_admin { - let _ = admins.insert(entity, Admin); - } - - // Tell the client its request was successful. - client.send(ServerRegisterAnswer::Ok(()))?; - - // Send initial player list - client.send(ServerGeneral::PlayerListUpdate(PlayerListUpdate::Init( - player_list.clone(), - )))?; - - // Add to list to notify all clients of the new player - new_players.push(entity); - } - - Ok(()) -} - -/// This system will handle new messages from clients -pub struct Sys; - -pub fn register_run(world: &mut World) { - let entities = world.entities(); - let player_metrics = world.read_resource::(); - //let mut timer = world.write_resource::>(); - let uids = world.read_storage::(); - let clients = world.read_storage::(); - let mut players = world.write_storage::(); - let stats = world.read_storage::(); - let mut login_provider = world.write_resource::(); - let mut admins = world.write_storage::(); - let editable_settings = world.read_resource::(); - - span!(_guard, "run", "msg::register::Sys::run"); - //timer.start(); - - // Player list to send new players. - let player_list = (&uids, &players, stats.maybe(), admins.maybe()) - .join() - .map(|(uid, player, stats, admin)| { - (*uid, PlayerInfo { - is_online: true, - is_admin: admin.is_some(), - player_alias: player.alias.clone(), - character: stats.map(|stats| CharacterInfo { - name: stats.name.clone(), - }), - }) - }) - .collect::>(); - // List of new players to update player lists of all clients. - let mut new_players = Vec::new(); - - for (entity, client) in (&entities, &clients).join() { - let _ = super::try_recv_all(client, 0, |client, msg| { - handle_register_msg( - &world, - &player_list, - &mut new_players, - entity, - client, - &player_metrics, - &mut login_provider, - &mut admins, - &mut players, - &editable_settings, - msg, - ) - }); - } - - // Handle new players. - // Tell all clients to add them to the player list. - for entity in new_players { - if let (Some(uid), Some(player)) = (uids.get(entity), players.get(entity)) { - let mut lazy_msg = None; - for (_, client) in (&players, &clients).join() { - if lazy_msg.is_none() { - lazy_msg = Some(client.prepare(ServerGeneral::PlayerListUpdate( - PlayerListUpdate::Add(*uid, PlayerInfo { - player_alias: player.alias.clone(), - is_online: true, - is_admin: admins.get(entity).is_some(), - character: None, // new players will be on character select. - }), - ))); - } - lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg)); - } - } - } - - //timer.end() -}