diff --git a/Cargo.lock b/Cargo.lock index c7f798fb2..4f66bfda4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2031,6 +2031,7 @@ dependencies = [ "log", "num-derive", "num-traits", + "pumpkin-config", "pumpkin-core", "pumpkin-macros", "pumpkin-world", diff --git a/pumpkin-config/src/compression.rs b/pumpkin-config/src/compression.rs index 544c8d31d..9bdd733d4 100644 --- a/pumpkin-config/src/compression.rs +++ b/pumpkin-config/src/compression.rs @@ -1,24 +1,39 @@ use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize)] -// Packet compression +/// Packet compression pub struct CompressionConfig { /// Is compression enabled ? pub enabled: bool, + #[serde(flatten)] + pub compression_info: CompressionInfo, +} + +#[derive(Deserialize, Serialize, Clone)] +/// We have this in a Seperate struct so we can use it outside of the Config +pub struct CompressionInfo { /// The compression threshold used when compression is enabled - pub compression_threshold: u32, + pub threshold: u32, /// A value between 0..9 /// 1 = Optimize for the best speed of encoding. /// 9 = Optimize for the size of data being encoded. - pub compression_level: u32, + pub level: u32, +} + +impl Default for CompressionInfo { + fn default() -> Self { + Self { + threshold: 256, + level: 4, + } + } } impl Default for CompressionConfig { fn default() -> Self { Self { enabled: true, - compression_threshold: 256, - compression_level: 4, + compression_info: Default::default(), } } } diff --git a/pumpkin-config/src/lib.rs b/pumpkin-config/src/lib.rs index f24ca2810..0679bf5ed 100644 --- a/pumpkin-config/src/lib.rs +++ b/pumpkin-config/src/lib.rs @@ -20,7 +20,7 @@ pub use pvp::PVPConfig; pub use rcon::RCONConfig; mod commands; -mod compression; +pub mod compression; mod pvp; mod rcon; diff --git a/pumpkin-protocol/Cargo.toml b/pumpkin-protocol/Cargo.toml index 3ae52b6eb..956c7021c 100644 --- a/pumpkin-protocol/Cargo.toml +++ b/pumpkin-protocol/Cargo.toml @@ -4,6 +4,7 @@ version.workspace = true edition.workspace = true [dependencies] +pumpkin-config = { path = "../pumpkin-config" } pumpkin-macros = { path = "../pumpkin-macros" } pumpkin-world = { path = "../pumpkin-world" } pumpkin-core = { path = "../pumpkin-core" } diff --git a/pumpkin-protocol/src/packet_decoder.rs b/pumpkin-protocol/src/packet_decoder.rs index b001cea15..f3aa9e41f 100644 --- a/pumpkin-protocol/src/packet_decoder.rs +++ b/pumpkin-protocol/src/packet_decoder.rs @@ -19,7 +19,7 @@ type Cipher = cfb8::Decryptor; pub struct PacketDecoder { buf: BytesMut, decompress_buf: BytesMut, - compression: Option, + compression: bool, cipher: Option, } @@ -45,7 +45,7 @@ impl PacketDecoder { let packet_len_len = VarInt(packet_len).written_size(); let mut data; - if self.compression.is_some() { + if self.compression { r = &r[..packet_len as usize]; let data_len = VarInt::decode(&mut r).map_err(|_| PacketError::TooLong)?.0; @@ -96,19 +96,26 @@ impl PacketDecoder { })) } - pub fn enable_encryption(&mut self, key: &[u8; 16]) { - assert!(self.cipher.is_none(), "encryption is already enabled"); + pub fn set_encryption(&mut self, key: Option<&[u8; 16]>) { + if let Some(key) = key { + assert!(self.cipher.is_none(), "encryption is already enabled"); - let mut cipher = Cipher::new_from_slices(key, key).expect("invalid key"); + let mut cipher = Cipher::new_from_slices(key, key).expect("invalid key"); - // Don't forget to decrypt the data we already have. - Self::decrypt_bytes(&mut cipher, &mut self.buf); + // Don't forget to decrypt the data we already have. - self.cipher = Some(cipher); + Self::decrypt_bytes(&mut cipher, &mut self.buf); + + self.cipher = Some(cipher); + } else { + assert!(self.cipher.is_some(), "encryption is already disabled"); + + self.cipher = None; + } } - /// Enables ZLib Deompression - pub fn set_compression(&mut self, compression: Option) { + /// Sets ZLib Deompression + pub fn set_compression(&mut self, compression: bool) { self.compression = compression; } diff --git a/pumpkin-protocol/src/packet_encoder.rs b/pumpkin-protocol/src/packet_encoder.rs index 55c4da7cc..947fdf81e 100644 --- a/pumpkin-protocol/src/packet_encoder.rs +++ b/pumpkin-protocol/src/packet_encoder.rs @@ -2,6 +2,7 @@ use std::io::Write; use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit}; use bytes::{BufMut, BytesMut}; +use pumpkin_config::compression::CompressionInfo; use std::io::Read; @@ -19,7 +20,7 @@ type Cipher = cfb8::Encryptor; pub struct PacketEncoder { buf: BytesMut, compress_buf: Vec, - compression: Option<(u32, u32)>, + compression: Option, cipher: Option, } @@ -40,10 +41,10 @@ impl PacketEncoder { let data_len = self.buf.len() - start_len; - if let Some((threshold, compression_level)) = self.compression { - if data_len > threshold as usize { + if let Some(compression) = &self.compression { + if data_len > compression.threshold as usize { let mut z = - ZlibEncoder::new(&self.buf[start_len..], Compression::new(compression_level)); + ZlibEncoder::new(&self.buf[start_len..], Compression::new(compression.level)); self.compress_buf.clear(); @@ -117,13 +118,20 @@ impl PacketEncoder { Ok(()) } - pub fn enable_encryption(&mut self, key: &[u8; 16]) { - assert!(self.cipher.is_none(), "encryption is already enabled"); - self.cipher = Some(Cipher::new_from_slices(key, key).expect("invalid key")); + pub fn set_encryption(&mut self, key: Option<&[u8; 16]>) { + if let Some(key) = key { + assert!(self.cipher.is_none(), "encryption is already enabled"); + + self.cipher = Some(Cipher::new_from_slices(key, key).expect("invalid key")); + } else { + assert!(self.cipher.is_some(), "encryption is disabled"); + + self.cipher = None; + } } /// Enables ZLib Compression - pub fn set_compression(&mut self, compression: Option<(u32, u32)>) { + pub fn set_compression(&mut self, compression: Option) { self.compression = compression; } diff --git a/pumpkin-world/src/block/block_id.rs b/pumpkin-world/src/block/block_id.rs index 80380842c..747daff2a 100644 --- a/pumpkin-world/src/block/block_id.rs +++ b/pumpkin-world/src/block/block_id.rs @@ -26,10 +26,9 @@ impl BlockId { .iter(); let block_state = match properties { - Some(properties) => match block_states.find(|state| &state.properties == properties) { - Some(state) => state, - None => return Err(WorldError::BlockStateIdNotFound), - }, + Some(properties) => block_states + .find(|state| &state.properties == properties) + .ok_or_else(|| WorldError::BlockStateIdNotFound)?, None => block_states .find(|state| state.is_default) .expect("Every Block should have at least 1 default state"), diff --git a/pumpkin-world/src/level.rs b/pumpkin-world/src/level.rs index d97ebe523..28c991124 100644 --- a/pumpkin-world/src/level.rs +++ b/pumpkin-world/src/level.rs @@ -135,6 +135,8 @@ impl Level { } } + pub fn get_block() {} + /// Reads/Generates many chunks in a world /// MUST be called from a tokio runtime thread /// @@ -147,7 +149,6 @@ impl Level { ) { chunks.into_par_iter().for_each(|at| { if is_alive { - dbg!("a"); return; } let mut loaded_chunks = self.loaded_chunks.lock(); @@ -235,29 +236,21 @@ impl Level { // Read the file using the offset and size let mut file_buf = { - let seek_result = region_file.seek(std::io::SeekFrom::Start(offset)); - if seek_result.is_err() { - return Err(WorldError::RegionIsInvalid); - } + region_file + .seek(std::io::SeekFrom::Start(offset)) + .map_err(|_| WorldError::RegionIsInvalid)?; let mut out = vec![0; size]; - let read_result = region_file.read_exact(&mut out); - if read_result.is_err() { - return Err(WorldError::RegionIsInvalid); - } + region_file + .read_exact(&mut out) + .map_err(|_| WorldError::RegionIsInvalid)?; out }; // TODO: check checksum to make sure chunk is not corrupted let header = file_buf.drain(0..5).collect_vec(); - let compression = match Compression::from_byte(header[4]) { - Some(c) => c, - None => { - return Err(WorldError::Compression( - CompressionError::UnknownCompression, - )) - } - }; + let compression = Compression::from_byte(header[4]) + .ok_or_else(|| WorldError::Compression(CompressionError::UnknownCompression))?; let size = u32::from_be_bytes(header[..4].try_into().unwrap()); @@ -277,23 +270,15 @@ impl Level { Compression::Gzip => { let mut z = GzDecoder::new(&compressed_data[..]); let mut chunk_data = Vec::with_capacity(compressed_data.len()); - match z.read_to_end(&mut chunk_data) { - Ok(_) => {} - Err(e) => { - return Err(CompressionError::GZipError(e)); - } - } + z.read_to_end(&mut chunk_data) + .map_err(CompressionError::GZipError)?; Ok(chunk_data) } Compression::Zlib => { let mut z = ZlibDecoder::new(&compressed_data[..]); let mut chunk_data = Vec::with_capacity(compressed_data.len()); - match z.read_to_end(&mut chunk_data) { - Ok(_) => {} - Err(e) => { - return Err(CompressionError::ZlibError(e)); - } - } + z.read_to_end(&mut chunk_data) + .map_err(CompressionError::ZlibError)?; Ok(chunk_data) } Compression::None => Ok(compressed_data), diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index a38b4059c..bcdb541dd 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -107,7 +107,7 @@ impl Client { ) { let shared_secret = server.decrypt(&encryption_response.shared_secret).unwrap(); - self.enable_encryption(&shared_secret) + self.set_encryption(Some(&shared_secret)) .unwrap_or_else(|e| self.kick(&e.to_string())); let mut gameprofile = self.gameprofile.lock(); @@ -115,6 +115,7 @@ impl Client { if BASIC_CONFIG.online_mode { let hash = server.digest_secret(&shared_secret); let ip = self.address.lock().ip(); + match authentication::authenticate( &gameprofile.as_ref().unwrap().name, &hash, @@ -123,15 +124,15 @@ impl Client { ) .await { - Ok(p) => { + Ok(profile) => { // Check if player should join - if let Some(p) = &p.profile_actions { + if let Some(actions) = &profile.profile_actions { if !ADVANCED_CONFIG .authentication .player_profile .allow_banned_players { - if !p.is_empty() { + if !actions.is_empty() { self.kick("Your account can't join"); } } else { @@ -140,28 +141,27 @@ impl Client { .player_profile .allowed_actions { - if !p.contains(allowed) { + if !actions.contains(allowed) { self.kick("Your account can't join"); } } } } - *gameprofile = Some(p); + *gameprofile = Some(profile); } Err(e) => self.kick(&e.to_string()), } } for property in &gameprofile.as_ref().unwrap().properties { - // TODO: use this (this was the todo here before, ill add it again cuz its prob here for a reason) - let _ = unpack_textures(property, &ADVANCED_CONFIG.authentication.textures); + unpack_textures(property, &ADVANCED_CONFIG.authentication.textures) + .unwrap_or_else(|e| self.kick(&e.to_string())); } // enable compression if ADVANCED_CONFIG.packet_compression.enabled { - let threshold = ADVANCED_CONFIG.packet_compression.compression_threshold; - let level = ADVANCED_CONFIG.packet_compression.compression_level; - self.send_packet(&CSetCompression::new(threshold.into())); - self.set_compression(Some((threshold, level))); + let compression = ADVANCED_CONFIG.packet_compression.compression_info.clone(); + self.send_packet(&CSetCompression::new(compression.threshold.into())); + self.set_compression(Some(compression)); } if let Some(profile) = gameprofile.as_ref() { diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 7acd396bd..ca744d1b5 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -16,6 +16,7 @@ use authentication::GameProfile; use crossbeam::atomic::AtomicCell; use mio::{event::Event, net::TcpStream, Token}; use parking_lot::Mutex; +use pumpkin_config::compression::CompressionInfo; use pumpkin_protocol::{ bytebuf::{packet_id::Packet, DeserializerError}, client::{config::CConfigDisconnect, login::CLoginDisconnect}, @@ -151,24 +152,29 @@ impl Client { client_packets_queue.push(packet); } - /// Enables encryption - pub fn enable_encryption( + /// Sets the Packet encryption + pub fn set_encryption( &self, - shared_secret: &[u8], // decrypted + shared_secret: Option<&[u8]>, // decrypted ) -> Result<(), EncryptionError> { - self.encryption - .store(true, std::sync::atomic::Ordering::Relaxed); - let crypt_key: [u8; 16] = shared_secret - .try_into() - .map_err(|_| EncryptionError::SharedWrongLength)?; - self.dec.lock().enable_encryption(&crypt_key); - self.enc.lock().enable_encryption(&crypt_key); + if let Some(shared_secret) = shared_secret { + self.encryption + .store(true, std::sync::atomic::Ordering::Relaxed); + let crypt_key: [u8; 16] = shared_secret + .try_into() + .map_err(|_| EncryptionError::SharedWrongLength)?; + self.dec.lock().set_encryption(Some(&crypt_key)); + self.enc.lock().set_encryption(Some(&crypt_key)); + } else { + self.dec.lock().set_encryption(None); + self.enc.lock().set_encryption(None); + } Ok(()) } - /// Compression threshold, Compression level - pub fn set_compression(&self, compression: Option<(u32, u32)>) { - self.dec.lock().set_compression(compression.map(|v| v.0)); + /// Sets the Packet compression + pub fn set_compression(&self, compression: Option) { + self.dec.lock().set_compression(compression.is_some()); self.enc.lock().set_compression(compression); } @@ -200,14 +206,11 @@ impl Client { /// Processes all packets send by the client pub async fn process_packets(&self, server: &Arc) { while let Some(mut packet) = self.client_packets_queue.lock().pop() { - match self.handle_packet(server, &mut packet).await { - Ok(_) => {} - Err(e) => { - let text = format!("Error while reading incoming packet {}", e); - log::error!("{}", text); - self.kick(&text) - } - }; + let _ = self.handle_packet(server, &mut packet).await.map_err(|e| { + let text = format!("Error while reading incoming packet {}", e); + log::error!("{}", text); + self.kick(&text) + }); } } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 759d4cb79..420d3589b 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -131,7 +131,7 @@ impl Player { self.kick(TextComponent::text("Invalid movement")); return; } - if !position_rotation.yaw.is_finite() || !position_rotation.pitch.is_finite() { + if position_rotation.yaw.is_infinite() || position_rotation.pitch.is_infinite() { self.kick(TextComponent::text("Invalid rotation")); return; } diff --git a/pumpkin/src/rcon/mod.rs b/pumpkin/src/rcon/mod.rs index a2cf8dfc2..af5944e03 100644 --- a/pumpkin/src/rcon/mod.rs +++ b/pumpkin/src/rcon/mod.rs @@ -140,13 +140,10 @@ impl RCONClient { } } // If we get a close here, we might have a reply, which we still want to write. - match self.poll(server, password).await { - Ok(()) => {} - Err(e) => { - log::error!("rcon error: {e}"); - self.closed = true; - } - } + let _ = self.poll(server, password).await.map_err(|e| { + log::error!("rcon error: {e}"); + self.closed = true; + }); } self.closed } diff --git a/pumpkin/src/server/connection_cache.rs b/pumpkin/src/server/connection_cache.rs index 6fdd618dd..58181c214 100644 --- a/pumpkin/src/server/connection_cache.rs +++ b/pumpkin/src/server/connection_cache.rs @@ -58,7 +58,7 @@ impl CachedStatus { } pub fn build_response(config: &BasicConfiguration) -> StatusResponse { - let icon_path = concat!(env!("CARGO_MANIFEST_DIR"), "/icon.png"); + let icon_path = "/icon.png"; let icon = if Path::new(icon_path).exists() { Some(Self::load_icon(icon_path)) } else { diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index b34d756c9..4f9ada322 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -103,11 +103,11 @@ impl Server { }; // Basically the default world // TODO: select default from config - let world = self.worlds[0].clone(); + let world = &self.worlds[0]; let player = Arc::new(Player::new(client, world.clone(), entity_id, gamemode)); world.add_player(token, player.clone()); - (player, world) + (player, world.clone()) } pub fn try_get_container(