From c36b6d3464ea594d4752e1bd236bb7198362bdd1 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Wed, 28 Aug 2024 18:52:30 +0200 Subject: [PATCH] Less unwraps --- pumpkin/src/client/client_packet.rs | 2 + pumpkin/src/client/player_packet.rs | 288 ++++++++++++++++------------ pumpkin/src/commands/arg_player.rs | 14 +- pumpkin/src/entity/player.rs | 21 +- pumpkin/src/server.rs | 10 +- 5 files changed, 194 insertions(+), 141 deletions(-) diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index 7ba6cfb62..7ac629f5d 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -31,6 +31,8 @@ use super::{ /// Processes incoming Packets from the Client to the Server /// Implements the `Client` Packets +/// NEVER TRUST THE CLIENT. HANDLE EVERY ERROR, UNWRAP/EXPECT +/// TODO: REMOVE ALL UNWRAPS impl Client { pub fn handle_handshake(&mut self, _server: &mut Server, handshake: SHandShake) { dbg!("handshake"); diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 13b077af0..64bf0d5f2 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -35,6 +35,7 @@ fn modulus(a: f32, b: f32) -> f32 { } /// Handles all Play Packets send by a real Player +/// NEVER TRUST THE CLIENT. HANDLE EVERY ERROR, UNWRAP/EXPECT ARE FORBIDDEN impl Player { pub fn handle_confirm_teleport( &mut self, @@ -205,15 +206,22 @@ impl Player { } pub fn handle_swing_arm(&mut self, server: &mut Server, swing_arm: SSwingArm) { - let animation = match Hand::from_i32(swing_arm.hand.0).unwrap() { - Hand::Main => Animation::SwingMainArm, - Hand::Off => Animation::SwingOffhand, + match Hand::from_i32(swing_arm.hand.0) { + Some(hand) => { + let animation = match hand { + Hand::Main => Animation::SwingMainArm, + Hand::Off => Animation::SwingOffhand, + }; + let id = self.entity_id(); + server.broadcast_packet_except( + &[&self.client.token], + &CEntityAnimation::new(id.into(), animation as u8), + ) + } + None => { + self.kick(TextComponent::text("Invalid hand")); + } }; - let id = self.entity_id(); - server.broadcast_packet_except( - &[&self.client.token], - &CEntityAnimation::new(id.into(), animation as u8), - ) } pub fn handle_chat_message(&mut self, server: &mut Server, chat_message: SChatMessage) { @@ -226,7 +234,7 @@ impl Player { } // TODO: filter message & validation - let gameprofile = self.client.gameprofile.as_ref().unwrap(); + let gameprofile = &self.gameprofile; server.broadcast_packet( self, @@ -262,123 +270,144 @@ impl Player { _server: &mut Server, client_information: SClientInformationPlay, ) { - self.client.config = Some(PlayerConfig { - locale: client_information.locale, - view_distance: client_information.view_distance, - chat_mode: ChatMode::from_i32(client_information.chat_mode.into()).unwrap(), - chat_colors: client_information.chat_colors, - skin_parts: client_information.skin_parts, - main_hand: Hand::from_i32(client_information.main_hand.into()).unwrap(), - text_filtering: client_information.text_filtering, - server_listing: client_information.server_listing, - }); + if let (Some(main_hand), Some(chat_mode)) = ( + Hand::from_i32(client_information.main_hand.into()), + ChatMode::from_i32(client_information.chat_mode.into()), + ) { + self.client.config = Some(PlayerConfig { + locale: client_information.locale, + view_distance: client_information.view_distance, + chat_mode, + chat_colors: client_information.chat_colors, + skin_parts: client_information.skin_parts, + main_hand, + text_filtering: client_information.text_filtering, + server_listing: client_information.server_listing, + }); + } else { + self.kick(TextComponent::text("Invalid hand or chat type")) + } } pub fn handle_interact(&mut self, server: &mut Server, interact: SInteract) { - let action = ActionType::from_i32(interact.typ.0).unwrap(); - if action == ActionType::Attack { - let entity_id = interact.entity_id; - // TODO: do validation and stuff - let config = &server.advanced_config.pvp; - if config.enabled { - let attacked_player = server.get_by_entityid(self, entity_id.0 as EntityId); - self.sneaking = interact.sneaking; - if let Some(mut player) = attacked_player { - let token = player.client.token.clone(); - let velo = player.velocity; - if config.protect_creative && player.gamemode == GameMode::Creative { - return; - } - if config.knockback { - let yaw = self.entity.yaw; - let strength = 1.0; - player.knockback( - strength * 0.5, - (yaw * (PI / 180.0)).sin() as f64, - -(yaw * (PI / 180.0)).cos() as f64, - ); - let packet = &CEntityVelocity::new( - &entity_id, - player.velocity.x as f32, - player.velocity.y as f32, - player.velocity.z as f32, - ); - self.velocity = self.velocity.multiply(0.6, 1.0, 0.6); - - player.velocity = velo; - player.client.send_packet(packet); - } - if config.hurt_animation { - // TODO - // thats how we prevent borrow errors :c - let packet = &CHurtAnimation::new(&entity_id, self.entity.yaw); - self.client.send_packet(packet); - player.client.send_packet(packet); - server.broadcast_packet_except( - &[self.client.token.as_ref(), token.as_ref()], - &CHurtAnimation::new(&entity_id, 10.0), - ) + match ActionType::from_i32(interact.typ.0) { + Some(action) => match action { + ActionType::Attack => { + let entity_id = interact.entity_id; + // TODO: do validation and stuff + let config = &server.advanced_config.pvp; + if config.enabled { + let attacked_player = server.get_by_entityid(self, entity_id.0 as EntityId); + self.sneaking = interact.sneaking; + if let Some(mut player) = attacked_player { + let token = player.client.token.clone(); + let velo = player.velocity; + if config.protect_creative && player.gamemode == GameMode::Creative { + return; + } + if config.knockback { + let yaw = self.entity.yaw; + let strength = 1.0; + player.knockback( + strength * 0.5, + (yaw * (PI / 180.0)).sin() as f64, + -(yaw * (PI / 180.0)).cos() as f64, + ); + let packet = &CEntityVelocity::new( + &entity_id, + player.velocity.x as f32, + player.velocity.y as f32, + player.velocity.z as f32, + ); + self.velocity = self.velocity.multiply(0.6, 1.0, 0.6); + + player.velocity = velo; + player.client.send_packet(packet); + } + if config.hurt_animation { + // TODO + // thats how we prevent borrow errors :c + let packet = &CHurtAnimation::new(&entity_id, self.entity.yaw); + self.client.send_packet(packet); + player.client.send_packet(packet); + server.broadcast_packet_except( + &[self.client.token.as_ref(), token.as_ref()], + &CHurtAnimation::new(&entity_id, 10.0), + ) + } + if config.swing {} + } else { + self.kick(TextComponent::text("Interacted with invalid entity id")) + } } - if config.swing {} - } else { - self.kick(TextComponent::text("Interacted with invalid entity id")) } - } + ActionType::Interact => { + dbg!("todo"); + } + ActionType::InteractAt => { + dbg!("todo"); + } + }, + None => self.kick(TextComponent::text("Invalid action type")), } } pub fn handle_player_action(&mut self, server: &mut Server, player_action: SPlayerAction) { - match Status::from_i32(player_action.status.0).unwrap() { - Status::StartedDigging => { - if !self.can_interact_with_block_at(&player_action.location, 1.0) { - // TODO: maybe log? - return; + match Status::from_i32(player_action.status.0) { + Some(status) => match status { + Status::StartedDigging => { + if !self.can_interact_with_block_at(&player_action.location, 1.0) { + // TODO: maybe log? + return; + } + // TODO: do validation + // TODO: Config + if self.gamemode == GameMode::Creative { + let location = player_action.location; + // Block break & block break sound + // TODO: currently this is always dirt replace it + server + .broadcast_packet(self, &CWorldEvent::new(2001, &location, 11, false)); + // AIR + server.broadcast_packet(self, &CBlockUpdate::new(&location, 0.into())); + } } - // TODO: do validation - // TODO: Config - if self.gamemode == GameMode::Creative { + Status::CancelledDigging => { + if !self.can_interact_with_block_at(&player_action.location, 1.0) { + // TODO: maybe log? + return; + } + self.current_block_destroy_stage = 0; + } + Status::FinishedDigging => { + // TODO: do validation let location = player_action.location; + if !self.can_interact_with_block_at(&location, 1.0) { + // TODO: maybe log? + return; + } // Block break & block break sound // TODO: currently this is always dirt replace it server.broadcast_packet(self, &CWorldEvent::new(2001, &location, 11, false)); // AIR server.broadcast_packet(self, &CBlockUpdate::new(&location, 0.into())); + // TODO: Send this every tick + self.client + .send_packet(&CAcknowledgeBlockChange::new(player_action.sequence)); } - } - Status::CancelledDigging => { - if !self.can_interact_with_block_at(&player_action.location, 1.0) { - // TODO: maybe log? - return; + Status::DropItemStack => { + dbg!("todo"); } - self.current_block_destroy_stage = 0; - } - Status::FinishedDigging => { - // TODO: do validation - let location = player_action.location; - if !self.can_interact_with_block_at(&location, 1.0) { - // TODO: maybe log? - return; + Status::DropItem => { + dbg!("todo"); } - // Block break & block break sound - // TODO: currently this is always dirt replace it - server.broadcast_packet(self, &CWorldEvent::new(2001, &location, 11, false)); - // AIR - server.broadcast_packet(self, &CBlockUpdate::new(&location, 0.into())); - // TODO: Send this every tick - self.client - .send_packet(&CAcknowledgeBlockChange::new(player_action.sequence)); - } - Status::DropItemStack => { - dbg!("todo"); - } - Status::DropItem => { - dbg!("todo"); - } - Status::ShootArrowOrFinishEating => { - dbg!("todo"); - } - Status::SwapItem => { - dbg!("todo"); - } + Status::ShootArrowOrFinishEating => { + dbg!("todo"); + } + Status::SwapItem => { + dbg!("todo"); + } + }, + None => self.kick(TextComponent::text("Invalid status")), } } @@ -395,27 +424,32 @@ impl Player { return; } - let face = BlockFace::from_i32(use_item_on.face.0).unwrap(); - if let Some(item) = self.inventory.held_item() { - let minecraft_id = - global_registry::find_minecraft_id(global_registry::ITEM_REGISTRY, item.item_id) - .expect("All item ids are in the global registry"); - if let Ok(block_state_id) = BlockId::new(minecraft_id, None) { - server.broadcast_packet( - self, - &CBlockUpdate::new(&location, block_state_id.get_id_mojang_repr().into()), - ); - server.broadcast_packet( - self, - &CBlockUpdate::new( - &WorldPosition(location.0 + face.to_offset()), - block_state_id.get_id_mojang_repr().into(), - ), - ); + if let Some(face) = BlockFace::from_i32(use_item_on.face.0) { + if let Some(item) = self.inventory.held_item() { + let minecraft_id = global_registry::find_minecraft_id( + global_registry::ITEM_REGISTRY, + item.item_id, + ) + .expect("All item ids are in the global registry"); + if let Ok(block_state_id) = BlockId::new(minecraft_id, None) { + server.broadcast_packet( + self, + &CBlockUpdate::new(&location, block_state_id.get_id_mojang_repr().into()), + ); + server.broadcast_packet( + self, + &CBlockUpdate::new( + &WorldPosition(location.0 + face.to_offset()), + block_state_id.get_id_mojang_repr().into(), + ), + ); + } } + self.client + .send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence)); + } else { + self.kick(TextComponent::text("Invalid block face")) } - self.client - .send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence)); } pub fn handle_use_item(&mut self, _server: &mut Server, _use_item: SUseItem) { diff --git a/pumpkin/src/commands/arg_player.rs b/pumpkin/src/commands/arg_player.rs index 6a52c5510..e3506b4cb 100644 --- a/pumpkin/src/commands/arg_player.rs +++ b/pumpkin/src/commands/arg_player.rs @@ -16,10 +16,9 @@ pub fn consume_arg_player(src: &CommandSender, args: &mut RawArgs) -> Option { // todo: implement any other player than sender if let Player(player) = src { - if let Some(profile) = &player.client.gameprofile { - if profile.name == s { - return Some(s.into()); - }; + let profile = &player.gameprofile; + if profile.name == s { + return Some(s.into()); }; }; None @@ -46,10 +45,9 @@ pub fn parse_arg_player<'a>( _ => { // todo: implement any other player than sender if let Player(player) = src { - if let Some(profile) = &player.client.gameprofile { - if profile.name == s { - return Ok(player); - }; + let profile = &player.gameprofile; + if profile.name == s { + return Ok(player); }; }; Err(InvalidConsumptionError(Some(s.into()))) diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index bf2d1f6ba..de433a9bd 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -23,7 +23,11 @@ use pumpkin_protocol::{ use pumpkin_world::vector3::Vector3; use serde::{Deserialize, Serialize}; -use crate::{client::Client, server::Server, util::boundingbox::BoundingBox}; +use crate::{ + client::{authentication::GameProfile, Client}, + server::Server, + util::boundingbox::BoundingBox, +}; pub struct PlayerAbilities { pub invulnerable: bool, @@ -48,6 +52,7 @@ impl Default for PlayerAbilities { } pub struct Player { + pub gameprofile: GameProfile, pub client: Client, pub entity: Entity, // current gamemode @@ -79,7 +84,21 @@ pub struct Player { impl Player { pub fn new(client: Client, entity_id: EntityId, gamemode: GameMode) -> Self { + let gameprofile = match client.gameprofile.clone() { + Some(profile) => profile, + None => { + log::error!("No gameprofile?. Impossible"); + GameProfile { + id: uuid::Uuid::new_v4(), + name: "".to_string(), + properties: vec![], + profile_actions: None, + } + } + }; + Self { + gameprofile, client, entity: Entity::new(entity_id, EntityType::Player, 1.62), on_ground: false, diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index f8e329bba..c673cbc9c 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -143,7 +143,7 @@ impl Server { // despawn the player // todo: put this into the entitiy struct let id = player.entity_id(); - let uuid = player.client.gameprofile.as_ref().unwrap().id; + let uuid = player.gameprofile.id; self.broadcast_packet_except( &[&player.client.token], &CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]), @@ -194,7 +194,7 @@ impl Server { let yaw = 10.0; let pitch = 10.0; player.teleport(x, y, z, 10.0, 10.0); - let gameprofile = player.client.gameprofile.as_ref().unwrap(); + let gameprofile = &player.gameprofile; // first send info update to our new player, So he can see his Skin // also send his info to everyone else self.broadcast_packet( @@ -222,7 +222,7 @@ impl Server { .filter(|c| c.0 != &player.client.token) { let playerr = playerr.as_ref().lock().unwrap(); - let gameprofile = &playerr.client.gameprofile.as_ref().unwrap(); + let gameprofile = &playerr.gameprofile; entries.push(pumpkin_protocol::client::play::Player { uuid: gameprofile.id, actions: vec![ @@ -241,7 +241,7 @@ impl Server { // Start waiting for level chunks player.client.send_packet(&CGameEvent::new(13, 0.0)); - let gameprofile = player.client.gameprofile.as_ref().unwrap(); + let gameprofile = &player.gameprofile; // spawn player for every client self.broadcast_packet_except( @@ -268,7 +268,7 @@ impl Server { for (_, existing_player) in self.current_players.iter().filter(|c| c.0 != &token) { let existing_player = existing_player.as_ref().lock().unwrap(); let entity = &existing_player.entity; - let gameprofile = existing_player.client.gameprofile.as_ref().unwrap(); + let gameprofile = &existing_player.gameprofile; player.client.send_packet(&CSpawnEntity::new( existing_player.entity_id().into(), UUID(gameprofile.id),