From ab5342c031789a61c3980304d150236f6d88c934 Mon Sep 17 00:00:00 2001 From: Erb3 <49862976+Erb3@users.noreply.github.com> Date: Tue, 20 Aug 2024 19:38:46 +0200 Subject: [PATCH 01/30] feat: initial docker support --- .dockerignore | 12 ++++++++++++ Dockerfile | 25 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..5c5187748 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +# A whitelist of files that should be included into docker +# Put an exclaimation mark before everything to include + +# Ignore everything +* + +# Allow the source code folders +!/pumpkin*/ + +# Dependencies +!Cargo.lock +!Cargo.toml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..ea678f677 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM rust:1.79 AS builder +WORKDIR /usr/src/pumpkin +COPY . . +RUN ls +RUN cargo install --path ./pumpkin + +FROM rust +WORKDIR /pumpkin +RUN apt update && apt-get install -y libssl-dev pkg-config ca-certificates && rm -rf /var/lib/apt/lists/* +COPY --from=builder /usr/local/cargo/bin/pumpkin /pumpkin/pumpkin +CMD ["/pumpkin/pumpkin"] + +# FROM rust:1.79-alpine AS builder +# WORKDIR /usr/src/pumpkin +# COPY . . +# RUN apk add openssl-dev libssl3 ca-certificates pkgconfig musl-dev +# RUN cargo install --path ./pumpkin + +# FROM rust:1.79-alpine +# WORKDIR /pumpkin +# RUN apk add openssl ca-certificates pkgconfig +# COPY --from=builder /usr/local/cargo/bin/pumpkin /pumpkin/pumpkin +# CMD ["/pumpkin/pumpkin"] + +#docker run --rm -v "./world:/pumpkin/world" pumpkin From e6e63c6c1e7c83c398998b33f076e184896947b7 Mon Sep 17 00:00:00 2001 From: Erb3 <49862976+Erb3@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:01:25 +0200 Subject: [PATCH 02/30] docs: simple docker instructions --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index b0c341e70..32f57450d 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,21 @@ Then run: RUSTFLAGS="-C target-cpu=native" cargo run --release ``` +### Docker + +Experimental Docker support is available. +The image is currently not published anywhere, but you can use the following command to build it: + +```shell +docker build . -t pumpkin +``` + +To run it use the following command: + +```shell +docker run --rm -v "./world:/pumpkin/world" pumpkin +``` + ## Contributions Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) From c64cdb23662799a7c9ff28189fab83ed9b7ff149 Mon Sep 17 00:00:00 2001 From: Erb3 <49862976+Erb3@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:00:18 +0200 Subject: [PATCH 03/30] fix: apply patch for command spam --- pumpkin/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index e4db13870..cc9ef23b5 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -94,7 +94,10 @@ fn main() -> io::Result<()> { stdin .read_line(&mut out) .expect("Failed to read console line"); - handle_command(&mut commands::CommandSender::Console, &out); + + if !out.is_empty() { + handle_command(&mut commands::CommandSender::Console, &out); + } } }); } From 88ebd25e9b143a5863bba947e018f6448d20eb21 Mon Sep 17 00:00:00 2001 From: kralverde Date: Thu, 22 Aug 2024 18:21:52 -0400 Subject: [PATCH 04/30] implement the unload chunk packet --- .../src/client/play/c_unload_chunk.rs | 15 +++++++++++++++ pumpkin-protocol/src/client/play/mod.rs | 2 ++ 2 files changed, 17 insertions(+) create mode 100644 pumpkin-protocol/src/client/play/c_unload_chunk.rs diff --git a/pumpkin-protocol/src/client/play/c_unload_chunk.rs b/pumpkin-protocol/src/client/play/c_unload_chunk.rs new file mode 100644 index 000000000..09294b9b0 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_unload_chunk.rs @@ -0,0 +1,15 @@ +use pumpkin_macros::packet; +use serde::Serialize; + +#[derive(Serialize)] +#[packet(0x21)] +pub struct CUnloadChunk { + z: i32, + x: i32, +} + +impl CUnloadChunk { + pub fn new(x: i32, z: i32) -> Self { + Self { z, x } + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index a732f2ccb..2e15aa978 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -30,6 +30,7 @@ mod c_spawn_player; mod c_subtitle; mod c_sync_player_position; mod c_system_chat_message; +mod c_unload_chunk; mod c_update_entitiy_pos_rot; mod c_update_entity_pos; mod c_update_entity_rot; @@ -68,6 +69,7 @@ pub use c_spawn_player::*; pub use c_subtitle::*; pub use c_sync_player_position::*; pub use c_system_chat_message::*; +pub use c_unload_chunk::*; pub use c_update_entitiy_pos_rot::*; pub use c_update_entity_pos::*; pub use c_update_entity_rot::*; From ebb5727bbd493141f68047f467147ca1601dd0ff Mon Sep 17 00:00:00 2001 From: we sell insurance Date: Thu, 22 Aug 2024 19:39:36 -0500 Subject: [PATCH 05/30] Change to print hex packet id instead of decimal for umimplemented packets --- pumpkin/src/client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 837976873..ec824cf39 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -311,7 +311,7 @@ impl Client { SPlayPingRequest::PACKET_ID => { self.handle_play_ping_request(server, SPlayPingRequest::read(bytebuf).unwrap()) } - _ => log::error!("Failed to handle player packet id {}", packet.id.0), + _ => log::error!("Failed to handle player packet id {:#04x}", packet.id.0), } } From 7c2b650bdb391a0d5c6cabb2df7478f60ad11b99 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Fri, 23 Aug 2024 10:32:00 +0200 Subject: [PATCH 06/30] add clientbound packet: CCloseContainer --- .../src/client/play/c_close_container.rs | 16 ++++++++++++++++ pumpkin-protocol/src/client/play/mod.rs | 2 ++ pumpkin/src/client/container.rs | 10 +++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 pumpkin-protocol/src/client/play/c_close_container.rs diff --git a/pumpkin-protocol/src/client/play/c_close_container.rs b/pumpkin-protocol/src/client/play/c_close_container.rs new file mode 100644 index 000000000..56c3bb457 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_close_container.rs @@ -0,0 +1,16 @@ +use serde::Serialize; +use pumpkin_macros::packet; + +#[derive(Serialize)] +#[packet(0x12)] +pub struct CCloseContainer { + window_id: u8 +} + +impl CCloseContainer { + pub const fn new(window_id: u8) -> Self { + Self { + window_id + } + } +} \ No newline at end of file diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 2e15aa978..65a5ba8d0 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -36,6 +36,7 @@ mod c_update_entity_pos; mod c_update_entity_rot; mod c_worldevent; mod player_action; +mod c_close_container; pub use c_acknowledge_block::*; pub use c_actionbar::*; @@ -75,3 +76,4 @@ pub use c_update_entity_pos::*; pub use c_update_entity_rot::*; pub use c_worldevent::*; pub use player_action::*; +pub use c_close_container::*; \ No newline at end of file diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index b8a242dbd..ead7eb502 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -1,6 +1,6 @@ use pumpkin_core::text::TextComponent; use pumpkin_inventory::WindowType; -use pumpkin_protocol::client::play::{COpenScreen, CSetContainerContent, CSetContainerSlot}; +use pumpkin_protocol::client::play::{CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerSlot}; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::Item; @@ -82,4 +82,12 @@ impl super::Client { &item.into(), )) } + + /// The official Minecraft client is weird, and will always just close *any* window that is opened when this gets sent + pub fn close_container( + &mut self, + window_type: WindowType + ) { + self.send_packet(&CCloseContainer::new(window_type as u8)) + } } From 85f7ab041ac2decea5f10137d1900ea93322d586 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Fri, 23 Aug 2024 11:51:12 +0200 Subject: [PATCH 07/30] add clientbound packet: CSetContainerProperty --- .../client/play/c_set_container_property.rs | 19 +++++++++++++++++++ pumpkin-protocol/src/client/play/mod.rs | 4 +++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 pumpkin-protocol/src/client/play/c_set_container_property.rs diff --git a/pumpkin-protocol/src/client/play/c_set_container_property.rs b/pumpkin-protocol/src/client/play/c_set_container_property.rs new file mode 100644 index 000000000..fd54753fe --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_set_container_property.rs @@ -0,0 +1,19 @@ +use serde::Serialize; +use pumpkin_macros::packet; +#[derive(Serialize)] +#[packet(0x14)] +pub struct CSetContainerProperty { + window_id: u8, + property: i16, + value: i16 +} + +impl CSetContainerProperty { + pub const fn new(window_id: u8, property: i16, value:i16) -> Self { + Self { + window_id, + property, + value + } + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 65a5ba8d0..838c79272 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -37,6 +37,7 @@ mod c_update_entity_rot; mod c_worldevent; mod player_action; mod c_close_container; +mod c_set_container_property; pub use c_acknowledge_block::*; pub use c_actionbar::*; @@ -76,4 +77,5 @@ pub use c_update_entity_pos::*; pub use c_update_entity_rot::*; pub use c_worldevent::*; pub use player_action::*; -pub use c_close_container::*; \ No newline at end of file +pub use c_close_container::*; +pub use c_set_container_property::*; \ No newline at end of file From 1d1dcc6a853349669684f4c32ede8ee6d1983d81 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Fri, 23 Aug 2024 11:51:37 +0200 Subject: [PATCH 08/30] make window property abstractions --- pumpkin-inventory/src/lib.rs | 1 + pumpkin-inventory/src/window_property.rs | 111 +++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 pumpkin-inventory/src/window_property.rs diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 044980cc4..0230ac189 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -1,6 +1,7 @@ use num_derive::ToPrimitive; pub mod player; +pub mod window_property; /// https://wiki.vg/Inventory #[derive(Debug, ToPrimitive, Clone)] diff --git a/pumpkin-inventory/src/window_property.rs b/pumpkin-inventory/src/window_property.rs new file mode 100644 index 000000000..64e24d044 --- /dev/null +++ b/pumpkin-inventory/src/window_property.rs @@ -0,0 +1,111 @@ +pub trait WindowPropertyTrait: Sized { + fn to_id(self) -> i16 { + 0 + } +} + +pub struct WindowProperty { + window_property: T, + value: i16 +} + +impl WindowProperty { + pub fn new(window_property: T,value: i16) -> Self { + Self { + window_property, + value + } + } + + pub fn into_packet(self) -> (i16,i16) { + (self.window_property.to_id(), self.value) + } +} + + +pub enum Furnace { + FireIcon, + MaximumFuelBurnTime, + ProgressArrow, + MaximumProgress +} + +impl WindowPropertyTrait for Furnace { + fn to_id(self) -> i16 { + self as i16 + } +} + + + +pub enum EnchantmentTable { + LevelRequirement{ + slot:u8 + }, + EnchantmentSeed, + EnchantmentId{ + slot:u8 + }, + EnchantmentLevel{slot:u8}, +} + +impl WindowPropertyTrait for EnchantmentTable { + fn to_id(self) -> i16 { + use EnchantmentTable::*; + + (match self { + LevelRequirement{slot} => slot, + EnchantmentSeed => 3, + EnchantmentId{slot} => 4+slot, + EnchantmentLevel{slot} => 7+slot, + }) as i16 + } +} + +pub enum Beacon { + PowerLevel, + FirstPotionEffect, + SecondPotionEffect +} + +impl WindowPropertyTrait for Beacon { + fn to_id(self) -> i16 { + self as i16 + } +} + +pub enum Anvil { + RepairCost +} + +impl WindowPropertyTrait for Anvil {} + +pub enum BrewingStand{ + BrewTime, + FuelTime +} + +impl WindowPropertyTrait for BrewingStand { + fn to_id(self) -> i16 { + self as i16 + } +} + +pub enum Stonecutter { + SelectedRecipe +} + +impl WindowPropertyTrait for Stonecutter {} + +pub enum Loom { + SelectedPattern +} + +impl WindowPropertyTrait for Loom {} + +pub enum Lectern { + PageNumber +} + +impl WindowPropertyTrait for Lectern {} + From 4523900de44f66c3d965c2fdf93dda9e18d133d6 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Fri, 23 Aug 2024 11:51:51 +0200 Subject: [PATCH 09/30] add method to set container property --- pumpkin/src/client/container.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index ead7eb502..edec9f39e 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -1,6 +1,7 @@ use pumpkin_core::text::TextComponent; +use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait}; use pumpkin_inventory::WindowType; -use pumpkin_protocol::client::play::{CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerSlot}; +use pumpkin_protocol::client::play::{CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot}; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::Item; @@ -90,4 +91,9 @@ impl super::Client { ) { self.send_packet(&CCloseContainer::new(window_type as u8)) } + + pub fn set_container_property(&mut self, window_type: WindowType, window_property: WindowProperty) { + let (id,value) = window_property.into_packet(); + self.send_packet(&CSetContainerProperty::new(window_type as u8,id,value)); + } } From 98fcd412c2f86cc2df43a1284d31acaf1b583aca Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Fri, 23 Aug 2024 11:52:21 +0200 Subject: [PATCH 10/30] formatting --- pumpkin-inventory/src/window_property.rs | 46 ++++++++----------- .../src/client/play/c_close_container.rs | 10 ++-- .../client/play/c_set_container_property.rs | 8 ++-- pumpkin-protocol/src/client/play/mod.rs | 8 ++-- pumpkin/src/client/container.rs | 25 +++++----- 5 files changed, 45 insertions(+), 52 deletions(-) diff --git a/pumpkin-inventory/src/window_property.rs b/pumpkin-inventory/src/window_property.rs index 64e24d044..67deb646e 100644 --- a/pumpkin-inventory/src/window_property.rs +++ b/pumpkin-inventory/src/window_property.rs @@ -6,28 +6,27 @@ pub trait WindowPropertyTrait: Sized { pub struct WindowProperty { window_property: T, - value: i16 + value: i16, } impl WindowProperty { - pub fn new(window_property: T,value: i16) -> Self { + pub fn new(window_property: T, value: i16) -> Self { Self { window_property, - value + value, } } - - pub fn into_packet(self) -> (i16,i16) { + + pub fn into_packet(self) -> (i16, i16) { (self.window_property.to_id(), self.value) } } - pub enum Furnace { FireIcon, MaximumFuelBurnTime, ProgressArrow, - MaximumProgress + MaximumProgress, } impl WindowPropertyTrait for Furnace { @@ -36,17 +35,11 @@ impl WindowPropertyTrait for Furnace { } } - - pub enum EnchantmentTable { - LevelRequirement{ - slot:u8 - }, + LevelRequirement { slot: u8 }, EnchantmentSeed, - EnchantmentId{ - slot:u8 - }, - EnchantmentLevel{slot:u8}, + EnchantmentId { slot: u8 }, + EnchantmentLevel { slot: u8 }, } impl WindowPropertyTrait for EnchantmentTable { @@ -54,10 +47,10 @@ impl WindowPropertyTrait for EnchantmentTable { use EnchantmentTable::*; (match self { - LevelRequirement{slot} => slot, + LevelRequirement { slot } => slot, EnchantmentSeed => 3, - EnchantmentId{slot} => 4+slot, - EnchantmentLevel{slot} => 7+slot, + EnchantmentId { slot } => 4 + slot, + EnchantmentLevel { slot } => 7 + slot, }) as i16 } } @@ -65,7 +58,7 @@ impl WindowPropertyTrait for EnchantmentTable { pub enum Beacon { PowerLevel, FirstPotionEffect, - SecondPotionEffect + SecondPotionEffect, } impl WindowPropertyTrait for Beacon { @@ -75,14 +68,14 @@ impl WindowPropertyTrait for Beacon { } pub enum Anvil { - RepairCost + RepairCost, } impl WindowPropertyTrait for Anvil {} -pub enum BrewingStand{ +pub enum BrewingStand { BrewTime, - FuelTime + FuelTime, } impl WindowPropertyTrait for BrewingStand { @@ -92,20 +85,19 @@ impl WindowPropertyTrait for BrewingStand { } pub enum Stonecutter { - SelectedRecipe + SelectedRecipe, } impl WindowPropertyTrait for Stonecutter {} pub enum Loom { - SelectedPattern + SelectedPattern, } impl WindowPropertyTrait for Loom {} pub enum Lectern { - PageNumber + PageNumber, } impl WindowPropertyTrait for Lectern {} - diff --git a/pumpkin-protocol/src/client/play/c_close_container.rs b/pumpkin-protocol/src/client/play/c_close_container.rs index 56c3bb457..b8350265b 100644 --- a/pumpkin-protocol/src/client/play/c_close_container.rs +++ b/pumpkin-protocol/src/client/play/c_close_container.rs @@ -1,16 +1,14 @@ -use serde::Serialize; use pumpkin_macros::packet; +use serde::Serialize; #[derive(Serialize)] #[packet(0x12)] pub struct CCloseContainer { - window_id: u8 + window_id: u8, } impl CCloseContainer { pub const fn new(window_id: u8) -> Self { - Self { - window_id - } + Self { window_id } } -} \ No newline at end of file +} diff --git a/pumpkin-protocol/src/client/play/c_set_container_property.rs b/pumpkin-protocol/src/client/play/c_set_container_property.rs index fd54753fe..1fee26ef5 100644 --- a/pumpkin-protocol/src/client/play/c_set_container_property.rs +++ b/pumpkin-protocol/src/client/play/c_set_container_property.rs @@ -1,19 +1,19 @@ -use serde::Serialize; use pumpkin_macros::packet; +use serde::Serialize; #[derive(Serialize)] #[packet(0x14)] pub struct CSetContainerProperty { window_id: u8, property: i16, - value: i16 + value: i16, } impl CSetContainerProperty { - pub const fn new(window_id: u8, property: i16, value:i16) -> Self { + pub const fn new(window_id: u8, property: i16, value: i16) -> Self { Self { window_id, property, - value + value, } } } diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 838c79272..8d4a6e84b 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -5,6 +5,7 @@ mod c_block_update; mod c_center_chunk; mod c_change_difficulty; mod c_chunk_data; +mod c_close_container; mod c_disguised_chat_message; mod c_entity_animation; mod c_entity_metadata; @@ -23,6 +24,7 @@ mod c_player_info_update; mod c_player_remove; mod c_remove_entities; mod c_set_container_content; +mod c_set_container_property; mod c_set_container_slot; mod c_set_held_item; mod c_set_title; @@ -36,8 +38,6 @@ mod c_update_entity_pos; mod c_update_entity_rot; mod c_worldevent; mod player_action; -mod c_close_container; -mod c_set_container_property; pub use c_acknowledge_block::*; pub use c_actionbar::*; @@ -46,6 +46,7 @@ pub use c_block_update::*; pub use c_center_chunk::*; pub use c_change_difficulty::*; pub use c_chunk_data::*; +pub use c_close_container::*; pub use c_disguised_chat_message::*; pub use c_entity_animation::*; pub use c_entity_metadata::*; @@ -64,6 +65,7 @@ pub use c_player_info_update::*; pub use c_player_remove::*; pub use c_remove_entities::*; pub use c_set_container_content::*; +pub use c_set_container_property::*; pub use c_set_container_slot::*; pub use c_set_held_item::*; pub use c_set_title::*; @@ -77,5 +79,3 @@ pub use c_update_entity_pos::*; pub use c_update_entity_rot::*; pub use c_worldevent::*; pub use player_action::*; -pub use c_close_container::*; -pub use c_set_container_property::*; \ No newline at end of file diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index edec9f39e..a0c852b53 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -1,7 +1,9 @@ use pumpkin_core::text::TextComponent; use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait}; use pumpkin_inventory::WindowType; -use pumpkin_protocol::client::play::{CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot}; +use pumpkin_protocol::client::play::{ + CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot, +}; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::Item; @@ -83,17 +85,18 @@ impl super::Client { &item.into(), )) } - - /// The official Minecraft client is weird, and will always just close *any* window that is opened when this gets sent - pub fn close_container( - &mut self, - window_type: WindowType - ) { + + /// The official Minecraft client is weird, and will always just close *any* window that is opened when this gets sent + pub fn close_container(&mut self, window_type: WindowType) { self.send_packet(&CCloseContainer::new(window_type as u8)) } - - pub fn set_container_property(&mut self, window_type: WindowType, window_property: WindowProperty) { - let (id,value) = window_property.into_packet(); - self.send_packet(&CSetContainerProperty::new(window_type as u8,id,value)); + + pub fn set_container_property( + &mut self, + window_type: WindowType, + window_property: WindowProperty, + ) { + let (id, value) = window_property.into_packet(); + self.send_packet(&CSetContainerProperty::new(window_type as u8, id, value)); } } From e1a7d4e7eed37bba4606d974767f8b0ee91d05cc Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Fri, 23 Aug 2024 11:51:37 +0200 Subject: [PATCH 11/30] add serverbound packet SContainerClose --- pumpkin-inventory/src/lib.rs | 34 +++++++++++++++++++ pumpkin-protocol/src/server/play/mod.rs | 2 ++ .../src/server/play/s_close_container.rs | 8 +++++ pumpkin/src/client/player_packet.rs | 13 +++++++ 4 files changed, 57 insertions(+) create mode 100644 pumpkin-protocol/src/server/play/s_close_container.rs diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 0230ac189..3595bd6c2 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -52,3 +52,37 @@ impl WindowType { "WINDOW TITLE" } } +impl TryFrom for WindowType { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(WindowType::Generic9x1), + 1 => Ok(WindowType::Generic9x2), + 2 => Ok(WindowType::Generic9x3), + 3 => Ok(WindowType::Generic9x4), + 4 => Ok(WindowType::Generic9x5), + 5 => Ok(WindowType::Generic9x6), + 6 => Ok(WindowType::Generic3x3), + 7 => Ok(WindowType::Craft3x3), + 8 => Ok(WindowType::Anvil), + 9 => Ok(WindowType::Beacon), + 10 => Ok(WindowType::BlastFurnace), + 11 => Ok(WindowType::BrewingStand), + 12 => Ok(WindowType::CraftingTable), + 13 => Ok(WindowType::EnchantmentTable), + 14 => Ok(WindowType::Furnace), + 15 => Ok(WindowType::Grindstone), + 16 => Ok(WindowType::Hopper), + 17 => Ok(WindowType::Lectern), + 18 => Ok(WindowType::Loom), + 19 => Ok(WindowType::Merchant), + 20 => Ok(WindowType::ShulkerBox), + 21 => Ok(WindowType::SmithingTable), + 22 => Ok(WindowType::Smoker), + 23 => Ok(WindowType::CartographyTable), + 24 => Ok(WindowType::Stonecutter), + _ => Err(()), + } + } +} diff --git a/pumpkin-protocol/src/server/play/mod.rs b/pumpkin-protocol/src/server/play/mod.rs index c29a11775..2cccb9c2e 100644 --- a/pumpkin-protocol/src/server/play/mod.rs +++ b/pumpkin-protocol/src/server/play/mod.rs @@ -1,6 +1,7 @@ mod s_chat_command; mod s_chat_message; mod s_client_information; +mod s_close_container; mod s_confirm_teleport; mod s_interact; mod s_ping_request; @@ -17,6 +18,7 @@ mod s_use_item_on; pub use s_chat_command::*; pub use s_chat_message::*; pub use s_client_information::*; +pub use s_close_container::*; pub use s_confirm_teleport::*; pub use s_interact::*; pub use s_ping_request::*; diff --git a/pumpkin-protocol/src/server/play/s_close_container.rs b/pumpkin-protocol/src/server/play/s_close_container.rs new file mode 100644 index 000000000..5ba6a5698 --- /dev/null +++ b/pumpkin-protocol/src/server/play/s_close_container.rs @@ -0,0 +1,8 @@ +use pumpkin_macros::packet; +use serde::Serialize; + +#[derive(Serialize)] +#[packet(0x0F)] +pub struct SCloseContainer { + pub window_id: u8, +} diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 52d1defad..70522718a 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -9,6 +9,8 @@ use crate::{ use num_traits::FromPrimitive; use pumpkin_core::text::TextComponent; use pumpkin_entity::EntityId; +use pumpkin_inventory::WindowType; +use pumpkin_protocol::server::play::SCloseContainer; use pumpkin_protocol::{ client::play::{ Animation, CAcknowledgeBlockChange, CBlockUpdate, CEntityAnimation, CEntityVelocity, @@ -414,4 +416,15 @@ impl Client { inventory.set_slot(packet.slot as usize, packet.clicked_item.to_item(), false); } + + // TODO: + // This function will in the future be used to keep track of if the client is in a valid state. + // But this is not possible yet + pub fn handle_close_container(&mut self, packet: SCloseContainer) { + // window_id 0 represents both 9x1 Generic AND inventory here + let Ok(_window_type) = WindowType::try_from(packet.window_id) else { + self.kick("Invalid window ID"); + return; + }; + } } From ef21b3ae4071b5e61498f4fdb434b316e2198a76 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Fri, 23 Aug 2024 11:51:37 +0200 Subject: [PATCH 12/30] add serverbound packet SContainerClose --- pumpkin-protocol/src/server/play/s_close_container.rs | 4 ++-- pumpkin/src/client/mod.rs | 7 +++++-- pumpkin/src/client/player_packet.rs | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pumpkin-protocol/src/server/play/s_close_container.rs b/pumpkin-protocol/src/server/play/s_close_container.rs index 5ba6a5698..564151168 100644 --- a/pumpkin-protocol/src/server/play/s_close_container.rs +++ b/pumpkin-protocol/src/server/play/s_close_container.rs @@ -1,7 +1,7 @@ use pumpkin_macros::packet; -use serde::Serialize; +use serde::Deserialize; -#[derive(Serialize)] +#[derive(Deserialize)] #[packet(0x0F)] pub struct SCloseContainer { pub window_id: u8, diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 8edca66c7..71c49990d 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -28,8 +28,8 @@ use pumpkin_protocol::{ handshake::SHandShake, login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, play::{ - SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract, - SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition, + SChatCommand, SChatMessage, SClientInformationPlay, SCloseContainer, SConfirmTeleport, + SInteract, SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSwingArm, SUseItemOn, }, @@ -312,6 +312,9 @@ impl Client { SPlayPingRequest::PACKET_ID => { self.handle_play_ping_request(server, SPlayPingRequest::read(bytebuf).unwrap()) } + SCloseContainer::PACKET_ID => { + self.handle_close_container(server, SCloseContainer::read(bytebuf).unwrap()) + } _ => log::error!("Failed to handle player packet id {:#04x}", packet.id.0), } } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 70522718a..27fe5e94c 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -420,7 +420,7 @@ impl Client { // TODO: // This function will in the future be used to keep track of if the client is in a valid state. // But this is not possible yet - pub fn handle_close_container(&mut self, packet: SCloseContainer) { + pub fn handle_close_container(&mut self, _server: &mut Server, packet: SCloseContainer) { // window_id 0 represents both 9x1 Generic AND inventory here let Ok(_window_type) = WindowType::try_from(packet.window_id) else { self.kick("Invalid window ID"); From 51da48d937a7b63a98748bb58fd533e350259c87 Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 19:52:04 -0400 Subject: [PATCH 13/30] hourse -> Horse --- pumpkin-protocol/src/server/play/s_player_command.rs | 4 ++-- pumpkin/src/client/player_packet.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pumpkin-protocol/src/server/play/s_player_command.rs b/pumpkin-protocol/src/server/play/s_player_command.rs index 235baa6d5..9399e25ce 100644 --- a/pumpkin-protocol/src/server/play/s_player_command.rs +++ b/pumpkin-protocol/src/server/play/s_player_command.rs @@ -16,8 +16,8 @@ pub enum Action { LeaveBed, StartSprinting, StopSprinting, - StartHourseJump, - StopHourseJump, + StartHorseJump, + StopHorseJump, OpenVehicleInventory, StartFlyingElytra, } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 52d1defad..8e82c8935 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -187,8 +187,8 @@ impl Client { pumpkin_protocol::server::play::Action::LeaveBed => todo!(), pumpkin_protocol::server::play::Action::StartSprinting => player.sprinting = true, pumpkin_protocol::server::play::Action::StopSprinting => player.sprinting = false, - pumpkin_protocol::server::play::Action::StartHourseJump => todo!(), - pumpkin_protocol::server::play::Action::StopHourseJump => todo!(), + pumpkin_protocol::server::play::Action::StartHorseJump => todo!(), + pumpkin_protocol::server::play::Action::StopHorseJump => todo!(), pumpkin_protocol::server::play::Action::OpenVehicleInventory => todo!(), pumpkin_protocol::server::play::Action::StartFlyingElytra => {} // TODO } From 849438832477db2254d88bf5f9e6561d98e7e378 Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 19:56:17 -0400 Subject: [PATCH 14/30] entitiy -> entity --- pumpkin-protocol/src/client/play/c_entity_velocity.rs | 6 +++--- pumpkin-protocol/src/client/play/c_hurt_animation.rs | 6 +++--- pumpkin-protocol/src/client/play/c_remove_entities.rs | 8 ++++---- ...date_entitiy_pos_rot.rs => c_update_entity_pos_rot.rs} | 0 pumpkin-protocol/src/client/play/mod.rs | 3 +-- pumpkin-protocol/src/server/play/s_player_command.rs | 4 ++-- pumpkin/src/client/player_packet.rs | 4 ++-- 7 files changed, 15 insertions(+), 16 deletions(-) rename pumpkin-protocol/src/client/play/{c_update_entitiy_pos_rot.rs => c_update_entity_pos_rot.rs} (100%) diff --git a/pumpkin-protocol/src/client/play/c_entity_velocity.rs b/pumpkin-protocol/src/client/play/c_entity_velocity.rs index 842fc1cda..fcfdccd59 100644 --- a/pumpkin-protocol/src/client/play/c_entity_velocity.rs +++ b/pumpkin-protocol/src/client/play/c_entity_velocity.rs @@ -6,16 +6,16 @@ use crate::VarInt; #[derive(Serialize)] #[packet(0x5A)] pub struct CEntityVelocity<'a> { - entitiy_id: &'a VarInt, + entity_id: &'a VarInt, velocity_x: i16, velocity_y: i16, velocity_z: i16, } impl<'a> CEntityVelocity<'a> { - pub fn new(entitiy_id: &'a VarInt, velocity_x: f32, velocity_y: f32, velocity_z: f32) -> Self { + pub fn new(entity_id: &'a VarInt, velocity_x: f32, velocity_y: f32, velocity_z: f32) -> Self { Self { - entitiy_id, + entity_id, velocity_x: (velocity_x.clamp(-3.9, 3.9) * 8000.0) as i16, velocity_y: (velocity_y.clamp(-3.9, 3.9) * 8000.0) as i16, velocity_z: (velocity_z.clamp(-3.9, 3.9) * 8000.0) as i16, diff --git a/pumpkin-protocol/src/client/play/c_hurt_animation.rs b/pumpkin-protocol/src/client/play/c_hurt_animation.rs index 6166acbd3..2b1b04d8f 100644 --- a/pumpkin-protocol/src/client/play/c_hurt_animation.rs +++ b/pumpkin-protocol/src/client/play/c_hurt_animation.rs @@ -6,12 +6,12 @@ use crate::VarInt; #[derive(Serialize)] #[packet(0x24)] pub struct CHurtAnimation<'a> { - entitiy_id: &'a VarInt, + entity_id: &'a VarInt, yaw: f32, } impl<'a> CHurtAnimation<'a> { - pub fn new(entitiy_id: &'a VarInt, yaw: f32) -> Self { - Self { entitiy_id, yaw } + pub fn new(entity_id: &'a VarInt, yaw: f32) -> Self { + Self { entity_id, yaw } } } diff --git a/pumpkin-protocol/src/client/play/c_remove_entities.rs b/pumpkin-protocol/src/client/play/c_remove_entities.rs index 9e89ec260..1b16ad92e 100644 --- a/pumpkin-protocol/src/client/play/c_remove_entities.rs +++ b/pumpkin-protocol/src/client/play/c_remove_entities.rs @@ -7,14 +7,14 @@ use crate::VarInt; #[packet(0x42)] pub struct CRemoveEntities<'a> { count: VarInt, - entitiy_ids: &'a [VarInt], + entity_ids: &'a [VarInt], } impl<'a> CRemoveEntities<'a> { - pub fn new(entitiy_ids: &'a [VarInt]) -> Self { + pub fn new(entity_ids: &'a [VarInt]) -> Self { Self { - count: VarInt(entitiy_ids.len() as i32), - entitiy_ids, + count: VarInt(entity_ids.len() as i32), + entity_ids, } } } diff --git a/pumpkin-protocol/src/client/play/c_update_entitiy_pos_rot.rs b/pumpkin-protocol/src/client/play/c_update_entity_pos_rot.rs similarity index 100% rename from pumpkin-protocol/src/client/play/c_update_entitiy_pos_rot.rs rename to pumpkin-protocol/src/client/play/c_update_entity_pos_rot.rs diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 2e15aa978..a5a2a097b 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -31,7 +31,6 @@ mod c_subtitle; mod c_sync_player_position; mod c_system_chat_message; mod c_unload_chunk; -mod c_update_entitiy_pos_rot; mod c_update_entity_pos; mod c_update_entity_rot; mod c_worldevent; @@ -70,8 +69,8 @@ pub use c_subtitle::*; pub use c_sync_player_position::*; pub use c_system_chat_message::*; pub use c_unload_chunk::*; -pub use c_update_entitiy_pos_rot::*; pub use c_update_entity_pos::*; +pub use c_update_entity_pos_rot::*; pub use c_update_entity_rot::*; pub use c_worldevent::*; pub use player_action::*; diff --git a/pumpkin-protocol/src/server/play/s_player_command.rs b/pumpkin-protocol/src/server/play/s_player_command.rs index 9399e25ce..f6365cc02 100644 --- a/pumpkin-protocol/src/server/play/s_player_command.rs +++ b/pumpkin-protocol/src/server/play/s_player_command.rs @@ -5,7 +5,7 @@ use crate::{bytebuf::DeserializerError, ServerPacket, VarInt}; #[packet(0x25)] pub struct SPlayerCommand { - pub entitiy_id: VarInt, + pub entity_id: VarInt, pub action: VarInt, pub jump_boost: VarInt, } @@ -25,7 +25,7 @@ pub enum Action { impl ServerPacket for SPlayerCommand { fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Result { Ok(Self { - entitiy_id: bytebuf.get_var_int(), + entity_id: bytebuf.get_var_int(), action: bytebuf.get_var_int(), jump_boost: bytebuf.get_var_int(), }) diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 8e82c8935..a1b4273ec 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -176,7 +176,7 @@ impl Client { pub fn handle_player_command(&mut self, _server: &mut Server, command: SPlayerCommand) { let player = self.player.as_mut().unwrap(); - if command.entitiy_id != player.entity.entity_id.into() { + if command.entity_id != player.entity.entity_id.into() { return; } @@ -317,7 +317,7 @@ impl Client { } if config.swing {} } else { - self.kick("Interacted with invalid entitiy id") + self.kick("Interacted with invalid entity id") } } } From 7c30391e2c040c623e5909044e8c110288ff5ed5 Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 20:01:28 -0400 Subject: [PATCH 15/30] messge,messagee -> message --- pumpkin-protocol/src/client/play/c_system_chat_message.rs | 4 ++-- pumpkin-protocol/src/server/play/s_chat_message.rs | 4 ++-- pumpkin/src/client/mod.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pumpkin-protocol/src/client/play/c_system_chat_message.rs b/pumpkin-protocol/src/client/play/c_system_chat_message.rs index a0f2342d1..2751b40c7 100644 --- a/pumpkin-protocol/src/client/play/c_system_chat_message.rs +++ b/pumpkin-protocol/src/client/play/c_system_chat_message.rs @@ -4,12 +4,12 @@ use serde::Serialize; #[derive(Serialize)] #[packet(0x6C)] -pub struct CSystemChatMessge<'a> { +pub struct CSystemChatMessage<'a> { content: TextComponent<'a>, overlay: bool, } -impl<'a> CSystemChatMessge<'a> { +impl<'a> CSystemChatMessage<'a> { pub fn new(content: TextComponent<'a>, overlay: bool) -> Self { Self { content, overlay } } diff --git a/pumpkin-protocol/src/server/play/s_chat_message.rs b/pumpkin-protocol/src/server/play/s_chat_message.rs index e644a5bc3..9332a28f2 100644 --- a/pumpkin-protocol/src/server/play/s_chat_message.rs +++ b/pumpkin-protocol/src/server/play/s_chat_message.rs @@ -13,7 +13,7 @@ pub struct SChatMessage { pub timestamp: i64, pub salt: i64, pub signature: Option, - pub messagee_count: VarInt, + pub message_count: VarInt, pub acknowledged: FixedBitSet, } @@ -25,7 +25,7 @@ impl ServerPacket for SChatMessage { timestamp: bytebuf.get_i64(), salt: bytebuf.get_i64(), signature: bytebuf.get_option(|v| v.copy_to_bytes(256)), - messagee_count: bytebuf.get_var_int(), + message_count: bytebuf.get_var_int(), acknowledged: bytebuf.get_fixed_bitset(20), }) } diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 8edca66c7..cd8d39177 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -19,7 +19,7 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge}, + play::{CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPosition, CSystemChatMessage}, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, @@ -160,7 +160,7 @@ impl Client { 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())); + 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) { @@ -362,7 +362,7 @@ impl Client { } pub fn send_system_message(&mut self, text: TextComponent) { - self.send_packet(&CSystemChatMessge::new(text, false)); + self.send_packet(&CSystemChatMessage::new(text, false)); } /// Kicks the Client with a reason depending on the connection state From f56b566afb1bdc1e829487aa3359ddb279e4a3e9 Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 20:02:09 -0400 Subject: [PATCH 16/30] mailformed -> malformed --- pumpkin-protocol/src/lib.rs | 2 +- pumpkin-protocol/src/packet_decoder.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index f44a0a811..e79388163 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -143,7 +143,7 @@ pub enum PacketError { #[error("packet length is out of bounds")] OutOfBounds, #[error("malformed packet length VarInt")] - MailformedLength, + MalformedLength, } #[derive(Debug, PartialEq)] diff --git a/pumpkin-protocol/src/packet_decoder.rs b/pumpkin-protocol/src/packet_decoder.rs index 3d3e3449a..308716ccb 100644 --- a/pumpkin-protocol/src/packet_decoder.rs +++ b/pumpkin-protocol/src/packet_decoder.rs @@ -28,7 +28,7 @@ impl PacketDecoder { let packet_len = match VarInt::decode_partial(&mut r) { Ok(len) => len, Err(VarIntDecodeError::Incomplete) => return Ok(None), - Err(VarIntDecodeError::TooLarge) => Err(PacketError::MailformedLength)?, + Err(VarIntDecodeError::TooLarge) => Err(PacketError::MalformedLength)?, }; if !(0..=MAX_PACKET_SIZE).contains(&packet_len) { From dbe3964e4150cecc3a9431a231fd9b374f62658b Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 20:04:33 -0400 Subject: [PATCH 17/30] postion -> position --- pumpkin-protocol/src/client/play/c_sync_player_position.rs | 4 ++-- pumpkin/src/client/mod.rs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pumpkin-protocol/src/client/play/c_sync_player_position.rs b/pumpkin-protocol/src/client/play/c_sync_player_position.rs index 056214281..422160ad2 100644 --- a/pumpkin-protocol/src/client/play/c_sync_player_position.rs +++ b/pumpkin-protocol/src/client/play/c_sync_player_position.rs @@ -5,7 +5,7 @@ use crate::VarInt; #[derive(Serialize)] #[packet(0x40)] -pub struct CSyncPlayerPostion { +pub struct CSyncPlayerPosition { x: f64, y: f64, z: f64, @@ -15,7 +15,7 @@ pub struct CSyncPlayerPostion { teleport_id: VarInt, } -impl CSyncPlayerPostion { +impl CSyncPlayerPosition { pub fn new( x: f64, y: f64, diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index cd8d39177..9cdccef3d 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -19,7 +19,10 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPosition, CSystemChatMessage}, + play::{ + CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPosition, + CSystemChatMessage, + }, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, From 4240df86b761404e238cd5d7e54855ee609a698a Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Wed, 21 Aug 2024 18:18:43 -0400 Subject: [PATCH 18/30] cargo fmt --- pumpkin-protocol/src/client/play/mod.rs | 1 + pumpkin/src/client/mod.rs | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index a5a2a097b..d5064aae4 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -32,6 +32,7 @@ mod c_sync_player_position; mod c_system_chat_message; mod c_unload_chunk; mod c_update_entity_pos; +mod c_update_entity_pos_rot; mod c_update_entity_rot; mod c_worldevent; mod player_action; diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 9cdccef3d..7793ec46d 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -19,10 +19,7 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{ - CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPosition, - CSystemChatMessage, - }, + play::{CGameEvent, CPlayDisconnect, CSyncPlayerPosition, CSystemChatMessage}, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, From fa1ca0782e3f6418706e66ca3137da4b5f90a0f9 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sat, 24 Aug 2024 11:17:36 +0200 Subject: [PATCH 19/30] Handle CTRL-C shutdown --- Cargo.lock | 38 ++++++++++++++++++++++++++++++++ pumpkin/Cargo.toml | 2 ++ pumpkin/src/commands/cmd_stop.rs | 10 +++++++-- pumpkin/src/main.rs | 13 +++++++++++ 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d01e7e507..6e165f7d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,6 +154,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "cipher" version = "0.4.4" @@ -267,6 +273,16 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + [[package]] name = "der" version = "0.7.9" @@ -823,6 +839,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -1066,6 +1094,7 @@ dependencies = [ "base64", "bytes", "crossbeam-channel", + "ctrlc", "dhat", "digest 0.11.0-pre.9", "hmac", @@ -2065,6 +2094,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 97b0b3a4a..1bd1fe81c 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -33,6 +33,8 @@ num-traits = "0.2" num-derive = "0.4" num-bigint = "0.4.6" +ctrlc = "3.4" + # encryption rsa = "0.9.6" rsa-der = "0.3.0" diff --git a/pumpkin/src/commands/cmd_stop.rs b/pumpkin/src/commands/cmd_stop.rs index 60f425b76..81bd07ea9 100644 --- a/pumpkin/src/commands/cmd_stop.rs +++ b/pumpkin/src/commands/cmd_stop.rs @@ -1,3 +1,6 @@ +use pumpkin_core::text::color::NamedColor; +use pumpkin_core::text::TextComponent; + use crate::commands::tree::CommandTree; use crate::commands::tree_builder::require; @@ -7,7 +10,10 @@ const DESCRIPTION: &str = "Stop the server."; pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { CommandTree::new(NAMES, DESCRIPTION).with_child( - require(&|sender| sender.permission_lvl() >= 4) - .execute(&|_sender, _args| std::process::exit(0)), + require(&|sender| sender.permission_lvl() >= 4).execute(&|sender, _args| { + sender + .send_message(TextComponent::text("Stopping Server").color_named(NamedColor::Red)); + std::process::exit(0) + }), ) } diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index 69f839c91..42ecb4423 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -31,6 +31,8 @@ static ALLOC: dhat::Alloc = dhat::Alloc; #[cfg(not(target_os = "wasi"))] fn main() -> io::Result<()> { + use pumpkin_core::text::{color::NamedColor, TextComponent}; + #[cfg(feature = "dhat-heap")] let _profiler = dhat::Profiler::new_heap(); #[cfg(feature = "dhat-heap")] @@ -39,6 +41,17 @@ fn main() -> io::Result<()> { .enable_all() .build() .unwrap(); + + ctrlc::set_handler(|| { + log::warn!( + "{}", + TextComponent::text("Stopping Server") + .color_named(NamedColor::Red) + .to_pretty_console() + ); + std::process::exit(0); + }) + .unwrap(); // ensure rayon is built outside of tokio scope rayon::ThreadPoolBuilder::new().build_global().unwrap(); rt.block_on(async { From 303594d908660e8bb2cc9cb16a6665afa568afbe Mon Sep 17 00:00:00 2001 From: Erb3 <49862976+Erb3@users.noreply.github.com> Date: Sat, 24 Aug 2024 13:18:09 +0200 Subject: [PATCH 20/30] refactor(docker): move to alpine for smaller image --- Dockerfile | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/Dockerfile b/Dockerfile index ea678f677..a3dd5b33b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,13 @@ -FROM rust:1.79 AS builder -WORKDIR /usr/src/pumpkin -COPY . . -RUN ls -RUN cargo install --path ./pumpkin - -FROM rust +FROM rust:1-alpine3.19 AS builder +ENV RUSTFLAGS="-C target-feature=-crt-static" +RUN apk add --no-cache musl-dev WORKDIR /pumpkin -RUN apt update && apt-get install -y libssl-dev pkg-config ca-certificates && rm -rf /var/lib/apt/lists/* -COPY --from=builder /usr/local/cargo/bin/pumpkin /pumpkin/pumpkin -CMD ["/pumpkin/pumpkin"] +COPY . /pumpkin +RUN cargo build --release +RUN strip target/release/pumpkin -# FROM rust:1.79-alpine AS builder -# WORKDIR /usr/src/pumpkin -# COPY . . -# RUN apk add openssl-dev libssl3 ca-certificates pkgconfig musl-dev -# RUN cargo install --path ./pumpkin - -# FROM rust:1.79-alpine -# WORKDIR /pumpkin -# RUN apk add openssl ca-certificates pkgconfig -# COPY --from=builder /usr/local/cargo/bin/pumpkin /pumpkin/pumpkin -# CMD ["/pumpkin/pumpkin"] - -#docker run --rm -v "./world:/pumpkin/world" pumpkin +FROM alpine:3.19 +WORKDIR /pumpkin +RUN apk add --no-cache libgcc +COPY --from=builder /pumpkin/target/release/pumpkin /pumpkin/pumpkin +ENTRYPOINT ["/pumpkin/pumpkin"] From a97551583b5c996bdd7b86988cc328909e8f266e Mon Sep 17 00:00:00 2001 From: Erb3 <49862976+Erb3@users.noreply.github.com> Date: Sat, 24 Aug 2024 13:28:04 +0200 Subject: [PATCH 21/30] feat(docker): enable target-cpu=native --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a3dd5b33b..69631ab81 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM rust:1-alpine3.19 AS builder -ENV RUSTFLAGS="-C target-feature=-crt-static" +ENV RUSTFLAGS="-C target-feature=-crt-static -C target-cpu=native" RUN apk add --no-cache musl-dev WORKDIR /pumpkin COPY . /pumpkin From c7f15dee3d4906e27446409c0243e68943f68783 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sat, 24 Aug 2024 14:51:43 +0200 Subject: [PATCH 22/30] Refactor Client --- pumpkin/src/client/client_packet.rs | 5 +- pumpkin/src/client/container.rs | 16 +-- pumpkin/src/client/mod.rs | 140 ++++-------------- pumpkin/src/client/player_packet.rs | 122 ++++++++-------- pumpkin/src/commands/arg_player.rs | 13 +- pumpkin/src/commands/mod.rs | 8 +- pumpkin/src/entity/player.rs | 129 ++++++++++++++++- pumpkin/src/main.rs | 58 +++++--- pumpkin/src/server.rs | 212 ++++++++++++++-------------- 9 files changed, 373 insertions(+), 330 deletions(-) diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index 065cf2c4e..442565b5b 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -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; } } diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index b8a242dbd..df188212f 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -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, @@ -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, @@ -37,14 +39,12 @@ impl super::Client { items: Option>>, carried_item: Option<&'a Item>, ) { - let player = self.player.as_ref().unwrap(); - let slots: Vec = { 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| { @@ -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( @@ -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, diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 7793ec46d..5146a31f2 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -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, @@ -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, @@ -57,9 +47,22 @@ pub struct PlayerConfig { pub server_listing: bool, } -pub struct Client { - pub player: Option, +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, pub config: Option, @@ -75,6 +78,8 @@ pub struct Client { enc: PacketEncoder, dec: PacketDecoder, pub client_packets_queue: VecDeque, + + pub make_player: bool, } impl Client { @@ -86,7 +91,6 @@ impl Client { brand: None, token, address, - player: None, connection_state: ConnectionState::HandShake, connection, enc: PacketEncoder::default(), @@ -94,6 +98,7 @@ impl Client { encryption: true, closed: false, client_packets_queue: VecDeque::new(), + make_player: false, } } @@ -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(&mut self, packet: &P) { self.enc @@ -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() { @@ -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; @@ -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; @@ -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()), @@ -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); @@ -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()); diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index a1b4273ec..993b20f56 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -2,7 +2,7 @@ use std::f32::consts::PI; use crate::{ commands::{handle_command, CommandSender}, - entity::player::{ChatMode, GameMode, Hand}, + entity::player::{ChatMode, GameMode, Hand, Player}, server::Server, util::math::wrap_degrees, }; @@ -26,28 +26,28 @@ use pumpkin_protocol::{ use pumpkin_world::block::BlockFace; use pumpkin_world::global_registry; -use super::{Client, PlayerConfig}; +use super::PlayerConfig; fn modulus(a: f32, b: f32) -> f32 { ((a % b) + b) % b } /// Handles all Play Packets send by a real Player -impl Client { +impl Player { pub fn handle_confirm_teleport( &mut self, _server: &mut Server, confirm_teleport: SConfirmTeleport, ) { - let player = self.player.as_mut().unwrap(); - if let Some(id) = player.awaiting_teleport.clone() { + if let Some(id) = self.awaiting_teleport.clone() { if id == confirm_teleport.teleport_id { } else { log::warn!("Teleport id does not match, Weird but okay"); } - player.awaiting_teleport = None; + self.awaiting_teleport = None; } else { - self.kick("Send Teleport confirm, but we did not teleport") + self.client + .kick("Send Teleport confirm, but we did not teleport") } } @@ -61,11 +61,10 @@ impl Client { pub fn handle_position(&mut self, server: &mut Server, position: SPlayerPosition) { if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() { - self.kick("Invalid movement"); + self.kick(TextComponent::text("Invalid movement")); return; } - let player = self.player.as_mut().unwrap(); - let entity = &mut player.entity; + let entity = &mut self.entity; entity.lastx = entity.x; entity.lasty = entity.y; entity.lastz = entity.z; @@ -75,7 +74,7 @@ impl Client { // TODO: teleport when moving > 8 block // send new position to all other players - let on_ground = player.on_ground; + let on_ground = self.on_ground; let entity_id = entity.entity_id; let (x, lastx) = (entity.x, entity.lastx); let (y, lasty) = (entity.y, entity.lasty); @@ -102,15 +101,14 @@ impl Client { || position_rotation.feet_y.is_nan() || position_rotation.z.is_nan() { - self.kick("Invalid movement"); + self.kick(TextComponent::text("Invalid movement")); return; } if !position_rotation.yaw.is_finite() || !position_rotation.pitch.is_finite() { - self.kick("Invalid rotation"); + self.kick(TextComponent::text("Invalid rotation")); return; } - let player = self.player.as_mut().unwrap(); - let entity = &mut player.entity; + let entity = &mut self.entity; entity.lastx = entity.x; entity.lasty = entity.y; @@ -122,7 +120,7 @@ impl Client { entity.pitch = wrap_degrees(position_rotation.pitch).clamp(-90.0, 90.0) % 360.0; // send new position to all other players - let on_ground = player.on_ground; + let on_ground = self.on_ground; let entity_id = entity.entity_id; let (x, lastx) = (entity.x, entity.lastx); let (y, lasty) = (entity.y, entity.lasty); @@ -148,15 +146,14 @@ impl Client { pub fn handle_rotation(&mut self, server: &mut Server, rotation: SPlayerRotation) { if !rotation.yaw.is_finite() || !rotation.pitch.is_finite() { - self.kick("Invalid rotation"); + self.kick(TextComponent::text("Invalid rotation")); return; } - let player = self.player.as_mut().unwrap(); - let entity = &mut player.entity; + let entity = &mut self.entity; entity.yaw = wrap_degrees(rotation.yaw) % 360.0; entity.pitch = wrap_degrees(rotation.pitch).clamp(-90.0, 90.0) % 360.0; // send new position to all other players - let on_ground = player.on_ground; + let on_ground = self.on_ground; let entity_id = entity.entity_id; let yaw = modulus(entity.yaw * 256.0 / 360.0, 256.0); let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0); @@ -174,26 +171,24 @@ impl Client { } pub fn handle_player_command(&mut self, _server: &mut Server, command: SPlayerCommand) { - let player = self.player.as_mut().unwrap(); - - if command.entity_id != player.entity.entity_id.into() { + if command.entity_id != self.entity.entity_id.into() { return; } if let Some(action) = Action::from_i32(command.action.0) { match action { - pumpkin_protocol::server::play::Action::StartSneaking => player.sneaking = true, - pumpkin_protocol::server::play::Action::StopSneaking => player.sneaking = false, + pumpkin_protocol::server::play::Action::StartSneaking => self.sneaking = true, + pumpkin_protocol::server::play::Action::StopSneaking => self.sneaking = false, pumpkin_protocol::server::play::Action::LeaveBed => todo!(), - pumpkin_protocol::server::play::Action::StartSprinting => player.sprinting = true, - pumpkin_protocol::server::play::Action::StopSprinting => player.sprinting = false, + pumpkin_protocol::server::play::Action::StartSprinting => self.sprinting = true, + pumpkin_protocol::server::play::Action::StopSprinting => self.sprinting = false, pumpkin_protocol::server::play::Action::StartHorseJump => todo!(), pumpkin_protocol::server::play::Action::StopHorseJump => todo!(), pumpkin_protocol::server::play::Action::OpenVehicleInventory => todo!(), pumpkin_protocol::server::play::Action::StartFlyingElytra => {} // TODO } } else { - self.kick("Invalid player command") + self.kick(TextComponent::text("Invalid player command")) } } @@ -202,10 +197,9 @@ impl Client { Hand::Main => Animation::SwingMainArm, Hand::Off => Animation::SwingOffhand, }; - let player = self.player.as_mut().unwrap(); - let id = player.entity_id(); + let id = self.entity_id(); server.broadcast_packet_except( - &[&self.token], + &[&self.client.token], &CEntityAnimation::new(id.into(), animation as u8), ) } @@ -215,12 +209,12 @@ impl Client { let message = chat_message.message; if message.len() > 256 { - self.kick("Oversized message"); + self.kick(TextComponent::text("Oversized message")); return; } // TODO: filter message & validation - let gameprofile = self.gameprofile.as_ref().unwrap(); + let gameprofile = self.client.gameprofile.as_ref().unwrap(); server.broadcast_packet( self, @@ -256,7 +250,7 @@ impl Client { _server: &mut Server, client_information: SClientInformationPlay, ) { - self.config = Some(PlayerConfig { + 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(), @@ -275,18 +269,16 @@ impl Client { // TODO: do validation and stuff let config = &server.advanced_config.pvp; if config.enabled { - let attacked_client = server.get_by_entityid(self, entity_id.0 as EntityId); - let attacker_player = self.player.as_mut().unwrap(); - attacker_player.sneaking = interact.sneaking; - if let Some(mut client) = attacked_client { - let token = client.token.clone(); - let player = client.player.as_mut().unwrap(); + 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 = attacker_player.entity.yaw; + let yaw = self.entity.yaw; let strength = 1.0; player.knockback( strength * 0.5, @@ -299,25 +291,25 @@ impl Client { player.velocity.y as f32, player.velocity.z as f32, ); - attacker_player.velocity = attacker_player.velocity.multiply(0.6, 1.0, 0.6); + self.velocity = self.velocity.multiply(0.6, 1.0, 0.6); player.velocity = velo; - client.send_packet(packet); + player.client.send_packet(packet); } if config.hurt_animation { // TODO // thats how we prevent borrow errors :c - let packet = &CHurtAnimation::new(&entity_id, attacker_player.entity.yaw); - self.send_packet(packet); - client.send_packet(packet); + let packet = &CHurtAnimation::new(&entity_id, self.entity.yaw); + self.client.send_packet(packet); + player.client.send_packet(packet); server.broadcast_packet_except( - &[self.token.as_ref(), token.as_ref()], + &[self.client.token.as_ref(), token.as_ref()], &CHurtAnimation::new(&entity_id, 10.0), ) } if config.swing {} } else { - self.kick("Interacted with invalid entity id") + self.kick(TextComponent::text("Interacted with invalid entity id")) } } } @@ -326,9 +318,8 @@ impl Client { match Status::from_i32(player_action.status.0).unwrap() { Status::StartedDigging => { // TODO: do validation - let player = self.player.as_mut().unwrap(); // TODO: Config - if player.gamemode == GameMode::Creative { + if self.gamemode == GameMode::Creative { let location = player_action.location; // Block break & block break sound // TODO: currently this is always dirt replace it @@ -338,8 +329,7 @@ impl Client { } } Status::CancelledDigging => { - let player = self.player.as_mut().unwrap(); - player.current_block_destroy_stage = 0; + self.current_block_destroy_stage = 0; } Status::FinishedDigging => { // TODO: do validation @@ -350,7 +340,8 @@ impl Client { // AIR server.broadcast_packet(self, &CBlockUpdate::new(location, 0.into())); // TODO: Send this every tick - self.send_packet(&CAcknowledgeBlockChange::new(player_action.sequence)); + self.client + .send_packet(&CAcknowledgeBlockChange::new(player_action.sequence)); } Status::DropItemStack => { dbg!("todo"); @@ -368,16 +359,18 @@ impl Client { } pub fn handle_play_ping_request(&mut self, _server: &mut Server, request: SPlayPingRequest) { - self.send_packet(&CPingResponse::new(request.payload)); + self.client + .send_packet(&CPingResponse::new(request.payload)); } pub fn handle_use_item_on(&mut self, server: &mut Server, use_item_on: SUseItemOn) { - self.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence)); + self.client + .send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence)); let location = use_item_on.location; let face = BlockFace::from_i32(use_item_on.face.0).unwrap(); let location = WorldPosition(location.0 + face.to_offset()); - if let Some(item) = self.player.as_ref().unwrap().inventory.held_item() { + 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"); @@ -398,20 +391,19 @@ impl Client { pub fn handle_set_held_item(&mut self, _server: &mut Server, held: SSetHeldItem) { let slot = held.slot; if !(0..=8).contains(&slot) { - self.kick("Invalid held slot") + self.kick(TextComponent::text("Invalid held slot")) } - let player = self.player.as_mut().unwrap(); - player.inventory.set_selected(slot as usize); + self.inventory.set_selected(slot as usize); } pub fn handle_set_creative_slot(&mut self, _server: &mut Server, packet: SSetCreativeSlot) { - let player = self.player.as_mut().unwrap(); - if player.gamemode != GameMode::Creative { - self.kick("Invalid action, you can only do that if you are in creative"); + if self.gamemode != GameMode::Creative { + self.kick(TextComponent::text( + "Invalid action, you can only do that if you are in creative", + )); return; } - let inventory = &mut player.inventory; - - inventory.set_slot(packet.slot as usize, packet.clicked_item.to_item(), false); + self.inventory + .set_slot(packet.slot as usize, packet.clicked_item.to_item(), false); } } diff --git a/pumpkin/src/commands/arg_player.rs b/pumpkin/src/commands/arg_player.rs index a8ee8f460..6a52c5510 100644 --- a/pumpkin/src/commands/arg_player.rs +++ b/pumpkin/src/commands/arg_player.rs @@ -1,4 +1,3 @@ -use crate::client::Client; use crate::commands::dispatcher::InvalidTreeError; use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError; use crate::commands::tree::{ConsumedArgs, RawArgs}; @@ -16,8 +15,8 @@ pub fn consume_arg_player(src: &CommandSender, args: &mut RawArgs) -> Option None, // todo: implement all players target selector _ => { // todo: implement any other player than sender - if let Player(client) = src { - if let Some(profile) = &client.gameprofile { + if let Player(player) = src { + if let Some(profile) = &player.client.gameprofile { if profile.name == s { return Some(s.into()); }; @@ -33,7 +32,7 @@ pub fn parse_arg_player<'a>( src: &'a mut CommandSender, arg_name: &str, consumed_args: &ConsumedArgs, -) -> Result<&'a mut Client, InvalidTreeError> { +) -> Result<&'a mut crate::entity::player::Player, InvalidTreeError> { let s = consumed_args .get(arg_name) .ok_or(InvalidConsumptionError(None))? @@ -46,10 +45,10 @@ pub fn parse_arg_player<'a>( "@a" | "@e" => Err(InvalidConsumptionError(Some(s.into()))), // todo: implement all players target selector _ => { // todo: implement any other player than sender - if let Player(client) = src { - if let Some(profile) = &client.gameprofile { + if let Player(player) = src { + if let Some(profile) = &player.client.gameprofile { if profile.name == s { - return Ok(client); + return Ok(player); }; }; }; diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index 7ca503fd5..a827303ce 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -2,8 +2,8 @@ use pumpkin_core::text::TextComponent; use std::collections::HashMap; use std::sync::OnceLock; -use crate::client::Client; use crate::commands::dispatcher::CommandDispatcher; +use crate::entity::player::Player; mod arg_player; mod cmd_gamemode; mod cmd_help; @@ -17,7 +17,7 @@ mod tree_format; pub enum CommandSender<'a> { Rcon(&'a mut Vec), Console, - Player(&'a mut Client), + Player(&'a mut Player), } impl<'a> CommandSender<'a> { @@ -45,9 +45,9 @@ impl<'a> CommandSender<'a> { CommandSender::Rcon(_) => true, } } - pub fn as_mut_player(&mut self) -> Option<&mut Client> { + pub fn as_mut_player(&mut self) -> Option<&mut Player> { match self { - CommandSender::Player(client) => Some(client), + CommandSender::Player(player) => Some(player), CommandSender::Console => None, CommandSender::Rcon(_) => None, } diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 939c7b8e2..935ba7cd4 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -1,13 +1,27 @@ use std::str::FromStr; use num_derive::{FromPrimitive, ToPrimitive}; +use num_traits::ToPrimitive; +use pumpkin_core::text::TextComponent; use pumpkin_entity::{entity_type::EntityType, Entity, EntityId}; use pumpkin_inventory::player::PlayerInventory; -use pumpkin_protocol::VarInt; +use pumpkin_protocol::{ + bytebuf::packet_id::Packet, + client::play::{CGameEvent, CPlayDisconnect, CSyncPlayerPosition, CSystemChatMessage}, + server::play::{ + SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract, + SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, + SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSwingArm, SUseItemOn, + }, + ConnectionState, RawPacket, ServerPacket, VarInt, +}; use pumpkin_world::vector3::Vector3; use serde::{Deserialize, Serialize}; +use crate::{client::Client, server::Server}; + pub struct Player { + pub client: Client, pub entity: Entity, // current gamemode pub gamemode: GameMode, @@ -34,8 +48,9 @@ pub struct Player { } impl Player { - pub fn new(entity_id: EntityId, gamemode: GameMode) -> Self { + pub fn new(client: Client, entity_id: EntityId, gamemode: GameMode) -> Self { Self { + client, entity: Entity::new(entity_id, EntityType::Player), on_ground: false, awaiting_teleport: None, @@ -77,15 +92,121 @@ impl Player { var7.z / 2.0 - var8.z, ); } + + pub fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) { + // TODO + let id = 0; + let entity = &mut self.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; + self.awaiting_teleport = Some(id.into()); + self.client + .send_packet(&CSyncPlayerPosition::new(x, y, z, yaw, pitch, 0, id.into())); + } + + /// Kicks the Client with a reason depending on the connection state + pub fn kick(&mut self, reason: TextComponent) { + assert!(self.client.connection_state == ConnectionState::Play); + dbg!(&reason); + self.client + .try_send_packet(&CPlayDisconnect::new(reason)) + .unwrap_or_else(|_| self.client.close()); + + self.client.close() + } + + pub fn update_health(&mut self, health: f32, food: i32, food_saturation: f32) { + self.health = health; + self.food = food; + self.food_saturation = food_saturation; + } + + pub fn set_gamemode(&mut self, gamemode: GameMode) { + self.gamemode = gamemode; + self.client + .send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); + } + + pub fn send_system_message(&mut self, text: TextComponent) { + self.client + .send_packet(&CSystemChatMessage::new(text, false)); + } } -#[derive(FromPrimitive)] +impl Player { + pub fn process_packets(&mut self, server: &mut Server) { + let mut i = 0; + while i < self.client.client_packets_queue.len() { + let mut packet = self.client.client_packets_queue.remove(i).unwrap(); + self.handle_play_packet(server, &mut packet); + i += 1; + } + } + + 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), + } + } +} + +#[derive(FromPrimitive, Clone)] pub enum Hand { Main, Off, } -#[derive(FromPrimitive)] +#[derive(FromPrimitive, Clone)] pub enum ChatMode { Enabled, CommandsOnly, diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index 316b2374e..3d0f2b368 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -31,6 +31,7 @@ static ALLOC: dhat::Alloc = dhat::Alloc; #[cfg(not(target_os = "wasi"))] fn main() -> io::Result<()> { + use entity::player::Player; use pumpkin_core::text::{color::NamedColor, TextComponent}; #[cfg(feature = "dhat-heap")] @@ -93,7 +94,8 @@ fn main() -> io::Result<()> { let use_console = advanced_configuration.commands.use_console; let rcon = advanced_configuration.rcon.clone(); - let mut connections: HashMap>> = HashMap::new(); + let mut clients: HashMap = HashMap::new(); + let mut players: HashMap, Rc>> = HashMap::new(); let mut server = Server::new((basic_config, advanced_configuration)); log::info!("Started Server took {}ms", time.elapsed().as_millis()); @@ -160,30 +162,50 @@ fn main() -> io::Result<()> { Interest::READABLE.add(Interest::WRITABLE), )?; let rc_token = Rc::new(token); - let client = Rc::new(RefCell::new(Client::new( - Rc::clone(&rc_token), - connection, - addr, - ))); - server.add_client(rc_token, Rc::clone(&client)); - connections.insert(token, client); + let client = Client::new(Rc::clone(&rc_token), connection, addr); + clients.insert(token, client); }, token => { - // Maybe received an event for a TCP connection. - let done = if let Some(client) = connections.get_mut(&token) { - let mut client = client.borrow_mut(); - client.poll(&mut server, event).await; - client.closed + // Poll Players + let done = if let Some(player) = players.get_mut(&token) { + let mut player = player.borrow_mut(); + player.client.poll(event).await; + player.process_packets(&mut server); + player.client.closed } else { - // Sporadic events happen, we can safely ignore them. false }; + if done { - if let Some(client) = connections.remove(&token) { - server.remove_client(&token); - let mut client = client.borrow_mut(); - poll.registry().deregister(&mut client.connection)?; + if let Some(player) = players.remove(&token) { + server.remove_player(&token); + let mut player = player.borrow_mut(); + poll.registry().deregister(&mut player.client.connection)?; + } + } + + // Poll current Clients (non players) + // Maybe received an event for a TCP connection. + let (done, make_player) = if let Some(client) = clients.get_mut(&token) { + client.poll(event).await; + client.process_packets(&mut server).await; + (client.closed, client.make_player) + } else { + // Sporadic events happen, we can safely ignore them. + (false, false) + }; + if done || make_player { + if let Some(mut client) = clients.remove(&token) { + if done { + poll.registry().deregister(&mut client.connection)?; + } else if make_player { + let token = client.token.clone(); + let player = server.add_player(token.clone(), client); + players.insert(token, player.clone()); + let mut player = player.borrow_mut(); + server.spawn_player(&mut player).await; + } } } } diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 0316a34b8..c2aa939d6 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -13,7 +13,7 @@ use std::{ use base64::{engine::general_purpose, Engine}; use image::GenericImageView; -use mio::{event::Event, Poll, Token}; +use mio::Token; use num_traits::ToPrimitive; use pumpkin_entity::{entity_type::EntityType, EntityId}; use pumpkin_protocol::{ @@ -60,7 +60,7 @@ pub struct Server { /// Cache the registry so we don't have to parse it every time a player joins pub cached_registry: Vec, - pub current_clients: HashMap, Rc>>, + pub current_players: HashMap, Rc>>, // TODO: replace with HashMap entity_id: AtomicI32, // TODO: place this into every world @@ -115,54 +115,48 @@ impl Server { status_response, status_response_json, public_key_der, - current_clients: HashMap::new(), + current_players: HashMap::new(), base_config: config.0, auth_client, advanced_config: config.1, } } - // Returns Tokens to remove - pub async fn poll(&mut self, client: &mut Client, _poll: &Poll, event: &Event) { - // TODO: Poll players in every world - client.poll(self, event).await - } - - pub fn add_client(&mut self, token: Rc, client: Rc>) { - self.current_clients.insert(token, client); - } - - pub fn remove_client(&mut self, token: &Token) { - let client = self.current_clients.remove(token).unwrap(); - let client = client.borrow(); - // despawn the player - // todo: put this into the entitiy struct - if client.is_player() { - let id = client.player.as_ref().unwrap().entity_id(); - let uuid = client.gameprofile.as_ref().unwrap().id; - self.broadcast_packet_except( - &[&client.token], - &CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]), - ); - self.broadcast_packet_except(&[&client.token], &CRemoveEntities::new(&[id.into()])) - } - } - - // here is where the magic happens - // TODO: do this in a world - pub async fn spawn_player(&mut self, client: &mut Client) { - // This code follows the vanilla packet order + pub fn add_player(&mut self, token: Rc, client: Client) -> Rc> { let entity_id = self.new_entity_id(); let gamemode = match self.base_config.default_gamemode { GameMode::Undefined => GameMode::Survival, game_mode => game_mode, }; + let player = Rc::new(RefCell::new(Player::new(client, entity_id, gamemode))); + self.current_players.insert(token, player.clone()); + player + } + + pub fn remove_player(&mut self, token: &Token) { + let player = self.current_players.remove(token).unwrap(); + let player = player.as_ref().borrow(); + // despawn the player + // todo: put this into the entitiy struct + let id = player.entity_id(); + let uuid = player.client.gameprofile.as_ref().unwrap().id; + self.broadcast_packet_except( + &[&player.client.token], + &CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]), + ); + self.broadcast_packet_except(&[&player.client.token], &CRemoveEntities::new(&[id.into()])) + } + + // here is where the magic happens + // TODO: do this in a world + pub async fn spawn_player(&mut self, player: &mut Player) { + // This code follows the vanilla packet order + let entity_id = player.entity_id(); + let gamemode = player.gamemode; log::debug!("spawning player, entity id {}", entity_id); - let player = Player::new(entity_id, gamemode); - client.player = Some(player); // login packet for our new player - client.send_packet(&CLogin::new( + player.client.send_packet(&CLogin::new( entity_id, self.base_config.hardcore, &["minecraft:overworld"], @@ -185,7 +179,9 @@ impl Server { )); dbg!("sending abilities"); // player abilities - client.send_packet(&CPlayerAbilities::new(0x02, 0.1, 0.1)); + player + .client + .send_packet(&CPlayerAbilities::new(0x02, 0.1, 0.1)); // teleport let x = 10.0; @@ -193,12 +189,12 @@ impl Server { let z = 10.0; let yaw = 10.0; let pitch = 10.0; - client.teleport(x, y, z, 10.0, 10.0); - let gameprofile = client.gameprofile.as_ref().unwrap(); + player.teleport(x, y, z, 10.0, 10.0); + let gameprofile = player.client.gameprofile.as_ref().unwrap(); // first send info update to our new player, So he can see his Skin // also send his info to everyone else self.broadcast_packet( - client, + player, &CPlayerInfoUpdate::new( 0x01 | 0x08, &[pumpkin_protocol::client::play::Player { @@ -216,32 +212,36 @@ impl Server { // here we send all the infos of already joined players let mut entries = Vec::new(); - for (_, client) in self.current_clients.iter().filter(|c| c.0 != &client.token) { - let client = client.borrow(); - if client.is_player() { - let gameprofile = client.gameprofile.as_ref().unwrap(); - entries.push(pumpkin_protocol::client::play::Player { - uuid: gameprofile.id, - actions: vec![ - PlayerAction::AddPlayer { - name: gameprofile.name.clone(), - properties: gameprofile.properties.clone(), - }, - PlayerAction::UpdateListed { listed: true }, - ], - }) - } + for (_, playerr) in self + .current_players + .iter() + .filter(|c| c.0 != &player.client.token) + { + let playerr = playerr.as_ref().borrow(); + let gameprofile = &playerr.client.gameprofile.as_ref().unwrap(); + entries.push(pumpkin_protocol::client::play::Player { + uuid: gameprofile.id, + actions: vec![ + PlayerAction::AddPlayer { + name: gameprofile.name.clone(), + properties: gameprofile.properties.clone(), + }, + PlayerAction::UpdateListed { listed: true }, + ], + }) } - client.send_packet(&CPlayerInfoUpdate::new(0x01 | 0x08, &entries)); + player + .client + .send_packet(&CPlayerInfoUpdate::new(0x01 | 0x08, &entries)); // Start waiting for level chunks - client.send_packet(&CGameEvent::new(13, 0.0)); + player.client.send_packet(&CGameEvent::new(13, 0.0)); - let gameprofile = client.gameprofile.as_ref().unwrap(); + let gameprofile = player.client.gameprofile.as_ref().unwrap(); // spawn player for every client self.broadcast_packet_except( - &[&client.token], + &[&player.client.token], // TODO: add velo &CSpawnEntity::new( entity_id.into(), @@ -260,33 +260,31 @@ impl Server { ), ); // spawn players for our client - let token = client.token.clone(); - for (_, existing_client) in self.current_clients.iter().filter(|c| c.0 != &token) { - let existing_client = existing_client.borrow(); - if let Some(player) = &existing_client.player { - let entity = &player.entity; - let gameprofile = existing_client.gameprofile.as_ref().unwrap(); - client.send_packet(&CSpawnEntity::new( - player.entity_id().into(), - UUID(gameprofile.id), - EntityType::Player.to_i32().unwrap().into(), - entity.x, - entity.y, - entity.z, - entity.yaw, - entity.pitch, - entity.pitch, - 0.into(), - 0.0, - 0.0, - 0.0, - )) - } + let token = player.client.token.clone(); + for (_, existing_player) in self.current_players.iter().filter(|c| c.0 != &token) { + let existing_player = existing_player.as_ref().borrow(); + let entity = &existing_player.entity; + let gameprofile = existing_player.client.gameprofile.as_ref().unwrap(); + player.client.send_packet(&CSpawnEntity::new( + player.entity_id().into(), + UUID(gameprofile.id), + EntityType::Player.to_i32().unwrap().into(), + entity.x, + entity.y, + entity.z, + entity.yaw, + entity.pitch, + entity.pitch, + 0.into(), + 0.0, + 0.0, + 0.0, + )) } // entity meta data - if let Some(config) = &client.config { + if let Some(config) = player.client.config.clone() { self.broadcast_packet( - client, + player, &CSetEntityMetadata::new( entity_id.into(), Metadata::new(17, VarInt(0), config.skin_parts), @@ -294,35 +292,41 @@ impl Server { ) } - self.spawn_test_chunk(client, self.base_config.view_distance as u32) + self.spawn_test_chunk(player, self.base_config.view_distance as u32) .await; } /// TODO: This definitly should be in world - pub fn get_by_entityid(&self, from: &Client, id: EntityId) -> Option> { - for (_, client) in self.current_clients.iter().filter(|c| c.0 != &from.token) { + pub fn get_by_entityid(&self, from: &Player, id: EntityId) -> Option> { + for (_, player) in self + .current_players + .iter() + .filter(|c| c.0 != &from.client.token) + { // Check if client is a player - let client = client.borrow_mut(); - if client.is_player() && client.player.as_ref().unwrap().entity_id() == id { - return Some(client); + let player = player.borrow_mut(); + if player.entity_id() == id { + return Some(player); } } None } /// Sends a Packet to all Players - pub fn broadcast_packet

