Skip to content

Commit

Permalink
Refactor Client
Browse files Browse the repository at this point in the history
  • Loading branch information
Snowiiii committed Aug 24, 2024
1 parent ae028da commit c7f15de
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 326 deletions.
5 changes: 2 additions & 3 deletions pumpkin/src/client/client_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,11 @@ impl Client {

pub async fn handle_config_acknowledged(
&mut self,
server: &mut Server,
_server: &mut Server,
_config_acknowledged: SAcknowledgeFinishConfig,
) {
dbg!("config acknowledged");
self.connection_state = ConnectionState::Play;
// generate a player
server.spawn_player(self).await;
self.make_player = true;
}
}
16 changes: 8 additions & 8 deletions pumpkin/src/client/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use pumpkin_protocol::client::play::{COpenScreen, CSetContainerContent, CSetCont
use pumpkin_protocol::slot::Slot;
use pumpkin_world::item::Item;

impl super::Client {
use crate::entity::player::Player;

impl Player {
pub fn open_container(
&mut self,
window_type: WindowType,
Expand All @@ -23,7 +25,7 @@ impl super::Client {
.unwrap())
.into();
let title = TextComponent::text(window_title.unwrap_or(window_type.default_title()));
self.send_packet(&COpenScreen::new(
self.client.send_packet(&COpenScreen::new(
(window_type.clone() as u8 + 1).into(),
menu_protocol_id,
title,
Expand All @@ -37,14 +39,12 @@ impl super::Client {
items: Option<Vec<Option<&'a Item>>>,
carried_item: Option<&'a Item>,
) {
let player = self.player.as_ref().unwrap();

let slots: Vec<Slot> = {
if let Some(mut items) = items {
items.extend(player.inventory.slots());
items.extend(self.inventory.slots());
items
} else {
player.inventory.slots()
self.inventory.slots()
}
.into_iter()
.map(|item| {
Expand All @@ -66,7 +66,7 @@ impl super::Client {
};
let packet =
CSetContainerContent::new(window_type as u8 + 1, 0.into(), &slots, &carried_item);
self.send_packet(&packet);
self.client.send_packet(&packet);
}

pub fn set_container_slot(
Expand All @@ -75,7 +75,7 @@ impl super::Client {
slot: usize,
item: Option<&Item>,
) {
self.send_packet(&CSetContainerSlot::new(
self.client.send_packet(&CSetContainerSlot::new(
window_type as i8,
0,
slot,
Expand Down
140 changes: 24 additions & 116 deletions pumpkin/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,22 @@ use std::{
};

use crate::{
entity::player::{ChatMode, GameMode, Hand, Player},
entity::player::{ChatMode, Hand},
server::Server,
};

use authentication::GameProfile;
use mio::{event::Event, net::TcpStream, Token};
use num_traits::ToPrimitive;
use pumpkin_core::text::TextComponent;
use pumpkin_protocol::{
bytebuf::packet_id::Packet,
client::{
config::CConfigDisconnect,
login::CLoginDisconnect,
play::{CGameEvent, CPlayDisconnect, CSyncPlayerPosition, CSystemChatMessage},
},
client::{config::CConfigDisconnect, login::CLoginDisconnect, play::CPlayDisconnect},
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,
SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition,
SPlayerPositionRotation, SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSwingArm,
SUseItemOn,
},
status::{SStatusPingRequest, SStatusRequest},
},
ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket,
Expand All @@ -46,6 +35,7 @@ mod client_packet;
mod container;
pub mod player_packet;

#[derive(Clone)]
pub struct PlayerConfig {
pub locale: String, // 16
pub view_distance: i8,
Expand All @@ -57,9 +47,22 @@ pub struct PlayerConfig {
pub server_listing: bool,
}

pub struct Client {
pub player: Option<Player>,
impl Default for PlayerConfig {
fn default() -> Self {
Self {
locale: "en_us".to_string(),
view_distance: 2,
chat_mode: ChatMode::Enabled,
chat_colors: true,
skin_parts: 0,
main_hand: Hand::Main,
text_filtering: false,
server_listing: false,
}
}
}

pub struct Client {
pub gameprofile: Option<GameProfile>,

pub config: Option<PlayerConfig>,
Expand All @@ -75,6 +78,8 @@ pub struct Client {
enc: PacketEncoder,
dec: PacketDecoder,
pub client_packets_queue: VecDeque<RawPacket>,

pub make_player: bool,
}

impl Client {
Expand All @@ -86,14 +91,14 @@ impl Client {
brand: None,
token,
address,
player: None,
connection_state: ConnectionState::HandShake,
connection,
enc: PacketEncoder::default(),
dec: PacketDecoder::default(),
encryption: true,
closed: false,
client_packets_queue: VecDeque::new(),
make_player: false,
}
}

Expand Down Expand Up @@ -122,10 +127,6 @@ impl Client {
self.enc.set_compression(compression);
}

pub fn is_player(&self) -> bool {
self.player.is_some()
}

/// Send a Clientbound Packet to the Client
pub fn send_packet<P: ClientPacket>(&mut self, packet: &P) {
self.enc
Expand All @@ -145,37 +146,6 @@ impl Client {
Ok(())
}

pub 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(&CSyncPlayerPosition::new(x, y, z, yaw, pitch, 0, id.into()));
}

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() {
Expand All @@ -185,7 +155,7 @@ impl Client {
}
}

/// Handles an incoming decoded Packet
/// Handles an incoming decoded not Play state 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;
Expand Down Expand Up @@ -254,71 +224,13 @@ impl Client {
packet.id.0
),
},
pumpkin_protocol::ConnectionState::Play => {
if self.player.is_some() {
self.handle_play_packet(server, packet);
} else {
// should be impossible
self.kick("no player in play state?")
}
}
_ => log::error!("Invalid Connection state {:?}", self.connection_state),
}
}

pub 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())
}
SChatCommand::PACKET_ID => {
self.handle_chat_command(server, SChatCommand::read(bytebuf).unwrap())
}
SPlayerPosition::PACKET_ID => {
self.handle_position(server, SPlayerPosition::read(bytebuf).unwrap())
}
SPlayerPositionRotation::PACKET_ID => self
.handle_position_rotation(server, SPlayerPositionRotation::read(bytebuf).unwrap()),
SPlayerRotation::PACKET_ID => {
self.handle_rotation(server, SPlayerRotation::read(bytebuf).unwrap())
}
SPlayerCommand::PACKET_ID => {
self.handle_player_command(server, SPlayerCommand::read(bytebuf).unwrap())
}
SSwingArm::PACKET_ID => {
self.handle_swing_arm(server, SSwingArm::read(bytebuf).unwrap())
}
SChatMessage::PACKET_ID => {
self.handle_chat_message(server, SChatMessage::read(bytebuf).unwrap())
}
SClientInformationPlay::PACKET_ID => self.handle_client_information_play(
server,
SClientInformationPlay::read(bytebuf).unwrap(),
),
SInteract::PACKET_ID => self.handle_interact(server, SInteract::read(bytebuf).unwrap()),
SPlayerAction::PACKET_ID => {
self.handle_player_action(server, SPlayerAction::read(bytebuf).unwrap())
}
SUseItemOn::PACKET_ID => {
self.handle_use_item_on(server, SUseItemOn::read(bytebuf).unwrap())
}
SSetHeldItem::PACKET_ID => {
self.handle_set_held_item(server, SSetHeldItem::read(bytebuf).unwrap())
}
SSetCreativeSlot::PACKET_ID => {
self.handle_set_creative_slot(server, SSetCreativeSlot::read(bytebuf).unwrap())
}
SPlayPingRequest::PACKET_ID => {
self.handle_play_ping_request(server, SPlayPingRequest::read(bytebuf).unwrap())
}
_ => log::error!("Failed to handle player packet id {:#04x}", 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: &mut Server, event: &Event) {
pub async fn poll(&mut self, event: &Event) {
if event.is_readable() {
let mut received_data = vec![0; 4096];
let mut bytes_read = 0;
Expand Down Expand Up @@ -351,7 +263,6 @@ impl Client {
Ok(packet) => {
if let Some(packet) = packet {
self.add_packet(packet);
self.process_packets(server).await;
}
}
Err(err) => self.kick(&err.to_string()),
Expand All @@ -361,10 +272,6 @@ impl Client {
}
}

pub fn send_system_message(&mut self, text: TextComponent) {
self.send_packet(&CSystemChatMessage::new(text, false));
}

/// Kicks the Client with a reason depending on the connection state
pub fn kick(&mut self, reason: &str) {
dbg!(reason);
Expand All @@ -379,6 +286,7 @@ impl Client {
self.try_send_packet(&CConfigDisconnect::new(reason))
.unwrap_or_else(|_| self.close());
}
// So we can also kick on errors, but generally should use Player::kick
ConnectionState::Play => {
self.try_send_packet(&CPlayDisconnect::new(TextComponent::text(reason)))
.unwrap_or_else(|_| self.close());
Expand Down
Loading

0 comments on commit c7f15de

Please sign in to comment.