From cc6fec44d16419a3f0c28d803c39c7f54374685e Mon Sep 17 00:00:00 2001 From: lokka30 Date: Sat, 26 Oct 2024 21:44:14 +0800 Subject: [PATCH 1/5] Implement max player limit --- pumpkin/src/client/client_packet.rs | 13 +++++++++++-- pumpkin/src/server/mod.rs | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index 92199817..96dac2e4 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -164,16 +164,25 @@ impl Client { } } + // Don't allow new logons when server is full. + // TODO: If client is an operator or otherwise suitable elevated permissions, allow client to bypass this requirement. + let player_count = server.get_player_count().await; + if player_count >= BASIC_CONFIG.max_players { + log::debug!("Player (IP '{}', username '{}') tried to log in, but the server is full ({}/{} players).", &self.address.lock().await, &profile.name, player_count, BASIC_CONFIG.max_players); + self.kick("The server is currently full, please try again later") + .await; + } + // Don't allow duplicate UUIDs if let Some(online_player) = &server.get_player_by_uuid(profile.id).await { - log::debug!("Player (IP '{}', username '{}') tried to log in with the same UUID ('{}') as an online player (IP '{}', username '{}')", &self.address.lock().await.to_string(), &profile.name, &profile.id.to_string(), &online_player.client.address.lock().await.to_string(), &online_player.gameprofile.name); + log::debug!("Player (IP '{}', username '{}') tried to log in with the same UUID ('{}') as an online player (IP '{}', username '{}')", &self.address.lock().await, &profile.name, &profile.id, &online_player.client.address.lock().await, &online_player.gameprofile.name); self.kick("You are already connected to this server").await; return; } // Don't allow a duplicate username if let Some(online_player) = &server.get_player_by_name(&profile.name).await { - log::debug!("A player (IP '{}', attempted username '{}') tried to log in with the same username as an online player (UUID '{}', IP '{}', username '{}')", &self.address.lock().await.to_string(), &profile.name, &profile.id.to_string(), &online_player.client.address.lock().await.to_string(), &online_player.gameprofile.name); + log::debug!("A player (IP '{}', attempted username '{}') tried to log in with the same username as an online player (UUID '{}', IP '{}', username '{}')", &self.address.lock().await, &profile.name, &profile.id, &online_player.client.address.lock().await, &online_player.gameprofile.name); self.kick("A player with this username is already connected") .await; return; diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index 4e5feb50..bfaaf4cd 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -1,5 +1,6 @@ use connection_cache::{CachedBranding, CachedStatus}; use key_store::KeyStore; +use num_traits::ToPrimitive; use pumpkin_config::BASIC_CONFIG; use pumpkin_core::GameMode; use pumpkin_entity::EntityId; @@ -163,6 +164,21 @@ impl Server { None } + /// Get the player count sum in all worlds + pub async fn get_player_count(&self) -> u32 { + let mut count = 0; + for world in &self.worlds { + count += world + .current_players + .lock() + .await + .len() + .to_u32() + .expect("Unable to convert to u32"); + } + return count; + } + /// Generates a new entity id /// This should be global pub fn new_entity_id(&self) -> EntityId { From 93f3a058a841c92a51c7d266a81d3659530d0e22 Mon Sep 17 00:00:00 2001 From: lokka30 Date: Sat, 26 Oct 2024 21:56:15 +0800 Subject: [PATCH 2/5] Removed unnecessary `return`. --- pumpkin/src/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index bfaaf4cd..bcc6f482 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -176,7 +176,7 @@ impl Server { .to_u32() .expect("Unable to convert to u32"); } - return count; + count } /// Generates a new entity id From 9fdc526b9949e96701b88874e2b00f4ab737238e Mon Sep 17 00:00:00 2001 From: lokka30 Date: Sun, 27 Oct 2024 16:51:08 +0800 Subject: [PATCH 3/5] Moved server full check to start of `handle_login_start` Also removed unnecessary debug log. --- pumpkin/src/client/client_packet.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index 96dac2e4..6b40d1bf 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -78,6 +78,13 @@ impl Client { pub async fn handle_login_start(&self, server: &Server, login_start: SLoginStart) { log::debug!("login start"); + // Don't allow new logons when server is full. + // TODO: If client is an operator or otherwise suitable elevated permissions, allow client to bypass this requirement. + if server.get_player_count().await >= BASIC_CONFIG.max_players { + self.kick("The server is currently full, please try again later") + .await; + } + if !Self::is_valid_player_name(&login_start.name) { self.kick("Invalid characters in username").await; return; @@ -164,15 +171,6 @@ impl Client { } } - // Don't allow new logons when server is full. - // TODO: If client is an operator or otherwise suitable elevated permissions, allow client to bypass this requirement. - let player_count = server.get_player_count().await; - if player_count >= BASIC_CONFIG.max_players { - log::debug!("Player (IP '{}', username '{}') tried to log in, but the server is full ({}/{} players).", &self.address.lock().await, &profile.name, player_count, BASIC_CONFIG.max_players); - self.kick("The server is currently full, please try again later") - .await; - } - // Don't allow duplicate UUIDs if let Some(online_player) = &server.get_player_by_uuid(profile.id).await { log::debug!("Player (IP '{}', username '{}') tried to log in with the same UUID ('{}') as an online player (IP '{}', username '{}')", &self.address.lock().await, &profile.name, &profile.id, &online_player.client.address.lock().await, &online_player.gameprofile.name); From 8aba1ffed4fb2db75149ad9ad7fb78218ca2d805 Mon Sep 17 00:00:00 2001 From: lokka30 Date: Sun, 27 Oct 2024 22:29:48 +0800 Subject: [PATCH 4/5] Use instead of for max players; add disable logic --- pumpkin-config/src/lib.rs | 2 +- pumpkin/src/client/client_packet.rs | 9 +++++++-- pumpkin/src/server/mod.rs | 11 ++--------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/pumpkin-config/src/lib.rs b/pumpkin-config/src/lib.rs index b2fd20d0..3295b186 100644 --- a/pumpkin-config/src/lib.rs +++ b/pumpkin-config/src/lib.rs @@ -64,7 +64,7 @@ pub struct BasicConfiguration { /// The seed for world generation. #[serde(default = "String::new")] pub seed: String, - /// The maximum number of players allowed on the server. + /// The maximum number of players allowed on the server. Specifying `0` disables the limit. #[serde_inline_default(10000)] pub max_players: u32, /// The maximum view distance for players. diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index 6b40d1bf..8fd1ac97 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -1,4 +1,4 @@ -use num_traits::FromPrimitive; +use num_traits::{FromPrimitive, ToPrimitive}; use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_core::text::TextComponent; use pumpkin_protocol::{ @@ -79,8 +79,13 @@ impl Client { log::debug!("login start"); // Don't allow new logons when server is full. + // If max players is set to zero, then there is no max player count enforced. // TODO: If client is an operator or otherwise suitable elevated permissions, allow client to bypass this requirement. - if server.get_player_count().await >= BASIC_CONFIG.max_players { + let max_players = BASIC_CONFIG + .max_players + .to_usize() + .expect("Unable to convert to usize"); + if max_players > 0 && server.get_player_count().await >= max_players { self.kick("The server is currently full, please try again later") .await; } diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index bcc6f482..d1a4897a 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -1,6 +1,5 @@ use connection_cache::{CachedBranding, CachedStatus}; use key_store::KeyStore; -use num_traits::ToPrimitive; use pumpkin_config::BASIC_CONFIG; use pumpkin_core::GameMode; use pumpkin_entity::EntityId; @@ -165,16 +164,10 @@ impl Server { } /// Get the player count sum in all worlds - pub async fn get_player_count(&self) -> u32 { + pub async fn get_player_count(&self) -> usize { let mut count = 0; for world in &self.worlds { - count += world - .current_players - .lock() - .await - .len() - .to_u32() - .expect("Unable to convert to u32"); + count += world.current_players.lock().await.len() } count } From abbc4549fbe0f9c2addaac4e3583de956e777f6b Mon Sep 17 00:00:00 2001 From: lokka30 Date: Sun, 27 Oct 2024 23:08:36 +0800 Subject: [PATCH 5/5] Fix semicolon missing --- pumpkin/src/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index d1a4897a..ba9ad442 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -167,7 +167,7 @@ impl Server { pub async fn get_player_count(&self) -> usize { let mut count = 0; for world in &self.worlds { - count += world.current_players.lock().await.len() + count += world.current_players.lock().await.len(); } count }