diff --git a/CHANGELOG.md b/CHANGELOG.md index bad552cbf6..bc5dc7c8b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed bug where the view distance selection was not immediately applied to entity syncing when first joining a server and when changing the view distance (previously this required moving to a new chunk for the initial setting or subsequent change to apply). +- Moderators and admins are no longer blocked from logging in when there are too many players. ## [0.13.0] - 2022-07-23 diff --git a/client/examples/chat-cli/main.rs b/client/examples/chat-cli/main.rs index ee79e3bc3f..87f9113870 100644 --- a/client/examples/chat-cli/main.rs +++ b/client/examples/chat-cli/main.rs @@ -51,19 +51,20 @@ fn main() { // Create a client. let mut client = runtime - .block_on(Client::new(addr, runtime2, &mut None)) + .block_on(Client::new( + addr, + runtime2, + &mut None, + &username, + &password, + |provider| provider == "https://auth.veloren.net", + )) .expect("Failed to create client instance"); println!("Server info: {:?}", client.server_info()); println!("Players online: {:?}", client.players().collect::>()); - runtime - .block_on(client.register(username, password, |provider| { - provider == "https://auth.veloren.net" - })) - .unwrap(); - let (tx, rx) = mpsc::channel(); thread::spawn(move || { loop { diff --git a/client/src/bin/bot/main.rs b/client/src/bin/bot/main.rs index ce4bacff73..9fcdade262 100644 --- a/client/src/bin/bot/main.rs +++ b/client/src/bin/bot/main.rs @@ -13,6 +13,7 @@ mod settings; mod tui; use common::comp::body::humanoid::Body; +use common_net::msg::ServerInfo; use settings::Settings; use tui::Cmd; @@ -46,31 +47,47 @@ pub fn main() { pub struct BotClient { settings: Settings, runtime: Arc, - menu_client: Client, + server_info: ServerInfo, bot_clients: HashMap, clock: Clock, } -pub fn make_client(runtime: &Arc, server: &str) -> Client { +pub fn make_client( + runtime: &Arc, + server: &str, + server_info: &mut Option, + username: &str, + password: &str, +) -> Option { let runtime_clone = Arc::clone(runtime); let addr = ConnectionArgs::Tcp { prefer_ipv6: false, hostname: server.to_owned(), }; runtime - .block_on(Client::new(addr, runtime_clone, &mut None)) - .expect("Failed to connect to server") + .block_on(Client::new( + addr, + runtime_clone, + server_info, + username, + password, + |_| true, + )) + .ok() } impl BotClient { pub fn new(settings: Settings) -> BotClient { let runtime = Arc::new(Runtime::new().unwrap()); - let menu_client: Client = make_client(&runtime, &settings.server); + let mut server_info = None; + // Don't care if we connect, just trying to grab the server info. + let _ = make_client(&runtime, &settings.server, &mut server_info, "", ""); + let server_info = server_info.expect("Failed to connect to server."); let clock = Clock::new(Duration::from_secs_f64(1.0 / 60.0)); BotClient { settings, runtime, - menu_client, + server_info, bot_clients: HashMap::new(), clock, } @@ -106,7 +123,7 @@ impl BotClient { None => vec![prefix.to_string()], }; info!("usernames: {:?}", usernames); - if let Some(auth_addr) = self.menu_client.server_info().auth_provider.as_ref() { + if let Some(auth_addr) = self.server_info.auth_provider.as_ref() { let (scheme, authority) = auth_addr.split_once("://").expect("invalid auth url"); let scheme = scheme .parse::() @@ -156,20 +173,16 @@ impl BotClient { for cred in creds.iter() { let runtime = Arc::clone(&self.runtime); - let server = self.settings.server.clone(); + let server = &self.settings.server; + // TODO: log the clients in in parallel instead of in series let client = self .bot_clients .entry(cred.username.clone()) - .or_insert_with(|| make_client(&runtime, &server)); + .or_insert_with(|| { + make_client(&runtime, server, &mut None, &cred.username, &cred.password) + .expect("Failed to connect to server") + }); - // TODO: log the clients in in parallel instead of in series - if let Err(e) = runtime.block_on(client.register( - cred.username.clone(), - cred.password.clone(), - |_| true, - )) { - warn!("error logging in {:?}: {:?}", cred.username, e); - } let body = BotClient::create_default_body(); client.create_character( cred.username.clone(), diff --git a/client/src/bin/swarm/main.rs b/client/src/bin/swarm/main.rs index 90e345f6ad..7284ddb95b 100644 --- a/client/src/bin/swarm/main.rs +++ b/client/src/bin/swarm/main.rs @@ -108,15 +108,17 @@ fn run_client( hostname: "localhost".into(), }; let runtime_clone = Arc::clone(&runtime); - let mut client = runtime - .block_on(Client::new(addr, runtime_clone, &mut None)) - .expect("Failed to connect to the server"); - - // Login // NOTE: use a no-auth server - runtime - .block_on(client.register(username.clone(), String::new(), |_| false)) - .expect("Failed to log in"); + let mut client = runtime + .block_on(Client::new( + addr, + runtime_clone, + &mut None, + &username, + "", + |_| false, + )) + .expect("Failed to connect to the server"); let mut clock = common::clock::Clock::new(Duration::from_secs_f32(1.0 / 30.0)); diff --git a/client/src/lib.rs b/client/src/lib.rs index 1138e9ab4f..d07bd78f85 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -275,6 +275,9 @@ impl Client { runtime: Arc, // TODO: refactor to avoid needing to use this out parameter mismatched_server_info: &mut Option, + username: &str, + password: &str, + auth_trusted: impl FnMut(&str) -> bool, ) -> Result { let network = Network::new(Pid::new(), &runtime); @@ -317,15 +320,24 @@ impl Client { common::util::GIT_HASH.to_string(), common::util::GIT_DATE.to_string(), ); - - // Pass the server info back to the caller to ensure they can access it even - // if this function errors. - mem::swap(mismatched_server_info, &mut Some(server_info.clone())); } + // Pass the server info back to the caller to ensure they can access it even + // if this function errors. + mem::swap(mismatched_server_info, &mut Some(server_info.clone())); debug!("Auth Server: {:?}", server_info.auth_provider); ping_stream.send(PingMsg::Ping)?; + // Register client + Self::register( + username, + password, + auth_trusted, + &server_info, + &mut register_stream, + ) + .await?; + // Wait for initial sync let mut ping_interval = tokio::time::interval(Duration::from_secs(1)); let ( @@ -632,7 +644,7 @@ impl Client { let map_bounds = Vec2::new(sea_level, max_height); debug!("Done preparing image..."); - Ok(( + ( state, lod_base, lod_alt, @@ -644,16 +656,15 @@ impl Client { component_recipe_book, max_group_size, client_timeout, - )) + ) }, - ServerInit::TooManyPlayers => Err(Error::TooManyPlayers), - }?; + }; ping_stream.send(PingMsg::Ping)?; debug!("Initial sync done"); Ok(Self { - registered: false, + registered: true, presence: None, runtime, server_info, @@ -722,14 +733,15 @@ impl Client { } /// Request a state transition to `ClientState::Registered`. - pub async fn register( - &mut self, - username: String, - password: String, + async fn register( + username: &str, + password: &str, mut auth_trusted: impl FnMut(&str) -> bool, + server_info: &ServerInfo, + register_stream: &mut Stream, ) -> Result<(), Error> { // Authentication - let token_or_username = match &self.server_info.auth_provider { + let token_or_username = match &server_info.auth_provider { Some(addr) => { // Query whether this is a trusted auth server if auth_trusted(addr) { @@ -749,26 +761,29 @@ impl Client { }; Ok(authc::AuthClient::new(scheme, authority)? - .sign_in(&username, &password) + .sign_in(username, password) .await? .serialize()) } else { Err(Error::AuthServerNotTrusted) } }, - None => Ok(username), + None => Ok(username.to_owned()), }?; - self.send_msg_err(ClientRegister { token_or_username })?; + debug!("Registering client..."); - match self.register_stream.recv::().await? { + register_stream.send(ClientRegister { token_or_username })?; + + match register_stream.recv::().await? { Err(RegisterError::AuthError(err)) => Err(Error::AuthErr(err)), Err(RegisterError::InvalidCharacter) => Err(Error::InvalidCharacter), Err(RegisterError::NotOnWhitelist) => Err(Error::NotOnWhitelist), Err(RegisterError::Kicked(err)) => Err(Error::Kicked(err)), Err(RegisterError::Banned(reason)) => Err(Error::Banned(reason)), + Err(RegisterError::TooManyPlayers) => Err(Error::TooManyPlayers), Ok(()) => { - self.registered = true; + debug!("Client registered successfully."); Ok(()) }, } @@ -2917,6 +2932,9 @@ mod tests { let runtime = Arc::new(Runtime::new().unwrap()); let runtime2 = Arc::clone(&runtime); + let username = "Foo"; + let password = "Bar"; + let auth_server = "auth.veloren.net"; let veloren_client: Result = runtime.block_on(Client::new( ConnectionArgs::Tcp { hostname: "127.0.0.1:9000".to_owned(), @@ -2924,18 +2942,12 @@ mod tests { }, runtime2, &mut None, + username, + password, + |suggestion: &str| suggestion == auth_server, )); let _ = veloren_client.map(|mut client| { - //register - let username: String = "Foo".to_string(); - let password: String = "Bar".to_string(); - let auth_server: String = "auth.veloren.net".to_string(); - let _result: Result<(), Error> = - runtime.block_on(client.register(username, password, |suggestion: &str| { - suggestion == auth_server - })); - //clock let mut clock = Clock::new(Duration::from_secs_f64(SPT)); diff --git a/common/net/src/msg/server.rs b/common/net/src/msg/server.rs index 948f9a80a2..4280416174 100644 --- a/common/net/src/msg/server.rs +++ b/common/net/src/msg/server.rs @@ -55,7 +55,6 @@ pub struct ServerInfo { #[derive(Debug, Clone, Serialize, Deserialize)] #[allow(clippy::large_enum_variant)] pub enum ServerInit { - TooManyPlayers, GameSync { entity_package: sync::EntityPackage, time_of_day: TimeOfDay, @@ -275,6 +274,7 @@ pub enum RegisterError { Kicked(String), InvalidCharacter, NotOnWhitelist, + TooManyPlayers, //TODO: InvalidAlias, } diff --git a/common/net/src/synced_components.rs b/common/net/src/synced_components.rs index 2675eec32b..1dfdf57da7 100644 --- a/common/net/src/synced_components.rs +++ b/common/net/src/synced_components.rs @@ -42,9 +42,6 @@ macro_rules! synced_components { shockwave: Shockwave, beam_segment: BeamSegment, alignment: Alignment, - // TODO: evaluate if this is used on the client, - // and if so what it is used for - player: Player, // TODO: change this to `SyncFrom::ClientEntity` and sync the bare minimum // from other entities (e.g. just keys needed to show appearance // based on their loadout). Also, it looks like this actually has @@ -210,10 +207,6 @@ impl NetSync for Alignment { const SYNC_FROM: SyncFrom = SyncFrom::AnyEntity; } -impl NetSync for Player { - const SYNC_FROM: SyncFrom = SyncFrom::AnyEntity; -} - impl NetSync for Inventory { const SYNC_FROM: SyncFrom = SyncFrom::AnyEntity; } @@ -222,7 +215,7 @@ impl NetSync for SkillSet { const SYNC_FROM: SyncFrom = SyncFrom::AnyEntity; } -// These are synced only from the client's own entity. +// These are synced only from the client's own entity. impl NetSync for Combo { const SYNC_FROM: SyncFrom = SyncFrom::ClientEntity; diff --git a/server/src/lib.rs b/server/src/lib.rs index c3205fc944..b8185565da 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -67,7 +67,7 @@ use crate::{ presence::{Presence, RegionSubscription, RepositionOnChunkLoad}, rtsim::RtSim, state_ext::StateExt, - sys::sentinel::{DeletedEntities, TrackedStorages}, + sys::sentinel::DeletedEntities, }; use censor::Censor; #[cfg(not(feature = "worldgen"))] @@ -79,7 +79,6 @@ use common::{ cmd::ServerChatCommand, comp, event::{EventBus, ServerEvent}, - recipe::{default_component_recipe_book, default_recipe_book}, resources::{BattleMode, Time, TimeOfDay}, rtsim::RtSimEntity, slowjob::SlowJobPool, @@ -88,9 +87,7 @@ use common::{ }; use common_ecs::run_now; use common_net::{ - msg::{ - ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg, WorldMapMsg, - }, + msg::{ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerMsg}, sync::WorldSyncExt, }; use common_state::{BuildAreas, State}; @@ -103,7 +100,7 @@ use persistence::{ }; use prometheus::Registry; use prometheus_hyper::Server as PrometheusServer; -use specs::{join::Join, Builder, Entity as EcsEntity, Entity, SystemData, WorldExt}; +use specs::{join::Join, Builder, Entity as EcsEntity, Entity, WorldExt}; use std::{ i32, ops::{Deref, DerefMut}, @@ -201,7 +198,6 @@ pub struct Server { state: State, world: Arc, index: IndexOwned, - map: WorldMapMsg, connection_handler: ConnectionHandler, @@ -387,6 +383,8 @@ impl Server { pois: Vec::new(), }; + state.ecs_mut().insert(map); + #[cfg(feature = "worldgen")] let spawn_point = SpawnPoint({ let index = index.as_index_ref(); @@ -562,8 +560,6 @@ impl Server { state, world, index, - map, - connection_handler, runtime, @@ -630,9 +626,6 @@ impl Server { /// Get a reference to the server's world. pub fn world(&self) -> &World { &self.world } - /// Get a reference to the server's world map. - pub fn map(&self) -> &WorldMapMsg { &self.map } - /// Execute a single server tick, handle input and update the game state by /// the given duration. pub fn tick(&mut self, _input: Input, dt: Duration) -> Result, Error> { @@ -1029,19 +1022,7 @@ impl Server { .map(|mut t| t.maintain()); } - fn initialize_client( - &mut self, - client: connection_handler::IncomingClient, - ) -> Result, Error> { - if self.settings().max_players <= self.state.ecs().read_storage::().join().count() { - trace!( - ?client.participant, - "to many players, wont allow participant to connect" - ); - client.send(ServerInit::TooManyPlayers)?; - return Ok(None); - } - + fn initialize_client(&mut self, client: connection_handler::IncomingClient) -> Entity { let entity = self .state .ecs_mut() @@ -1053,43 +1034,7 @@ impl Server { .read_resource::() .clients_connected .inc(); - // Send client all the tracked components currently attached to its entity as - // well as synced resources (currently only `TimeOfDay`) - debug!("Starting initial sync with client."); - self.state - .ecs() - .read_storage::() - .get(entity) - .expect( - "We just created this entity with a Client component using build(), and we have \ - &mut access to the ecs so it can't have been deleted yet.", - ) - .send(ServerInit::GameSync { - // Send client their entity - entity_package: TrackedStorages::fetch(self.state.ecs()) - .create_entity_package(entity, None, None, None) - .expect( - "We just created this entity as marked() (using create_entity_synced) so \ - it definitely has a uid", - ), - time_of_day: *self.state.ecs().read_resource(), - max_group_size: self.settings().max_player_group_size, - client_timeout: self.settings().client_timeout, - world_map: self.map.clone(), - recipe_book: default_recipe_book().cloned(), - component_recipe_book: default_component_recipe_book().cloned(), - material_stats: (&*self - .state - .ecs() - .read_resource::()) - .clone(), - ability_map: (&*self - .state - .ecs() - .read_resource::()) - .clone(), - })?; - Ok(Some(entity)) + entity } /// Disconnects all clients if requested by either an admin command or @@ -1155,16 +1100,8 @@ impl Server { } while let Ok(incoming) = self.connection_handler.client_receiver.try_recv() { - match self.initialize_client(incoming) { - Ok(None) => (), - Ok(Some(entity)) => { - frontend_events.push(Event::ClientConnected { entity }); - debug!("Done initial sync with client."); - }, - Err(e) => { - debug!(?e, "failed initializing a new client"); - }, - } + let entity = self.initialize_client(incoming); + frontend_events.push(Event::ClientConnected { entity }); } } diff --git a/server/src/login_provider.rs b/server/src/login_provider.rs index 96d4d8d69f..1da5b95a18 100644 --- a/server/src/login_provider.rs +++ b/server/src/login_provider.rs @@ -97,7 +97,7 @@ impl LoginProvider { PendingLogin { pending_r } } - pub fn login( + pub(crate) fn login( &mut self, pending: &mut PendingLogin, #[cfg(feature = "plugins")] world: &EcsWorld, @@ -105,6 +105,7 @@ impl LoginProvider { admins: &HashMap, whitelist: &HashMap, banlist: &HashMap, + player_count_exceeded: bool, ) -> Option> { match pending.pending_r.try_recv() { Ok(Err(e)) => Some(Err(e)), @@ -137,6 +138,11 @@ impl LoginProvider { return Some(Err(RegisterError::NotOnWhitelist)); } + // non-admins can only join if the player count has not been exceeded. + if admin.is_none() && player_count_exceeded { + return Some(Err(RegisterError::TooManyPlayers)); + } + #[cfg(feature = "plugins")] { // Plugin player join hooks execute for all players, but are only allowed to diff --git a/server/src/sys/entity_sync.rs b/server/src/sys/entity_sync.rs index dc303e732f..8032765efa 100644 --- a/server/src/sys/entity_sync.rs +++ b/server/src/sys/entity_sync.rs @@ -6,7 +6,7 @@ use crate::{ }; use common::{ calendar::Calendar, - comp::{Collider, ForceUpdate, InventoryUpdate, Last, Ori, Pos, Vel}, + comp::{Collider, ForceUpdate, InventoryUpdate, Last, Ori, Player, Pos, Vel}, event::EventBus, outcome::Outcome, region::{Event as RegionEvent, RegionMap}, @@ -40,6 +40,7 @@ impl<'a> System<'a> for Sys { ReadStorage<'a, Vel>, ReadStorage<'a, Ori>, ReadStorage<'a, RegionSubscription>, + ReadStorage<'a, Player>, ReadStorage<'a, Presence>, ReadStorage<'a, Client>, WriteStorage<'a, Last>, @@ -70,6 +71,7 @@ impl<'a> System<'a> for Sys { velocities, orientations, subscriptions, + players, presences, clients, mut last_pos, @@ -88,7 +90,6 @@ impl<'a> System<'a> for Sys { let uids = &tracked_storages.uid; let colliders = &tracked_storages.collider; let inventories = &tracked_storages.inventory; - let players = &tracked_storages.player; let is_rider = &tracked_storages.is_rider; // To send entity updates diff --git a/server/src/sys/msg/register.rs b/server/src/sys/msg/register.rs index 8d751b094f..147d8e117d 100644 --- a/server/src/sys/msg/register.rs +++ b/server/src/sys/msg/register.rs @@ -2,17 +2,20 @@ use crate::{ client::Client, login_provider::{LoginProvider, PendingLogin}, metrics::PlayerMetrics, + sys::sentinel::TrackedStorages, EditableSettings, Settings, }; use common::{ - comp::{Admin, Player, Stats}, + comp::{self, Admin, Player, Stats}, event::{EventBus, ServerEvent}, + recipe::{default_component_recipe_book, default_recipe_book}, + resources::TimeOfDay, uid::{Uid, UidAllocator}, }; use common_ecs::{Job, Origin, Phase, System}; use common_net::msg::{ CharacterInfo, ClientRegister, DisconnectReason, PlayerInfo, PlayerListUpdate, RegisterError, - ServerGeneral, + ServerGeneral, ServerInit, WorldMapMsg, }; use hashbrown::HashMap; use plugin_api::Health; @@ -20,7 +23,7 @@ use specs::{ shred::ResourceId, storage::StorageEntry, Entities, Join, Read, ReadExpect, ReadStorage, SystemData, World, WriteExpect, WriteStorage, }; -use tracing::trace; +use tracing::{debug, trace}; #[cfg(feature = "plugins")] use {common_state::plugin::memory_manager::EcsWorld, common_state::plugin::PluginMgr}; @@ -40,6 +43,11 @@ pub struct ReadData<'a> { player_metrics: ReadExpect<'a, PlayerMetrics>, settings: ReadExpect<'a, Settings>, editable_settings: ReadExpect<'a, EditableSettings>, + time_of_day: Read<'a, TimeOfDay>, + material_stats: ReadExpect<'a, comp::item::MaterialStatManifest>, + ability_map: ReadExpect<'a, comp::item::tool::AbilityMap>, + map: ReadExpect<'a, WorldMapMsg>, + trackers: TrackedStorages<'a>, _healths: ReadStorage<'a, Health>, // used by plugin feature _plugin_mgr: ReadPlugin<'a>, // used by plugin feature _uid_allocator: Read<'a, UidAllocator>, // used by plugin feature @@ -107,6 +115,8 @@ impl<'a> System<'a> for Sys { let mut finished_pending = vec![]; let mut retries = vec![]; + let mut player_count = player_list.len(); + let max_players = read_data.settings.max_players; for (entity, client, pending) in (&read_data.entities, &read_data.clients, &mut pending_logins).join() { @@ -129,6 +139,7 @@ impl<'a> System<'a> for Sys { &*read_data.editable_settings.admins, &*read_data.editable_settings.whitelist, &*read_data.editable_settings.banlist, + player_count >= max_players, ) { None => return Ok(()), Some(r) => { @@ -190,6 +201,7 @@ impl<'a> System<'a> for Sys { if let Ok(StorageEntry::Vacant(v)) = players.entry(entity) { // Add Player component to this client, if the entity exists. v.insert(player); + player_count += 1; read_data.player_metrics.players_connected.inc(); // Give the Admin component to the player if their name exists in @@ -203,6 +215,31 @@ impl<'a> System<'a> for Sys { // Tell the client its request was successful. client.send(Ok(()))?; + // Send client all the tracked components currently attached to its entity as + // well as synced resources (currently only `TimeOfDay`) + debug!("Starting initial sync with client."); + client.send(ServerInit::GameSync { + // Send client their entity + entity_package: + read_data.trackers + .create_entity_package(entity, None, None, None) + // NOTE: We are apparently okay with crashing if a uid is removed from + // a non-logged-in player without removing the whole thing. + .expect( + "We created this entity as marked() (using create_entity_synced) so \ + it definitely has a uid", + ), + time_of_day: *read_data.time_of_day, + max_group_size: read_data.settings.max_player_group_size, + client_timeout: read_data.settings.client_timeout, + world_map: (&*read_data.map).clone(), + recipe_book: default_recipe_book().cloned(), + component_recipe_book: default_component_recipe_book().cloned(), + material_stats: (&*read_data.material_stats).clone(), + ability_map: (&*read_data.ability_map).clone(), + })?; + debug!("Done initial sync with client."); + // Send initial player list client.send(ServerGeneral::PlayerListUpdate(PlayerListUpdate::Init( player_list.clone(), diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 5d950626d1..a14c97dd06 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -1278,7 +1278,6 @@ impl Hud { let bodies = ecs.read_storage::(); let items = ecs.read_storage::(); let inventories = ecs.read_storage::(); - let players = ecs.read_storage::(); let msm = ecs.read_resource::(); let entities = ecs.entities(); let me = info.viewpoint_entity; @@ -1978,7 +1977,6 @@ impl Hud { &mut hp_floater_lists, &uids, &inventories, - players.maybe(), poises.maybe(), (alignments.maybe(), is_mount.maybe()), ) @@ -2002,7 +2000,6 @@ impl Hud { hpfl, uid, inventory, - player, poise, (alignment, is_mount), )| { @@ -2013,7 +2010,8 @@ impl Hud { // TODO: once the site2 rework lands and merchants have dedicated stalls or // buildings, they no longer need to be emphasized via the higher overhead // text radius relative to other NPCs - let is_merchant = stats.name == "Merchant" && player.is_none(); + let is_merchant = + stats.name == "Merchant" && client.player_list().get(uid).is_none(); let dist_sqr = pos.distance_squared(player_pos); // Determine whether to display nametag and healthbar based on whether the // entity has been damaged, is targeted/selected, or is in your group diff --git a/voxygen/src/menu/main/client_init.rs b/voxygen/src/menu/main/client_init.rs index 5cc0b5b791..cf5ab2daf2 100644 --- a/voxygen/src/menu/main/client_init.rs +++ b/voxygen/src/menu/main/client_init.rs @@ -77,17 +77,13 @@ impl ClientInit { connection_args.clone(), Arc::clone(&runtime2), &mut mismatched_server_info, + &username, + &password, + trust_fn, ) .await { - Ok(mut client) => { - if let Err(e) = client.register(username, password, trust_fn).await { - last_err = Some(Error::ClientError { - error: e, - mismatched_server_info: None, - }); - break 'tries; - } + Ok(client) => { let _ = tx.send(Msg::Done(Ok(client))); tokio::task::block_in_place(move || drop(runtime2)); return;