diff --git a/pumpkin/src/client/client.rs b/pumpkin/src/client/client.rs new file mode 100644 index 000000000..9e40f573c --- /dev/null +++ b/pumpkin/src/client/client.rs @@ -0,0 +1,444 @@ +use std::{ + collections::VecDeque, + io::{self, Write}, + net::SocketAddr, + sync::Arc, + time::Duration, +}; + +use crate::{ + entity::player::{ChatMode, GameMode, Hand, Player}, + server::Server, +}; + +use super::connection::Connection; +use super::{authentication::GameProfile, EncryptionError}; +use bytes::BytesMut; +use num_traits::ToPrimitive; +use pumpkin_protocol::{ + bytebuf::packet_id::Packet, + client::{ + config::CConfigDisconnect, + login::CLoginDisconnect, + play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge}, + }, + server::{ + config::{SAcknowledgeFinishConfig, SClientInformationConfig, SKnownPacks, SPluginMessage}, + handshake::SHandShake, + login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, + play::{ + SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract, + SPlayerAction, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, + SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSwingArm, SUseItemOn, + }, + status::{SPingRequest, SStatusRequest}, + }, + ClientPacket, ConnectionState, RawPacket, ServerPacket, +}; +use pumpkin_text::TextComponent; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpStream, + select, + sync::RwLock, +}; + +use std::io::Read; + +pub struct PlayerConfig { + pub locale: String, // 16 + pub view_distance: i8, + pub chat_mode: ChatMode, + pub chat_colors: bool, + pub skin_parts: u8, + pub main_hand: Hand, + pub text_filtering: bool, + pub server_listing: bool, +} + +pub struct Client { + pub player: Option, + + pub gameprofile: Option, + + pub config: Option, + pub brand: Option, + + pub protocol_version: i32, + pub connection_state: ConnectionState, + pub encrytion: bool, + pub closed: bool, + pub token: u32, + pub connection: Connection, + pub address: SocketAddr, + pub client_packets_queue: VecDeque, +} + +impl Client { + pub fn new(token: u32, client: TcpStream, address: SocketAddr) -> Self { + Self { + protocol_version: 0, + gameprofile: None, + config: None, + brand: None, + token, + address, + player: None, + connection_state: ConnectionState::HandShake, + connection: Connection::new(client), + encrytion: true, + closed: false, + client_packets_queue: VecDeque::new(), + } + } + + /// adds a Incoming packet to the queue + pub fn add_packet(&mut self, packet: RawPacket) { + self.client_packets_queue.push_back(packet); + } + + /// enables encryption + pub fn enable_encryption( + &mut self, + shared_secret: &[u8], // decrypted + ) -> Result<(), EncryptionError> { + self.encrytion = true; + let crypt_key: [u8; 16] = shared_secret + .try_into() + .map_err(|_| EncryptionError::SharedWrongLength)?; + self.connection.dec.enable_encryption(&crypt_key); + self.connection.enc.enable_encryption(&crypt_key); + Ok(()) + } + + // Compression threshold, Compression level + pub fn set_compression(&mut self, compression: Option<(u32, u32)>) { + self.connection + .dec + .set_compression(compression.map(|v| v.0)); + self.connection.enc.set_compression(compression); + } + + pub fn is_player(&self) -> bool { + self.player.is_some() + } + + /// Send a Clientbound Packet to the Client + pub async fn send_packet(&mut self, packet: &P) { + match self.connection.try_send_packet(packet).await { + Ok(_) => {} + Err(e) => { + self.kick(&e.to_string()).await; + } + }; + } + + pub async fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) { + assert!(self.is_player()); + // TODO + let id = 0; + let player = self.player.as_mut().unwrap(); + let entity = &mut player.entity; + entity.x = x; + entity.y = y; + entity.z = z; + entity.lastx = x; + entity.lasty = y; + entity.lastz = z; + entity.yaw = yaw; + entity.pitch = pitch; + player.awaiting_teleport = Some(id.into()); + self.send_packet(&CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into())) + .await; + } + + pub fn update_health(&mut self, health: f32, food: i32, food_saturation: f32) { + let player = self.player.as_mut().unwrap(); + player.health = health; + player.food = food; + player.food_saturation = food_saturation; + } + + pub fn set_gamemode(&mut self, gamemode: GameMode) { + let player = self.player.as_mut().unwrap(); + player.gamemode = gamemode; + self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); + } + + pub async fn process_packets(&mut self, server: &mut Server) { + let mut i = 0; + while i < self.client_packets_queue.len() { + let mut packet = self.client_packets_queue.remove(i).unwrap(); + self.handle_packet(server, &mut packet).await; + i += 1; + } + } + + /// Handles an incoming decoded Packet + pub async fn handle_packet(&mut self, server: &mut Server, packet: &mut RawPacket) { + // TODO: handle each packet's Error instead of calling .unwrap() + let bytebuf = &mut packet.bytebuf; + match self.connection_state { + pumpkin_protocol::ConnectionState::HandShake => match packet.id.0 { + SHandShake::PACKET_ID => { + self.handle_handshake(server, SHandShake::read(bytebuf).unwrap()) + .await + } + _ => log::error!( + "Failed to handle packet id {} while in Handshake state", + packet.id.0 + ), + }, + pumpkin_protocol::ConnectionState::Status => match packet.id.0 { + SStatusRequest::PACKET_ID => { + self.handle_status_request(server, SStatusRequest::read(bytebuf).unwrap()) + .await + } + SPingRequest::PACKET_ID => { + self.handle_ping_request(server, SPingRequest::read(bytebuf).unwrap()) + .await + } + _ => log::error!( + "Failed to handle packet id {} while in Status state", + packet.id.0 + ), + }, + pumpkin_protocol::ConnectionState::Login => match packet.id.0 { + SLoginStart::PACKET_ID => { + self.handle_login_start(server, SLoginStart::read(bytebuf).unwrap()) + .await + } + SEncryptionResponse::PACKET_ID => { + self.handle_encryption_response( + server, + SEncryptionResponse::read(bytebuf).unwrap(), + ) + .await + } + SLoginPluginResponse::PACKET_ID => { + self.handle_plugin_response( + server, + SLoginPluginResponse::read(bytebuf).unwrap(), + ) + .await + } + SLoginAcknowledged::PACKET_ID => { + self.handle_login_acknowledged( + server, + SLoginAcknowledged::read(bytebuf).unwrap(), + ) + .await + } + _ => log::error!( + "Failed to handle packet id {} while in Login state", + packet.id.0 + ), + }, + pumpkin_protocol::ConnectionState::Config => match packet.id.0 { + SClientInformationConfig::PACKET_ID => { + self.handle_client_information_config( + server, + SClientInformationConfig::read(bytebuf).unwrap(), + ) + .await + } + SPluginMessage::PACKET_ID => { + self.handle_plugin_message(server, SPluginMessage::read(bytebuf).unwrap()) + .await + } + SAcknowledgeFinishConfig::PACKET_ID => { + self.handle_config_acknowledged( + server, + SAcknowledgeFinishConfig::read(bytebuf).unwrap(), + ) + .await + } + SKnownPacks::PACKET_ID => { + self.handle_known_packs(server, SKnownPacks::read(bytebuf).unwrap()) + .await + } + _ => log::error!( + "Failed to handle packet id {} while in Config state", + packet.id.0 + ), + }, + pumpkin_protocol::ConnectionState::Play => { + if self.player.is_some() { + self.handle_play_packet(server, packet).await; + } else { + // should be impossible + self.kick("no player in play state?").await + } + } + _ => log::error!("Invalid Connection state {:?}", self.connection_state), + } + } + + pub async fn handle_play_packet(&mut self, server: &mut Server, packet: &mut RawPacket) { + let bytebuf = &mut packet.bytebuf; + match packet.id.0 { + SConfirmTeleport::PACKET_ID => { + self.handle_confirm_teleport(server, SConfirmTeleport::read(bytebuf).unwrap()) + .await + } + SChatCommand::PACKET_ID => { + self.handle_chat_command(server, SChatCommand::read(bytebuf).unwrap()) + .await + } + SPlayerPosition::PACKET_ID => { + self.handle_position(server, SPlayerPosition::read(bytebuf).unwrap()) + .await + } + SPlayerPositionRotation::PACKET_ID => { + self.handle_position_rotation( + server, + SPlayerPositionRotation::read(bytebuf).unwrap(), + ) + .await + } + SPlayerRotation::PACKET_ID => { + self.handle_rotation(server, SPlayerRotation::read(bytebuf).unwrap()) + .await + } + SPlayerCommand::PACKET_ID => { + self.handle_player_command(server, SPlayerCommand::read(bytebuf).unwrap()) + .await + } + SSwingArm::PACKET_ID => { + self.handle_swing_arm(server, SSwingArm::read(bytebuf).unwrap()) + .await + } + SChatMessage::PACKET_ID => { + self.handle_chat_message(server, SChatMessage::read(bytebuf).unwrap()) + .await + } + SClientInformationPlay::PACKET_ID => { + self.handle_client_information_play( + server, + SClientInformationPlay::read(bytebuf).unwrap(), + ) + .await + } + SInteract::PACKET_ID => { + self.handle_interact(server, SInteract::read(bytebuf).unwrap()) + .await + } + SPlayerAction::PACKET_ID => { + self.handle_player_action(server, SPlayerAction::read(bytebuf).unwrap()) + .await + } + SUseItemOn::PACKET_ID => { + self.handle_use_item_on(server, SUseItemOn::read(bytebuf).unwrap()) + .await + } + SSetHeldItem::PACKET_ID => { + self.handle_set_held_item(server, SSetHeldItem::read(bytebuf).unwrap()) + .await + } + SSetCreativeSlot::PACKET_ID => { + self.handle_set_creative_slot(server, SSetCreativeSlot::read(bytebuf).unwrap()) + .await + } + _ => log::error!("Failed to handle player packet id {}", packet.id.0), + } + } + + // Reads the connection until our buffer of len 4096 is full, then decode + /// Close connection when an error occurs + pub async fn poll(&mut self, server: Arc>) { + dbg!("b"); + + let mut buf = BytesMut::new(); + loop { + select! { + result = self.connection.client.read_buf(&mut buf) => { + match result { + Ok(0) => { + self.close(); + break; + } + Ok(_) => { + self.connection.dec.queue_bytes(buf.split()); + } + Err(e) => { + log::error!("{}", e); + self.kick(&e.to_string()).await; + break; + } + }; + loop { + match self.connection.dec.decode() { + Ok(Some(packet)) => { + self.add_packet(packet); + let mut server = server.write().await; + self.process_packets(&mut server).await; + continue; + } + Ok(None) => break, + Err(err) => { + self.kick(&err.to_string()).await; + break; + }, + }; + } + + }, + _ = tokio::time::sleep(Duration::from_millis(100)) => { + // Handle timeout (optional) + } + } + } + } + + pub async fn send_system_message(&mut self, text: TextComponent) { + self.send_packet(&CSystemChatMessge::new(text, false)).await; + } + + /// Kicks the Client with a reason depending on the connection state + pub async fn kick(&mut self, reason: &str) { + dbg!(reason); + match self.connection_state { + ConnectionState::Login => { + match self + .connection + .try_send_packet(&CLoginDisconnect::new( + &serde_json::to_string_pretty(&reason).unwrap(), + )) + .await + { + Ok(_) => {} + Err(_) => self.close(), + } + } + ConnectionState::Config => { + match self + .connection + .try_send_packet(&CConfigDisconnect::new(reason)) + .await + { + Ok(_) => {} + Err(_) => self.close(), + } + } + ConnectionState::Play => { + match self + .connection + .try_send_packet(&CPlayDisconnect::new(TextComponent::from(reason))) + .await + { + Ok(_) => {} + Err(_) => self.close(), + } + } + _ => { + log::warn!("Cant't kick in {:?} State", self.connection_state) + } + } + self.close() + } + + /// You should prefer to use `kick` when you can + pub fn close(&mut self) { + self.closed = true; + } +} diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index db5f2a6d7..81b641fe3 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -20,7 +20,10 @@ use rsa::Pkcs1v15Encrypt; use sha1::{Digest, Sha1}; use crate::{ - client::authentication::{self, GameProfile}, + client::{ + authentication::{self, GameProfile}, + client::PlayerConfig, + }, entity::player::{ChatMode, Hand}, proxy::velocity::velocity_login, server::{Server, CURRENT_MC_VERSION}, @@ -28,7 +31,8 @@ use crate::{ use super::{ authentication::{auth_digest, unpack_textures}, - Client, EncryptionError, PlayerConfig, + client::Client, + EncryptionError, }; /// Processes incoming Packets from the Client to the Server diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index d23fa5608..72db137ce 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -1,455 +1,13 @@ -use std::{ - collections::VecDeque, - io::{self, Write}, - net::SocketAddr, - sync::Arc, - time::Duration, -}; +use std::io; -use crate::{ - entity::player::{ChatMode, GameMode, Hand, Player}, - server::Server, -}; - -use authentication::GameProfile; -use bytes::BytesMut; -use connection::Connection; -use num_traits::ToPrimitive; -use pumpkin_protocol::{ - bytebuf::packet_id::Packet, - client::{ - config::CConfigDisconnect, - login::CLoginDisconnect, - play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge}, - }, - packet_decoder::PacketDecoder, - packet_encoder::PacketEncoder, - server::{ - config::{SAcknowledgeFinishConfig, SClientInformationConfig, SKnownPacks, SPluginMessage}, - handshake::SHandShake, - login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, - play::{ - SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract, - SPlayerAction, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, - SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSwingArm, SUseItemOn, - }, - status::{SPingRequest, SStatusRequest}, - }, - ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket, -}; -use pumpkin_text::TextComponent; -use tokio::{ - io::{AsyncReadExt, AsyncWriteExt}, - net::TcpStream, - select, - sync::RwLock, -}; - -use std::io::Read; use thiserror::Error; - pub mod authentication; +pub mod client; mod client_packet; pub mod connection; pub mod player_packet; -pub struct PlayerConfig { - pub locale: String, // 16 - pub view_distance: i8, - pub chat_mode: ChatMode, - pub chat_colors: bool, - pub skin_parts: u8, - pub main_hand: Hand, - pub text_filtering: bool, - pub server_listing: bool, -} - -pub struct Client { - pub player: Option, - - pub gameprofile: Option, - - pub config: Option, - pub brand: Option, - - pub protocol_version: i32, - pub connection_state: ConnectionState, - pub encrytion: bool, - pub closed: bool, - pub token: u32, - pub connection: Connection, - pub address: SocketAddr, - pub client_packets_queue: VecDeque, -} - -impl Client { - pub fn new(token: u32, client: TcpStream, address: SocketAddr) -> Self { - Self { - protocol_version: 0, - gameprofile: None, - config: None, - brand: None, - token, - address, - player: None, - connection_state: ConnectionState::HandShake, - connection: Connection::new(client), - encrytion: true, - closed: false, - client_packets_queue: VecDeque::new(), - } - } - - /// adds a Incoming packet to the queue - pub fn add_packet(&mut self, packet: RawPacket) { - self.client_packets_queue.push_back(packet); - } - - /// enables encryption - pub fn enable_encryption( - &mut self, - shared_secret: &[u8], // decrypted - ) -> Result<(), EncryptionError> { - self.encrytion = true; - let crypt_key: [u8; 16] = shared_secret - .try_into() - .map_err(|_| EncryptionError::SharedWrongLength)?; - self.connection.dec.enable_encryption(&crypt_key); - self.connection.enc.enable_encryption(&crypt_key); - Ok(()) - } - - // Compression threshold, Compression level - pub fn set_compression(&mut self, compression: Option<(u32, u32)>) { - self.connection - .dec - .set_compression(compression.map(|v| v.0)); - self.connection.enc.set_compression(compression); - } - - pub fn is_player(&self) -> bool { - self.player.is_some() - } - - /// Send a Clientbound Packet to the Client - pub async fn send_packet(&mut self, packet: &P) { - match self.connection.try_send_packet(packet).await { - Ok(_) => {} - Err(e) => { - self.kick(&e.to_string()).await; - } - }; - } - - pub async fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) { - assert!(self.is_player()); - // TODO - let id = 0; - let player = self.player.as_mut().unwrap(); - let entity = &mut player.entity; - entity.x = x; - entity.y = y; - entity.z = z; - entity.lastx = x; - entity.lasty = y; - entity.lastz = z; - entity.yaw = yaw; - entity.pitch = pitch; - player.awaiting_teleport = Some(id.into()); - self.send_packet(&CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into())) - .await; - } - - pub fn update_health(&mut self, health: f32, food: i32, food_saturation: f32) { - let player = self.player.as_mut().unwrap(); - player.health = health; - player.food = food; - player.food_saturation = food_saturation; - } - - pub fn set_gamemode(&mut self, gamemode: GameMode) { - let player = self.player.as_mut().unwrap(); - player.gamemode = gamemode; - self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); - } - - pub async fn process_packets(&mut self, server: &mut Server) { - let mut i = 0; - while i < self.client_packets_queue.len() { - let mut packet = self.client_packets_queue.remove(i).unwrap(); - self.handle_packet(server, &mut packet).await; - i += 1; - } - } - - /// Handles an incoming decoded Packet - pub async fn handle_packet(&mut self, server: &mut Server, packet: &mut RawPacket) { - // TODO: handle each packet's Error instead of calling .unwrap() - let bytebuf = &mut packet.bytebuf; - match self.connection_state { - pumpkin_protocol::ConnectionState::HandShake => match packet.id.0 { - SHandShake::PACKET_ID => { - self.handle_handshake(server, SHandShake::read(bytebuf).unwrap()) - .await - } - _ => log::error!( - "Failed to handle packet id {} while in Handshake state", - packet.id.0 - ), - }, - pumpkin_protocol::ConnectionState::Status => match packet.id.0 { - SStatusRequest::PACKET_ID => { - self.handle_status_request(server, SStatusRequest::read(bytebuf).unwrap()) - .await - } - SPingRequest::PACKET_ID => { - self.handle_ping_request(server, SPingRequest::read(bytebuf).unwrap()) - .await - } - _ => log::error!( - "Failed to handle packet id {} while in Status state", - packet.id.0 - ), - }, - pumpkin_protocol::ConnectionState::Login => match packet.id.0 { - SLoginStart::PACKET_ID => { - self.handle_login_start(server, SLoginStart::read(bytebuf).unwrap()) - .await - } - SEncryptionResponse::PACKET_ID => { - self.handle_encryption_response( - server, - SEncryptionResponse::read(bytebuf).unwrap(), - ) - .await - } - SLoginPluginResponse::PACKET_ID => { - self.handle_plugin_response( - server, - SLoginPluginResponse::read(bytebuf).unwrap(), - ) - .await - } - SLoginAcknowledged::PACKET_ID => { - self.handle_login_acknowledged( - server, - SLoginAcknowledged::read(bytebuf).unwrap(), - ) - .await - } - _ => log::error!( - "Failed to handle packet id {} while in Login state", - packet.id.0 - ), - }, - pumpkin_protocol::ConnectionState::Config => match packet.id.0 { - SClientInformationConfig::PACKET_ID => { - self.handle_client_information_config( - server, - SClientInformationConfig::read(bytebuf).unwrap(), - ) - .await - } - SPluginMessage::PACKET_ID => { - self.handle_plugin_message(server, SPluginMessage::read(bytebuf).unwrap()) - .await - } - SAcknowledgeFinishConfig::PACKET_ID => { - self.handle_config_acknowledged( - server, - SAcknowledgeFinishConfig::read(bytebuf).unwrap(), - ) - .await - } - SKnownPacks::PACKET_ID => { - self.handle_known_packs(server, SKnownPacks::read(bytebuf).unwrap()) - .await - } - _ => log::error!( - "Failed to handle packet id {} while in Config state", - packet.id.0 - ), - }, - pumpkin_protocol::ConnectionState::Play => { - if self.player.is_some() { - self.handle_play_packet(server, packet).await; - } else { - // should be impossible - self.kick("no player in play state?").await - } - } - _ => log::error!("Invalid Connection state {:?}", self.connection_state), - } - } - - pub async fn handle_play_packet(&mut self, server: &mut Server, packet: &mut RawPacket) { - let bytebuf = &mut packet.bytebuf; - match packet.id.0 { - SConfirmTeleport::PACKET_ID => { - self.handle_confirm_teleport(server, SConfirmTeleport::read(bytebuf).unwrap()) - .await - } - SChatCommand::PACKET_ID => { - self.handle_chat_command(server, SChatCommand::read(bytebuf).unwrap()) - .await - } - SPlayerPosition::PACKET_ID => { - self.handle_position(server, SPlayerPosition::read(bytebuf).unwrap()) - .await - } - SPlayerPositionRotation::PACKET_ID => { - self.handle_position_rotation( - server, - SPlayerPositionRotation::read(bytebuf).unwrap(), - ) - .await - } - SPlayerRotation::PACKET_ID => { - self.handle_rotation(server, SPlayerRotation::read(bytebuf).unwrap()) - .await - } - SPlayerCommand::PACKET_ID => { - self.handle_player_command(server, SPlayerCommand::read(bytebuf).unwrap()) - .await - } - SSwingArm::PACKET_ID => { - self.handle_swing_arm(server, SSwingArm::read(bytebuf).unwrap()) - .await - } - SChatMessage::PACKET_ID => { - self.handle_chat_message(server, SChatMessage::read(bytebuf).unwrap()) - .await - } - SClientInformationPlay::PACKET_ID => { - self.handle_client_information_play( - server, - SClientInformationPlay::read(bytebuf).unwrap(), - ) - .await - } - SInteract::PACKET_ID => { - self.handle_interact(server, SInteract::read(bytebuf).unwrap()) - .await - } - SPlayerAction::PACKET_ID => { - self.handle_player_action(server, SPlayerAction::read(bytebuf).unwrap()) - .await - } - SUseItemOn::PACKET_ID => { - self.handle_use_item_on(server, SUseItemOn::read(bytebuf).unwrap()) - .await - } - SSetHeldItem::PACKET_ID => { - self.handle_set_held_item(server, SSetHeldItem::read(bytebuf).unwrap()) - .await - } - SSetCreativeSlot::PACKET_ID => { - self.handle_set_creative_slot(server, SSetCreativeSlot::read(bytebuf).unwrap()) - .await - } - _ => log::error!("Failed to handle player packet id {}", packet.id.0), - } - } - - // Reads the connection until our buffer of len 4096 is full, then decode - /// Close connection when an error occurs - pub async fn poll(&mut self, server: Arc>) { - dbg!("b"); - - let mut buf = BytesMut::new(); - loop { - select! { - result = self.connection.client.read_buf(&mut buf) => { - match result { - Ok(0) => { - self.close(); - break; - } - Ok(_) => { - self.connection.dec.queue_bytes(buf.split()); - } - Err(e) => { - log::error!("{}", e); - self.kick(&e.to_string()).await; - break; - } - }; - loop { - match self.connection.dec.decode() { - Ok(Some(packet)) => { - self.add_packet(packet); - let mut server = server.write().await; - self.process_packets(&mut server).await; - continue; - } - Ok(None) => break, - Err(err) => { - self.kick(&err.to_string()).await; - break; - }, - }; - } - - }, - _ = tokio::time::sleep(Duration::from_millis(100)) => { - // Handle timeout (optional) - } - } - } - } - - pub async fn send_system_message(&mut self, text: TextComponent) { - self.send_packet(&CSystemChatMessge::new(text, false)).await; - } - - /// Kicks the Client with a reason depending on the connection state - pub async fn kick(&mut self, reason: &str) { - dbg!(reason); - match self.connection_state { - ConnectionState::Login => { - match self - .connection - .try_send_packet(&CLoginDisconnect::new( - &serde_json::to_string_pretty(&reason).unwrap(), - )) - .await - { - Ok(_) => {} - Err(_) => self.close(), - } - } - ConnectionState::Config => { - match self - .connection - .try_send_packet(&CConfigDisconnect::new(reason)) - .await - { - Ok(_) => {} - Err(_) => self.close(), - } - } - ConnectionState::Play => { - match self - .connection - .try_send_packet(&CPlayDisconnect::new(TextComponent::from(reason))) - .await - { - Ok(_) => {} - Err(_) => self.close(), - } - } - _ => { - log::warn!("Cant't kick in {:?} State", self.connection_state) - } - } - self.close() - } - - /// You should prefer to use `kick` when you can - pub fn close(&mut self) { - self.closed = true; - } -} +pub use client::Client; #[derive(Error, Debug)] pub enum EncryptionError { diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index ea1473be4..4e38117ad 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -24,7 +24,7 @@ use crate::{ util::math::wrap_degrees, }; -use super::{Client, PlayerConfig}; +use super::{client::PlayerConfig, Client}; fn modulus(a: f32, b: f32) -> f32 { ((a % b) + b) % b