(&self, from: &mut Client, packet: &P) + pub fn broadcast_packet

(&self, from: &mut Player, packet: &P) where P: ClientPacket, { // we can't borrow twice at same time - from.send_packet(packet); - for (_, client) in self.current_clients.iter().filter(|c| c.0 != &from.token) { + from.client.send_packet(packet); + for (_, player) in self + .current_players + .iter() + .filter(|c| c.0 != &from.client.token) + { // Check if client is a player - let mut client = client.borrow_mut(); - if client.is_player() { - client.send_packet(packet); - } + let mut player = player.borrow_mut(); + player.client.send_packet(packet); } } @@ -331,21 +335,19 @@ impl Server { where P: ClientPacket, { - for (_, client) in self - .current_clients + for (_, player) in self + .current_players .iter() .filter(|c| !from.contains(&c.0.as_ref())) { // Check if client is a player - let mut client = client.borrow_mut(); - if client.is_player() { - client.send_packet(packet); - } + let mut player = player.borrow_mut(); + player.client.send_packet(packet); } } // TODO: do this in a world - async fn spawn_test_chunk(&self, client: &mut Client, distance: u32) { + async fn spawn_test_chunk(&self, player: &mut Player, distance: u32) { let inst = std::time::Instant::now(); let (sender, mut chunk_receiver) = mpsc::channel(distance as usize); let world = self.world.clone(); @@ -358,7 +360,7 @@ impl Server { .await; }); - client.send_packet(&CCenterChunk { + player.client.send_packet(&CCenterChunk { chunk_x: 0.into(), chunk_z: 0.into(), }); @@ -382,7 +384,7 @@ impl Server { len / (1024 * 1024) ); } - client.send_packet(&CChunkData(&chunk_data)); + player.client.send_packet(&CChunkData(&chunk_data)); } let t = inst.elapsed(); dbg!("DONE", t); From 52943f66c876bcb7eb1f5422329d297c7d054656 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sat, 24 Aug 2024 18:03:32 +0200 Subject: [PATCH 23/30] Simply abstraction of property trait --- pumpkin-inventory/src/lib.rs | 38 ++------------------ pumpkin-inventory/src/window_property.rs | 46 +++++++++--------------- pumpkin/src/client/player_packet.rs | 2 +- 3 files changed, 19 insertions(+), 67 deletions(-) diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 3595bd6c2..dadb10cc6 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -1,10 +1,10 @@ -use num_derive::ToPrimitive; +use num_derive::{FromPrimitive, ToPrimitive}; pub mod player; pub mod window_property; /// https://wiki.vg/Inventory -#[derive(Debug, ToPrimitive, Clone)] +#[derive(Debug, ToPrimitive, FromPrimitive, Clone)] pub enum WindowType { // not used Generic9x1, @@ -52,37 +52,3 @@ impl WindowType { "WINDOW TITLE" } } -impl TryFrom for WindowType { - type Error = (); - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(WindowType::Generic9x1), - 1 => Ok(WindowType::Generic9x2), - 2 => Ok(WindowType::Generic9x3), - 3 => Ok(WindowType::Generic9x4), - 4 => Ok(WindowType::Generic9x5), - 5 => Ok(WindowType::Generic9x6), - 6 => Ok(WindowType::Generic3x3), - 7 => Ok(WindowType::Craft3x3), - 8 => Ok(WindowType::Anvil), - 9 => Ok(WindowType::Beacon), - 10 => Ok(WindowType::BlastFurnace), - 11 => Ok(WindowType::BrewingStand), - 12 => Ok(WindowType::CraftingTable), - 13 => Ok(WindowType::EnchantmentTable), - 14 => Ok(WindowType::Furnace), - 15 => Ok(WindowType::Grindstone), - 16 => Ok(WindowType::Hopper), - 17 => Ok(WindowType::Lectern), - 18 => Ok(WindowType::Loom), - 19 => Ok(WindowType::Merchant), - 20 => Ok(WindowType::ShulkerBox), - 21 => Ok(WindowType::SmithingTable), - 22 => Ok(WindowType::Smoker), - 23 => Ok(WindowType::CartographyTable), - 24 => Ok(WindowType::Stonecutter), - _ => Err(()), - } - } -} diff --git a/pumpkin-inventory/src/window_property.rs b/pumpkin-inventory/src/window_property.rs index 67deb646e..56f4b2942 100644 --- a/pumpkin-inventory/src/window_property.rs +++ b/pumpkin-inventory/src/window_property.rs @@ -1,6 +1,13 @@ -pub trait WindowPropertyTrait: Sized { +use num_derive::ToPrimitive; +use num_traits::ToPrimitive; + +pub trait WindowPropertyTrait { + fn to_id(self) -> i16; +} + +impl WindowPropertyTrait for T { fn to_id(self) -> i16 { - 0 + self.to_i16().unwrap() } } @@ -21,7 +28,7 @@ impl WindowProperty { (self.window_property.to_id(), self.value) } } - +#[derive(ToPrimitive)] pub enum Furnace { FireIcon, MaximumFuelBurnTime, @@ -29,12 +36,6 @@ pub enum Furnace { MaximumProgress, } -impl WindowPropertyTrait for Furnace { - fn to_id(self) -> i16 { - self as i16 - } -} - pub enum EnchantmentTable { LevelRequirement { slot: u8 }, EnchantmentSeed, @@ -54,50 +55,35 @@ impl WindowPropertyTrait for EnchantmentTable { }) as i16 } } - +#[derive(ToPrimitive)] pub enum Beacon { PowerLevel, FirstPotionEffect, SecondPotionEffect, } -impl WindowPropertyTrait for Beacon { - fn to_id(self) -> i16 { - self as i16 - } -} - +#[derive(ToPrimitive)] pub enum Anvil { RepairCost, } -impl WindowPropertyTrait for Anvil {} - +#[derive(ToPrimitive)] pub enum BrewingStand { BrewTime, FuelTime, } -impl WindowPropertyTrait for BrewingStand { - fn to_id(self) -> i16 { - self as i16 - } -} - +#[derive(ToPrimitive)] pub enum Stonecutter { SelectedRecipe, } -impl WindowPropertyTrait for Stonecutter {} - +#[derive(ToPrimitive)] pub enum Loom { SelectedPattern, } -impl WindowPropertyTrait for Loom {} - +#[derive(ToPrimitive)] pub enum Lectern { PageNumber, } - -impl WindowPropertyTrait for Lectern {} diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 27fe5e94c..5f4c0c61c 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -422,7 +422,7 @@ impl Client { // But this is not possible yet pub fn handle_close_container(&mut self, _server: &mut Server, packet: SCloseContainer) { // window_id 0 represents both 9x1 Generic AND inventory here - let Ok(_window_type) = WindowType::try_from(packet.window_id) else { + let Some(_window_type) = WindowType::from_u8(packet.window_id) else { self.kick("Invalid window ID"); return; }; From bae9198980381a7657b05a4fa38c40a12ce0bdbe Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sat, 24 Aug 2024 18:09:13 +0200 Subject: [PATCH 24/30] fix issues --- pumpkin/src/client/container.rs | 6 ++++-- pumpkin/src/client/mod.rs | 1 - pumpkin/src/client/player_packet.rs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index a2edae31c..80616d423 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -88,7 +88,8 @@ impl Player { /// The official Minecraft client is weird, and will always just close *any* window that is opened when this gets sent pub fn close_container(&mut self, window_type: WindowType) { - self.send_packet(&CCloseContainer::new(window_type as u8)) + self.client + .send_packet(&CCloseContainer::new(window_type as u8)) } pub fn set_container_property( @@ -97,6 +98,7 @@ impl Player { window_property: WindowProperty, ) { let (id, value) = window_property.into_packet(); - self.send_packet(&CSetContainerProperty::new(window_type as u8, id, value)); + self.client + .send_packet(&CSetContainerProperty::new(window_type as u8, id, value)); } } diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index ae5b7f650..5146a31f2 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -228,7 +228,6 @@ impl Client { } } - // 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, event: &Event) { diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 867b34475..b27af67cd 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -415,7 +415,7 @@ impl Player { pub fn handle_close_container(&mut self, _server: &mut Server, packet: SCloseContainer) { // window_id 0 represents both 9x1 Generic AND inventory here let Some(_window_type) = WindowType::from_u8(packet.window_id) else { - self.kick("Invalid window ID"); + self.kick(TextComponent::text("Invalid window ID")); return; }; } From 3428f03a0f98ef50a3f92f084575fbb2b8a58dbb Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sat, 24 Aug 2024 18:12:51 +0200 Subject: [PATCH 25/30] better name --- pumpkin-inventory/src/window_property.rs | 2 +- pumpkin/src/client/container.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pumpkin-inventory/src/window_property.rs b/pumpkin-inventory/src/window_property.rs index 56f4b2942..136d68312 100644 --- a/pumpkin-inventory/src/window_property.rs +++ b/pumpkin-inventory/src/window_property.rs @@ -24,7 +24,7 @@ impl WindowProperty { } } - pub fn into_packet(self) -> (i16, i16) { + pub fn into_tuple(self) -> (i16, i16) { (self.window_property.to_id(), self.value) } } diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index 80616d423..fc9cf1059 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -97,7 +97,7 @@ impl Player { window_type: WindowType, window_property: WindowProperty, ) { - let (id, value) = window_property.into_packet(); + let (id, value) = window_property.into_tuple(); self.client .send_packet(&CSetContainerProperty::new(window_type as u8, id, value)); } From f40eb85c53599ae073cd94dd470b88bcdeaff882 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sat, 24 Aug 2024 20:09:56 +0200 Subject: [PATCH 26/30] Don't clone PlayerConfig --- pumpkin/src/client/mod.rs | 1 - pumpkin/src/entity/player.rs | 4 ++-- pumpkin/src/server.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 5146a31f2..4744594e8 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -35,7 +35,6 @@ mod client_packet; mod container; pub mod player_packet; -#[derive(Clone)] pub struct PlayerConfig { pub locale: String, // 16 pub view_distance: i8, diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 935ba7cd4..19a9c2ac1 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -200,13 +200,13 @@ impl Player { } } -#[derive(FromPrimitive, Clone)] +#[derive(FromPrimitive)] pub enum Hand { Main, Off, } -#[derive(FromPrimitive, Clone)] +#[derive(FromPrimitive)] pub enum ChatMode { Enabled, CommandsOnly, diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index c2aa939d6..7e569bf4b 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -282,7 +282,7 @@ impl Server { )) } // entity meta data - if let Some(config) = player.client.config.clone() { + if let Some(config) = player.client.config.as_ref() { self.broadcast_packet( player, &CSetEntityMetadata::new( From d69f6c5fc19549d799d8c3152b660683f12ceb69 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sat, 24 Aug 2024 23:07:12 +0200 Subject: [PATCH 27/30] Add Clientbound Teleport Entity usually used when Player moves more than 8 blocks --- .../src/client/play/c_teleport_entity.rs | 38 +++++++++++++++++++ pumpkin-protocol/src/client/play/mod.rs | 2 + pumpkin/src/client/player_packet.rs | 4 +- 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 pumpkin-protocol/src/client/play/c_teleport_entity.rs diff --git a/pumpkin-protocol/src/client/play/c_teleport_entity.rs b/pumpkin-protocol/src/client/play/c_teleport_entity.rs new file mode 100644 index 000000000..01722a6c0 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_teleport_entity.rs @@ -0,0 +1,38 @@ +use pumpkin_macros::packet; +use serde::Serialize; + +use crate::VarInt; + +#[derive(Serialize)] +#[packet(0x70)] +pub struct CTeleportEntitiy { + entity_id: VarInt, + x: f64, + y: f64, + z: f64, + yaw: u8, + pitch: u8, + on_ground: bool, +} + +impl CTeleportEntitiy { + pub fn new( + entity_id: VarInt, + x: f64, + y: f64, + z: f64, + yaw: u8, + pitch: u8, + on_ground: bool, + ) -> Self { + Self { + entity_id, + x, + y, + z, + yaw, + pitch, + on_ground, + } + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index c64720948..90a405280 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -32,6 +32,7 @@ mod c_spawn_player; mod c_subtitle; mod c_sync_player_position; mod c_system_chat_message; +mod c_teleport_entity; mod c_unload_chunk; mod c_update_entity_pos; mod c_update_entity_pos_rot; @@ -73,6 +74,7 @@ pub use c_spawn_player::*; pub use c_subtitle::*; pub use c_sync_player_position::*; pub use c_system_chat_message::*; +pub use c_teleport_entity::*; pub use c_unload_chunk::*; pub use c_update_entity_pos::*; pub use c_update_entity_pos_rot::*; diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index b27af67cd..246702d41 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -41,8 +41,8 @@ impl Player { _server: &mut Server, confirm_teleport: SConfirmTeleport, ) { - if let Some(id) = self.awaiting_teleport.clone() { - if id == confirm_teleport.teleport_id { + if let Some(id) = self.awaiting_teleport.as_ref() { + if id == &confirm_teleport.teleport_id { } else { log::warn!("Teleport id does not match, Weird but okay"); } From d8fd1dd00b77b704ae94802c684e582f93a4ee2e Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sat, 24 Aug 2024 23:51:01 +0200 Subject: [PATCH 28/30] Improve teleport we now use teleport id's and also set player position when receiving the response packet --- pumpkin/src/client/player_packet.rs | 18 +++++++++++++----- pumpkin/src/entity/player.rs | 26 +++++++++++++++++++------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 246702d41..2328d2943 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -41,15 +41,23 @@ impl Player { _server: &mut Server, confirm_teleport: SConfirmTeleport, ) { - if let Some(id) = self.awaiting_teleport.as_ref() { + if let Some((id, position)) = self.awaiting_teleport.as_ref() { if id == &confirm_teleport.teleport_id { + // we should set the pos now to that we requested in the teleport packet, Is may fixed issues when the client sended position packets while being teleported + self.entity.x = position.x; + self.entity.y = position.y; + self.entity.z = position.z; + + self.awaiting_teleport = None; } else { - log::warn!("Teleport id does not match, Weird but okay"); + self.kick(TextComponent::text( + "Wrong teleport id", + )) } - self.awaiting_teleport = None; } else { - self.client - .kick("Send Teleport confirm, but we did not teleport") + self.kick(TextComponent::text( + "Send Teleport confirm, but we did not teleport", + )) } } diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 19a9c2ac1..221ac0021 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -43,8 +43,9 @@ pub struct Player { // TODO: prbly should put this into an Living Entitiy or something pub velocity: Vector3, - // Current awaiting teleport id, None if did not teleport - pub awaiting_teleport: Option, + pub teleport_id_count: i32, + // Current awaiting teleport id and location, None if did not teleport + pub awaiting_teleport: Option<(VarInt, Vector3)>, } impl Player { @@ -63,6 +64,7 @@ impl Player { current_block_destroy_stage: 0, velocity: Vector3::new(0.0, 0.0, 0.0), inventory: PlayerInventory::new(), + teleport_id_count: 0, gamemode, } } @@ -94,8 +96,11 @@ impl Player { } pub fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) { - // TODO - let id = 0; + // this is the ultra special magic code used to create the teleport id + self.teleport_id_count += 1; + if self.teleport_id_count == i32::max_value() { + self.teleport_id_count = 0; + } let entity = &mut self.entity; entity.x = x; entity.y = y; @@ -105,9 +110,16 @@ impl Player { entity.lastz = z; entity.yaw = yaw; entity.pitch = pitch; - self.awaiting_teleport = Some(id.into()); - self.client - .send_packet(&CSyncPlayerPosition::new(x, y, z, yaw, pitch, 0, id.into())); + self.awaiting_teleport = Some((self.teleport_id_count.into(), Vector3::new(x, y, z))); + self.client.send_packet(&CSyncPlayerPosition::new( + x, + y, + z, + yaw, + pitch, + 0, + self.teleport_id_count.into(), + )); } /// Kicks the Client with a reason depending on the connection state From 024789dfbb900dbba6ae30436a98f5bbf1a5c4c4 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sun, 25 Aug 2024 00:17:53 +0200 Subject: [PATCH 29/30] Fixed an upsi --- pumpkin/src/server.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 7e569bf4b..725f6091e 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -266,7 +266,7 @@ impl Server { let entity = &existing_player.entity; let gameprofile = existing_player.client.gameprofile.as_ref().unwrap(); player.client.send_packet(&CSpawnEntity::new( - player.entity_id().into(), + existing_player.entity_id().into(), UUID(gameprofile.id), EntityType::Player.to_i32().unwrap().into(), entity.x, @@ -303,7 +303,6 @@ impl Server { .iter() .filter(|c| c.0 != &from.client.token) { - // Check if client is a player let player = player.borrow_mut(); if player.entity_id() == id { return Some(player); @@ -324,7 +323,6 @@ impl Server { .iter() .filter(|c| c.0 != &from.client.token) { - // Check if client is a player let mut player = player.borrow_mut(); player.client.send_packet(packet); } @@ -340,7 +338,6 @@ impl Server { .iter() .filter(|c| !from.contains(&c.0.as_ref())) { - // Check if client is a player let mut player = player.borrow_mut(); player.client.send_packet(packet); } From 80477f9aabb74d7c7a03edf7677d26faccd4d66f Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sun, 25 Aug 2024 00:19:16 +0200 Subject: [PATCH 30/30] fix: clippy warns --- pumpkin/src/client/player_packet.rs | 4 +--- pumpkin/src/entity/player.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 2328d2943..fff71fb08 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -50,9 +50,7 @@ impl Player { self.awaiting_teleport = None; } else { - self.kick(TextComponent::text( - "Wrong teleport id", - )) + self.kick(TextComponent::text("Wrong teleport id")) } } else { self.kick(TextComponent::text( diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 221ac0021..64f46e585 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -98,7 +98,7 @@ impl Player { pub fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) { // this is the ultra special magic code used to create the teleport id self.teleport_id_count += 1; - if self.teleport_id_count == i32::max_value() { + if self.teleport_id_count == i32::MAX { self.teleport_id_count = 0; } let entity = &mut self.entity;