From 5ce79fcd7779b4c4b3257659a526097bd46aad42 Mon Sep 17 00:00:00 2001 From: tomasalias Date: Mon, 6 Jan 2025 18:53:24 +0100 Subject: [PATCH 01/34] Copy some lines from other-branch --- Cargo.toml | 8 + pumpkin-core/src/math/boundingbox.rs | 10 + pumpkin-core/src/math/position.rs | 4 + pumpkin-core/src/math/vector2.rs | 9 + pumpkin-core/src/math/vector3.rs | 32 +++ pumpkin-entity/src/entity_type.rs | 15 ++ pumpkin-inventory/src/container_click.rs | 13 +- pumpkin-inventory/src/player.rs | 11 +- .../src/client/play/c_entity_metadata.rs | 18 +- .../src/client/play/c_entity_velocity.rs | 12 +- .../src/client/play/c_spawn_entity.rs | 6 +- pumpkin-protocol/src/client/play/mod.rs | 2 + pumpkin-world/src/block/block_registry.rs | 7 + pumpkin-world/src/coordinates.rs | 20 ++ pumpkin-world/src/item/item_registry.rs | 4 + pumpkin/src/command/commands/cmd_clear.rs | 4 +- pumpkin/src/command/commands/cmd_gamemode.rs | 5 +- pumpkin/src/command/commands/cmd_give.rs | 3 +- pumpkin/src/command/commands/cmd_help.rs | 8 +- pumpkin/src/command/commands/cmd_kick.rs | 3 +- pumpkin/src/command/commands/cmd_kill.rs | 5 +- pumpkin/src/command/commands/cmd_list.rs | 2 +- pumpkin/src/command/commands/cmd_pumpkin.rs | 6 +- pumpkin/src/command/commands/cmd_say.rs | 3 +- pumpkin/src/command/commands/cmd_setblock.rs | 5 +- pumpkin/src/command/commands/cmd_stop.rs | 3 +- pumpkin/src/command/commands/cmd_teleport.rs | 15 +- pumpkin/src/command/commands/cmd_transfer.rs | 9 +- .../src/command/commands/cmd_worldborder.rs | 21 +- pumpkin/src/command/dispatcher.rs | 7 +- pumpkin/src/command/mod.rs | 4 +- pumpkin/src/entity/mod.rs | 224 ++++++++++++++++++ pumpkin/src/entity/player.rs | 18 +- pumpkin/src/net/combat.rs | 4 + pumpkin/src/net/container.rs | 62 ++++- pumpkin/src/world/mod.rs | 71 +++--- 36 files changed, 556 insertions(+), 97 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 371e6e846..4dfc13f9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,3 +55,11 @@ uuid = { version = "1.11.0", features = ["serde", "v3", "v4"] } derive_more = { version = "1.0.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +<<<<<<< HEAD +======= + +itertools = "0.13.0" + +[profile.dev] +opt-level = 2 +>>>>>>> origin/item-dropping diff --git a/pumpkin-core/src/math/boundingbox.rs b/pumpkin-core/src/math/boundingbox.rs index d9ad58d8a..f8b39a4a1 100644 --- a/pumpkin-core/src/math/boundingbox.rs +++ b/pumpkin-core/src/math/boundingbox.rs @@ -65,6 +65,16 @@ impl BoundingBox { let f = f64::max(f64::max(self.min_z - pos.z, pos.z - self.max_z), 0.0); super::squared_magnitude(d, e, f) } + + pub fn offset(&mut self, vector3: Vector3) { + self.min_x += vector3.x; + self.min_y += vector3.y; + self.min_z += vector3.z; + + self.max_x += vector3.x; + self.max_y += vector3.y; + self.max_z += vector3.z; + } } #[derive(Clone, Copy)] diff --git a/pumpkin-core/src/math/position.rs b/pumpkin-core/src/math/position.rs index a3b82cbeb..d9dab5ffe 100644 --- a/pumpkin-core/src/math/position.rs +++ b/pumpkin-core/src/math/position.rs @@ -5,7 +5,11 @@ use crate::math::vector2::Vector2; use num_traits::Euclid; use serde::{Deserialize, Serialize}; +<<<<<<< HEAD #[derive(Clone, Copy, PartialEq, Eq)] +======= +#[derive(Clone, Copy, Default)] +>>>>>>> origin/item-dropping /// Aka Block Position pub struct WorldPosition(pub Vector3); diff --git a/pumpkin-core/src/math/vector2.rs b/pumpkin-core/src/math/vector2.rs index 62ab639fc..b386643b4 100644 --- a/pumpkin-core/src/math/vector2.rs +++ b/pumpkin-core/src/math/vector2.rs @@ -10,6 +10,15 @@ pub struct Vector2 { pub z: T, } +impl Default for Vector2 { + fn default() -> Self { + Self { + x: T::default(), + z: T::default(), + } + } +} + impl Vector2 { pub const fn new(x: T, z: T) -> Self { Vector2 { x, z } diff --git a/pumpkin-core/src/math/vector3.rs b/pumpkin-core/src/math/vector3.rs index a56be9e16..ec3cf0173 100644 --- a/pumpkin-core/src/math/vector3.rs +++ b/pumpkin-core/src/math/vector3.rs @@ -10,6 +10,16 @@ pub struct Vector3 { pub z: T, } +impl Default for Vector3 { + fn default() -> Self { + Vector3 { + x: T::default(), + y: T::default(), + z: T::default(), + } + } +} + impl Vector3 { pub const fn new(x: T, y: T, z: T) -> Self { Vector3 { x, y, z } @@ -18,6 +28,9 @@ impl Vector3 { pub fn length_squared(&self) -> T { self.x * self.x + self.y * self.y + self.z * self.z } + pub fn horizontal_length_squared(&self) -> T { + (self.x * self.x) + (self.z * self.z) + } pub fn add(&self, other: &Vector3) -> Self { Vector3 { @@ -55,10 +68,29 @@ impl Vector3 { } } +impl std::iter::Sum for Vector3 { + fn sum>(iter: I) -> Self { + let mut x = T::default(); + let mut y = T::default(); + let mut z = T::default(); + for vec in iter { + x = x + vec.x; + y = y + vec.y; + z = z + vec.z; + } + Vector3 { x, y, z } + } +} + impl Vector3 { pub fn length(&self) -> T { self.length_squared().sqrt() } + + pub fn horizontal_length(&self) -> T { + self.horizontal_length_squared().sqrt() + } + pub fn normalize(&self) -> Self { let length = self.length(); Vector3 { diff --git a/pumpkin-entity/src/entity_type.rs b/pumpkin-entity/src/entity_type.rs index e065722fd..9c450601d 100644 --- a/pumpkin-entity/src/entity_type.rs +++ b/pumpkin-entity/src/entity_type.rs @@ -1,5 +1,10 @@ +<<<<<<< HEAD // TODO make this dynamic #[derive(Clone)] +======= +// TODO +#[derive(Clone, Copy)] +>>>>>>> origin/item-dropping #[repr(i32)] pub enum EntityType { AcaciaBoat = 0, @@ -152,3 +157,13 @@ pub enum EntityType { Player = 147, FishingBobber = 148, } + +impl EntityType { + pub const fn gravity(&self) -> f64 { + use EntityType::*; + match self { + Item => 0.04, + _ => todo!(), + } + } +} diff --git a/pumpkin-inventory/src/container_click.rs b/pumpkin-inventory/src/container_click.rs index d93ba3d3c..d5bf3ec29 100644 --- a/pumpkin-inventory/src/container_click.rs +++ b/pumpkin-inventory/src/container_click.rs @@ -18,9 +18,15 @@ impl Click { click_type: ClickType::CreativePickItem, slot: Slot::Normal(slot.try_into().or(Err(InventoryError::InvalidSlot))?), }), +<<<<<<< HEAD SlotActionType::Throw => Self::new_drop_item(button), SlotActionType::QuickCraft => Self::new_drag_item(button, slot), SlotActionType::PickupAll => Ok(Self { +======= + 4 => Self::new_drop_item(button, slot), + 5 => Self::new_drag_item(button, slot), + 6 => Ok(Self { +>>>>>>> origin/item-dropping click_type: ClickType::DoubleClick, slot: Slot::Normal(slot.try_into().or(Err(InventoryError::InvalidSlot))?), }), @@ -66,15 +72,18 @@ impl Click { }) } - fn new_drop_item(button: i8) -> Result { + fn new_drop_item(button: i8, slot: i16) -> Result { let drop_type = match button { 0 => DropType::SingleItem, 1 => DropType::FullStack, _ => Err(InventoryError::InvalidPacket)?, }; + if slot == -999 { + return Err(InventoryError::InvalidPacket); + } Ok(Self { click_type: ClickType::DropType(drop_type), - slot: Slot::OutsideInventory, + slot: Slot::Normal(slot.try_into().or(Err(InventoryError::InvalidPacket))?), }) } diff --git a/pumpkin-inventory/src/player.rs b/pumpkin-inventory/src/player.rs index 1305ea452..8f4870986 100644 --- a/pumpkin-inventory/src/player.rs +++ b/pumpkin-inventory/src/player.rs @@ -1,6 +1,7 @@ use crate::container_click::MouseClick; use crate::crafting::check_if_matches_crafting; use crate::{handle_item_change, Container, InventoryError, WindowType}; +use itertools::Itertools; use pumpkin_world::item::ItemStack; use std::iter::Chain; use std::slice::IterMut; @@ -13,7 +14,7 @@ pub struct PlayerInventory { armor: [Option; 4], offhand: Option, // current selected slot in hotbar - selected: usize, + pub selected: usize, pub state_id: u32, // Notchian server wraps this value at 100, we can just keep it as a u8 that automatically wraps pub total_opened_containers: i32, @@ -158,6 +159,14 @@ impl PlayerInventory { slots } + pub fn hotbar_mut(&mut self) -> Vec<&mut Option> { + self.items.iter_mut().skip(27).collect_vec() + } + + pub fn main_inventory_mut(&mut self) -> Vec<&mut Option> { + self.items.iter_mut().take(27).collect_vec() + } + pub fn slots_mut(&mut self) -> Vec<&mut Option> { let mut slots = vec![&mut self.crafting_output]; slots.extend(self.crafting.iter_mut()); diff --git a/pumpkin-protocol/src/client/play/c_entity_metadata.rs b/pumpkin-protocol/src/client/play/c_entity_metadata.rs index 67b35e834..bfcae822e 100644 --- a/pumpkin-protocol/src/client/play/c_entity_metadata.rs +++ b/pumpkin-protocol/src/client/play/c_entity_metadata.rs @@ -5,13 +5,13 @@ use crate::VarInt; #[derive(Serialize)] #[client_packet("play:set_entity_data")] -pub struct CSetEntityMetadata { +pub struct CSetEntityMetadata { entity_id: VarInt, metadata: Metadata, end: u8, } -impl CSetEntityMetadata { +impl CSetEntityMetadata { pub fn new(entity_id: VarInt, metadata: Metadata) -> Self { Self { entity_id, @@ -22,14 +22,18 @@ impl CSetEntityMetadata { } #[derive(Serialize)] -pub struct Metadata { +pub struct Metadata { index: u8, - typ: VarInt, + r#type: VarInt, value: T, } -impl Metadata { - pub fn new(index: u8, typ: VarInt, value: T) -> Self { - Self { index, typ, value } +impl Metadata { + pub fn new(index: u8, r#type: VarInt, value: T) -> Self { + Self { + index, + r#type, + value, + } } } diff --git a/pumpkin-protocol/src/client/play/c_entity_velocity.rs b/pumpkin-protocol/src/client/play/c_entity_velocity.rs index 63c543501..728fd751c 100644 --- a/pumpkin-protocol/src/client/play/c_entity_velocity.rs +++ b/pumpkin-protocol/src/client/play/c_entity_velocity.rs @@ -1,6 +1,6 @@ +use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::client_packet; use serde::Serialize; - use crate::VarInt; #[derive(Serialize)] @@ -13,12 +13,16 @@ pub struct CEntityVelocity<'a> { } impl<'a> CEntityVelocity<'a> { +<<<<<<< HEAD pub fn new(entity_id: &'a VarInt, velocity_x: f64, velocity_y: f64, velocity_z: f64) -> Self { +======= + pub fn new(entity_id: &'a VarInt, velocity: Vector3) -> Self { +>>>>>>> origin/item-dropping Self { 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, + 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_spawn_entity.rs b/pumpkin-protocol/src/client/play/c_spawn_entity.rs index 258101049..1f3678c5b 100644 --- a/pumpkin-protocol/src/client/play/c_spawn_entity.rs +++ b/pumpkin-protocol/src/client/play/c_spawn_entity.rs @@ -35,9 +35,9 @@ impl CSpawnEntity { yaw: f32, // angle head_yaw: f32, // angle data: VarInt, - velocity_x: f32, - velocity_y: f32, - velocity_z: f32, + velocity_x: f64, + velocity_y: f64, + velocity_z: f64, ) -> Self { Self { entity_id, diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 68a7cc576..bd3ed87d9 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -30,6 +30,7 @@ mod c_level_event; mod c_login; mod c_open_screen; mod c_particle; +mod c_pickup_item; mod c_ping_response; mod c_play_disconnect; mod c_player_abilities; @@ -101,6 +102,7 @@ pub use c_level_event::*; pub use c_login::*; pub use c_open_screen::*; pub use c_particle::*; +pub use c_pickup_item::*; pub use c_ping_response::*; pub use c_play_disconnect::*; pub use c_player_abilities::*; diff --git a/pumpkin-world/src/block/block_registry.rs b/pumpkin-world/src/block/block_registry.rs index d043c21f2..ca8a3450d 100644 --- a/pumpkin-world/src/block/block_registry.rs +++ b/pumpkin-world/src/block/block_registry.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::sync::LazyLock; +use crate::item::ItemStack; use serde::Deserialize; pub static BLOCKS: LazyLock = LazyLock::new(|| { @@ -101,6 +102,12 @@ pub struct Block { pub default_state_id: u16, pub states: Vec, } + +impl Block { + pub fn to_item(&self, count: u8) -> ItemStack { + ItemStack::new(count, self.item_id) + } +} #[expect(dead_code)] #[derive(Deserialize, Clone, Debug)] pub struct Property { diff --git a/pumpkin-world/src/coordinates.rs b/pumpkin-world/src/coordinates.rs index 87d9e0902..d779c86a5 100644 --- a/pumpkin-world/src/coordinates.rs +++ b/pumpkin-world/src/coordinates.rs @@ -3,6 +3,7 @@ use std::ops::Deref; use crate::{WORLD_LOWEST_Y, WORLD_MAX_Y}; use derive_more::derive::{AsMut, AsRef, Display, Into}; use num_traits::{PrimInt, Signed, Unsigned}; +use pumpkin_core::math::position::WorldPosition; use pumpkin_core::math::vector2::Vector2; use pumpkin_core::math::vector3::Vector3; use serde::{Deserialize, Serialize}; @@ -108,6 +109,25 @@ impl ChunkRelativeBlockCoordinates { } } +impl From for ChunkRelativeBlockCoordinates { + fn from(pos: WorldPosition) -> Self { + Self { + x: ChunkRelativeOffset((pos.0.x / 16) as u8), + y: Height(pos.0.y as i16), + z: ChunkRelativeOffset((pos.0.z / 16) as u8), + } + } +} + +impl From> for ChunkRelativeBlockCoordinates { + fn from(pos: Vector3) -> Self { + Self { + x: ChunkRelativeOffset((pos.x / 16.).round() as u8), + y: Height(pos.y.ceil() as i16), + z: ChunkRelativeOffset((pos.z / 16.).round() as u8), + } + } +} #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ChunkRelativeXZBlockCoordinates { pub x: ChunkRelativeOffset, diff --git a/pumpkin-world/src/item/item_registry.rs b/pumpkin-world/src/item/item_registry.rs index 704840c31..222727117 100644 --- a/pumpkin-world/src/item/item_registry.rs +++ b/pumpkin-world/src/item/item_registry.rs @@ -36,6 +36,10 @@ pub fn get_spawn_egg(item_id: u16) -> Option { None } +pub fn get_item_by_id(id: u16) -> Option<&'static Item> { + ITEMS.values().find(|item| item.id == id) +} + #[derive(Deserialize, Clone, Debug)] pub struct Item { pub id: u16, diff --git a/pumpkin/src/command/commands/cmd_clear.rs b/pumpkin/src/command/commands/cmd_clear.rs index 067ebf52d..f19c3717f 100644 --- a/pumpkin/src/command/commands/cmd_clear.rs +++ b/pumpkin/src/command/commands/cmd_clear.rs @@ -63,7 +63,7 @@ impl CommandExecutor for ClearExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let Some(Arg::Entities(targets)) = args.get(&ARG_TARGET) else { @@ -90,7 +90,7 @@ impl CommandExecutor for ClearSelfExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, _args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let target = sender.as_player().ok_or(CommandError::InvalidRequirement)?; diff --git a/pumpkin/src/command/commands/cmd_gamemode.rs b/pumpkin/src/command/commands/cmd_gamemode.rs index b45f4403f..4dedac9d8 100644 --- a/pumpkin/src/command/commands/cmd_gamemode.rs +++ b/pumpkin/src/command/commands/cmd_gamemode.rs @@ -1,4 +1,5 @@ use async_trait::async_trait; +use std::sync::Arc; use crate::command::args::arg_gamemode::GamemodeArgumentConsumer; use crate::command::args::GetCloned; @@ -30,7 +31,7 @@ impl CommandExecutor for GamemodeTargetSelf { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let Some(Arg::GameMode(gamemode)) = args.get_cloned(&ARG_GAMEMODE) else { @@ -66,7 +67,7 @@ impl CommandExecutor for GamemodeTargetPlayer { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let Some(Arg::GameMode(gamemode)) = args.get_cloned(&ARG_GAMEMODE) else { diff --git a/pumpkin/src/command/commands/cmd_give.rs b/pumpkin/src/command/commands/cmd_give.rs index fcd60da15..2098bb04e 100644 --- a/pumpkin/src/command/commands/cmd_give.rs +++ b/pumpkin/src/command/commands/cmd_give.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use pumpkin_core::text::color::{Color, NamedColor}; use pumpkin_core::text::TextComponent; +use std::sync::Arc; use crate::command::args::arg_bounded_num::BoundedNumArgumentConsumer; use crate::command::args::arg_item::ItemArgumentConsumer; @@ -30,7 +31,7 @@ impl CommandExecutor for GiveExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let targets = PlayersArgumentConsumer.find_arg_default_name(args)?; diff --git a/pumpkin/src/command/commands/cmd_help.rs b/pumpkin/src/command/commands/cmd_help.rs index 3808c0acf..352423d7e 100644 --- a/pumpkin/src/command/commands/cmd_help.rs +++ b/pumpkin/src/command/commands/cmd_help.rs @@ -2,6 +2,7 @@ use async_trait::async_trait; use pumpkin_core::text::click::ClickEvent; use pumpkin_core::text::color::{Color, NamedColor}; use pumpkin_core::text::TextComponent; +use std::sync::Arc; use crate::command::args::arg_bounded_num::BoundedNumArgumentConsumer; use crate::command::args::arg_command::CommandTreeArgumentConsumer; @@ -32,7 +33,7 @@ impl CommandExecutor for CommandHelpExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let Some(Arg::CommandTree(tree)) = args.get(&ARG_COMMAND) else { @@ -103,8 +104,13 @@ impl CommandExecutor for BaseHelpExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, +<<<<<<< HEAD server: &Server, args: &ConsumedArgs<'a>, +======= + server: &Arc, + _args: &ConsumedArgs<'a>, +>>>>>>> origin/item-dropping ) -> Result<(), CommandError> { let page_number = match page_number_consumer().find_arg_default_name(args) { Err(_) => 1, diff --git a/pumpkin/src/command/commands/cmd_kick.rs b/pumpkin/src/command/commands/cmd_kick.rs index 9a6dff636..d927984ce 100644 --- a/pumpkin/src/command/commands/cmd_kick.rs +++ b/pumpkin/src/command/commands/cmd_kick.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use pumpkin_core::text::color::NamedColor; use pumpkin_core::text::TextComponent; +use std::sync::Arc; use crate::command::args::arg_players::PlayersArgumentConsumer; use crate::command::args::{Arg, ConsumedArgs}; @@ -22,7 +23,7 @@ impl CommandExecutor for KickExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let Some(Arg::Players(targets)) = args.get(&ARG_TARGET) else { diff --git a/pumpkin/src/command/commands/cmd_kill.rs b/pumpkin/src/command/commands/cmd_kill.rs index a29a1fbab..d4b36f3b6 100644 --- a/pumpkin/src/command/commands/cmd_kill.rs +++ b/pumpkin/src/command/commands/cmd_kill.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use pumpkin_core::text::color::NamedColor; use pumpkin_core::text::TextComponent; +use std::sync::Arc; use crate::command::args::arg_entities::EntitiesArgumentConsumer; use crate::command::args::{Arg, ConsumedArgs}; @@ -21,7 +22,7 @@ impl CommandExecutor for KillExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let Some(Arg::Entities(targets)) = args.get(&ARG_TARGET) else { @@ -53,7 +54,7 @@ impl CommandExecutor for KillSelfExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, _args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let target = sender.as_player().ok_or(CommandError::InvalidRequirement)?; diff --git a/pumpkin/src/command/commands/cmd_list.rs b/pumpkin/src/command/commands/cmd_list.rs index 63a8bb036..8aea602a5 100644 --- a/pumpkin/src/command/commands/cmd_list.rs +++ b/pumpkin/src/command/commands/cmd_list.rs @@ -22,7 +22,7 @@ impl CommandExecutor for ListExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &crate::server::Server, + server: &Arc, _args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let players: Vec> = server.get_all_players().await; diff --git a/pumpkin/src/command/commands/cmd_pumpkin.rs b/pumpkin/src/command/commands/cmd_pumpkin.rs index a60c955e0..c0a7b88a1 100644 --- a/pumpkin/src/command/commands/cmd_pumpkin.rs +++ b/pumpkin/src/command/commands/cmd_pumpkin.rs @@ -3,7 +3,11 @@ use pumpkin_core::text::click::ClickEvent; use pumpkin_core::text::hover::HoverEvent; use pumpkin_core::text::{color::NamedColor, TextComponent}; use pumpkin_protocol::CURRENT_MC_PROTOCOL; +<<<<<<< HEAD use std::borrow::Cow; +======= +use std::sync::Arc; +>>>>>>> origin/item-dropping use crate::{ command::{ @@ -27,7 +31,7 @@ impl CommandExecutor for PumpkinExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, _args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { sender diff --git a/pumpkin/src/command/commands/cmd_say.rs b/pumpkin/src/command/commands/cmd_say.rs index 893fecb8c..e07f91560 100644 --- a/pumpkin/src/command/commands/cmd_say.rs +++ b/pumpkin/src/command/commands/cmd_say.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use pumpkin_core::text::TextComponent; use pumpkin_protocol::client::play::CSystemChatMessage; +use std::sync::Arc; use crate::command::{ args::{arg_message::MsgArgConsumer, Arg, ConsumedArgs}, @@ -23,7 +24,7 @@ impl CommandExecutor for SayExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &crate::server::Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let Some(Arg::Msg(msg)) = args.get(ARG_MESSAGE) else { diff --git a/pumpkin/src/command/commands/cmd_setblock.rs b/pumpkin/src/command/commands/cmd_setblock.rs index c9eb3a0ef..08eb79a77 100644 --- a/pumpkin/src/command/commands/cmd_setblock.rs +++ b/pumpkin/src/command/commands/cmd_setblock.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use pumpkin_core::text::color::NamedColor; use pumpkin_core::text::TextComponent; +use std::sync::Arc; use crate::command::args::arg_block::BlockArgumentConsumer; use crate::command::args::arg_position_block::BlockPosArgumentConsumer; @@ -35,7 +36,7 @@ impl CommandExecutor for SetblockExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?; @@ -47,7 +48,7 @@ impl CommandExecutor for SetblockExecutor { let success = match mode { Mode::Destroy => { - world.break_block(pos, None).await; + world.break_block(pos, None, server.clone()).await; world.set_block_state(pos, block_state_id).await; true } diff --git a/pumpkin/src/command/commands/cmd_stop.rs b/pumpkin/src/command/commands/cmd_stop.rs index c1f3f4f33..c6480d265 100644 --- a/pumpkin/src/command/commands/cmd_stop.rs +++ b/pumpkin/src/command/commands/cmd_stop.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use pumpkin_core::text::color::NamedColor; use pumpkin_core::text::TextComponent; +use std::sync::Arc; use crate::command::args::ConsumedArgs; use crate::command::tree::CommandTree; @@ -17,7 +18,7 @@ impl CommandExecutor for StopExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &crate::server::Server, + server: &Arc, _args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { sender diff --git a/pumpkin/src/command/commands/cmd_teleport.rs b/pumpkin/src/command/commands/cmd_teleport.rs index d5f535f14..1959ba568 100644 --- a/pumpkin/src/command/commands/cmd_teleport.rs +++ b/pumpkin/src/command/commands/cmd_teleport.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use pumpkin_core::math::vector3::Vector3; use pumpkin_core::text::TextComponent; +use std::sync::Arc; use crate::command::args::arg_entities::EntitiesArgumentConsumer; use crate::command::args::arg_entity::EntityArgumentConsumer; @@ -56,7 +57,7 @@ impl CommandExecutor for TpEntitiesToEntityExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?; @@ -81,7 +82,7 @@ impl CommandExecutor for TpEntitiesToPosFacingPosExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?; @@ -106,7 +107,7 @@ impl CommandExecutor for TpEntitiesToPosFacingEntityExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?; @@ -133,7 +134,7 @@ impl CommandExecutor for TpEntitiesToPosWithRotationExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?; @@ -157,7 +158,7 @@ impl CommandExecutor for TpEntitiesToPosExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?; @@ -181,7 +182,7 @@ impl CommandExecutor for TpSelfToEntityExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let destination = EntityArgumentConsumer::find_arg(args, ARG_DESTINATION)?; @@ -213,7 +214,7 @@ impl CommandExecutor for TpSelfToPosExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { match sender { diff --git a/pumpkin/src/command/commands/cmd_transfer.rs b/pumpkin/src/command/commands/cmd_transfer.rs index 504739206..661e60711 100644 --- a/pumpkin/src/command/commands/cmd_transfer.rs +++ b/pumpkin/src/command/commands/cmd_transfer.rs @@ -2,7 +2,12 @@ use async_trait::async_trait; use pumpkin_core::text::color::{Color, NamedColor}; use pumpkin_core::text::TextComponent; use pumpkin_protocol::client::play::CTransfer; +<<<<<<< HEAD use pumpkin_protocol::codec::var_int::VarInt; +======= +use pumpkin_protocol::VarInt; +use std::sync::Arc; +>>>>>>> origin/item-dropping use crate::command::args::arg_bounded_num::BoundedNumArgumentConsumer; use crate::command::args::arg_players::PlayersArgumentConsumer; @@ -36,7 +41,7 @@ impl CommandExecutor for TransferTargetSelf { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let Some(Arg::Simple(hostname)) = args.get(ARG_HOSTNAME) else { @@ -78,7 +83,7 @@ impl CommandExecutor for TransferTargetPlayer { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - _server: &crate::server::Server, + _server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let Some(Arg::Simple(hostname)) = args.get(ARG_HOSTNAME) else { diff --git a/pumpkin/src/command/commands/cmd_worldborder.rs b/pumpkin/src/command/commands/cmd_worldborder.rs index 7ee3dbae2..55b38f8a6 100644 --- a/pumpkin/src/command/commands/cmd_worldborder.rs +++ b/pumpkin/src/command/commands/cmd_worldborder.rs @@ -6,6 +6,7 @@ use pumpkin_core::{ TextComponent, }, }; +use std::sync::Arc; use crate::{ command::{ @@ -54,7 +55,7 @@ impl CommandExecutor for WorldborderGetExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, _args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server @@ -80,7 +81,7 @@ impl CommandExecutor for WorldborderSetExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server @@ -129,7 +130,7 @@ impl CommandExecutor for WorldborderSetTimeExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server @@ -201,7 +202,7 @@ impl CommandExecutor for WorldborderAddExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server @@ -252,7 +253,7 @@ impl CommandExecutor for WorldborderAddTimeExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server @@ -326,7 +327,7 @@ impl CommandExecutor for WorldborderCenterExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server @@ -354,7 +355,7 @@ impl CommandExecutor for WorldborderDamageAmountExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server @@ -405,7 +406,7 @@ impl CommandExecutor for WorldborderDamageBufferExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server @@ -456,7 +457,7 @@ impl CommandExecutor for WorldborderWarningDistanceExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server @@ -507,7 +508,7 @@ impl CommandExecutor for WorldborderWarningTimeExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let world = server diff --git a/pumpkin/src/command/dispatcher.rs b/pumpkin/src/command/dispatcher.rs index a860e070e..51acdcb2c 100644 --- a/pumpkin/src/command/dispatcher.rs +++ b/pumpkin/src/command/dispatcher.rs @@ -13,6 +13,7 @@ use crate::error::PumpkinError; use crate::server::Server; use pumpkin_core::text::color::{Color, NamedColor}; use std::collections::{HashMap, HashSet}; +use std::sync::Arc; #[derive(Debug)] pub(crate) enum CommandError { @@ -63,7 +64,7 @@ impl CommandDispatcher { pub async fn handle_command<'a>( &'a self, sender: &mut CommandSender<'a>, - server: &'a Server, + server: &'a Arc, cmd: &'a str, ) { if let Err(e) = self.dispatch(sender, server, cmd).await { @@ -149,7 +150,7 @@ impl CommandDispatcher { pub(crate) async fn dispatch<'a>( &'a self, src: &mut CommandSender<'a>, - server: &'a Server, + server: &'a Arc, cmd: &'a str, ) -> Result<(), CommandError> { // Other languages dont use the ascii whitespace @@ -208,7 +209,7 @@ impl CommandDispatcher { async fn try_is_fitting_path<'a>( src: &mut CommandSender<'a>, - server: &'a Server, + server: &'a Arc, path: &[usize], tree: &'a CommandTree, raw_args: &mut RawArgs<'a>, diff --git a/pumpkin/src/command/mod.rs b/pumpkin/src/command/mod.rs index aa1fa56d1..4725f71d3 100644 --- a/pumpkin/src/command/mod.rs +++ b/pumpkin/src/command/mod.rs @@ -98,7 +98,7 @@ impl<'a> CommandSender<'a> { } #[must_use] - pub fn world(&self) -> Option<&World> { + pub fn world(&self) -> Option<&Arc> { match self { // TODO: maybe return first world when console CommandSender::Console | CommandSender::Rcon(..) => None, @@ -140,7 +140,7 @@ pub(crate) trait CommandExecutor: Sync { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, - server: &Server, + server: &Arc, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError>; } diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 052d18c13..7202552db 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -1,7 +1,15 @@ +<<<<<<< HEAD use core::f32; use std::sync::{atomic::AtomicBool, Arc}; use crossbeam::atomic::AtomicCell; +======= +use crate::server::Server; +use crossbeam::atomic::AtomicCell; +use itertools::Itertools; +use num_derive::FromPrimitive; +use num_traits::real::Real; +>>>>>>> origin/item-dropping use pumpkin_core::math::{ boundingbox::{BoundingBox, BoundingBoxSize}, get_section_cord, @@ -11,16 +19,26 @@ use pumpkin_core::math::{ wrap_degrees, }; use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId}; +use pumpkin_protocol::client::play::{CEntityVelocity, CSpawnEntity, CUpdateEntityPos}; use pumpkin_protocol::{ client::play::{CHeadRot, CSetEntityMetadata, CTeleportEntity, CUpdateEntityRot, Metadata}, codec::var_int::VarInt, }; +use pumpkin_world::coordinates::ChunkRelativeBlockCoordinates; +use rand::Rng; +use std::sync::atomic::Ordering; +use std::sync::{atomic::AtomicBool, Arc}; +use uuid::Uuid; use crate::world::World; +<<<<<<< HEAD pub mod ai; pub mod mob; +======= +pub mod item; +>>>>>>> origin/item-dropping pub mod living; pub mod player; @@ -28,8 +46,12 @@ pub mod player; pub struct Entity { /// A unique identifier for the entity pub entity_id: EntityId, +<<<<<<< HEAD /// A persistant, unique identifier for the entity pub entity_uuid: uuid::Uuid, +======= + pub uuid: Uuid, +>>>>>>> origin/item-dropping /// The type of entity (e.g., player, zombie, item) pub entity_type: EntityType, /// The world in which the entity exists. @@ -50,6 +72,8 @@ pub struct Entity { pub velocity: AtomicCell>, /// Indicates whether the entity is on the ground (may not always be accurate). pub on_ground: AtomicBool, + /// Indicates whether the entity is inside of ground, and needs to be pushed out. + pub in_ground: AtomicBool, /// The entity's yaw rotation (horizontal rotation) ← → pub yaw: AtomicCell, /// The entity's head yaw rotation (horizontal rotation of the head) @@ -70,7 +94,11 @@ impl Entity { #[allow(clippy::too_many_arguments)] pub fn new( entity_id: EntityId, +<<<<<<< HEAD entity_uuid: uuid::Uuid, +======= + uuid: Uuid, +>>>>>>> origin/item-dropping world: Arc, position: Vector3, entity_type: EntityType, @@ -84,8 +112,13 @@ impl Entity { Self { entity_id, +<<<<<<< HEAD entity_uuid, +======= + uuid, +>>>>>>> origin/item-dropping entity_type, + in_ground: AtomicBool::new(false), on_ground: AtomicBool::new(false), pos: AtomicCell::new(position), block_pos: AtomicCell::new(WorldPosition(Vector3::new(floor_x, floor_y, floor_z))), @@ -202,6 +235,165 @@ impl Entity { self.world.remove_entity(self).await; } + pub async fn advance_position(&self) { + let velocity = self.velocity.load(); + let mut pos = self.pos.load().add(&velocity); + dbg!(pos.y); + self.collision_check(true).await; + let collision_y_pos = self.pos.load().y; + if (pos.y.ceil() - collision_y_pos.ceil()) > 1. { + pos.y = collision_y_pos; + } + self.set_pos(pos.x, pos.y, pos.z); + } + + async fn collision_check(&self, snap: bool) { + // TODO: Collision check with other entities. + + let pos = self.pos.load(); + let future_positions = self.add_velocity_block_by_block(); + + let mut chunks = vec![]; + for future_position in &future_positions { + // TODO Change rounding based on velocity direction + let x_section = get_section_cord(future_position.x.round() as i32); + let z_section = get_section_cord(future_position.z.round() as i32); + let chunk_pos = Vector2::new(x_section, z_section); + if !chunks.contains(&chunk_pos) { + chunks.push(chunk_pos); + } + } + + if chunks.is_empty() { + return; + } + let (_, mut chunks) = self.world.receive_chunks(&chunks); + + let mut passed_y_value = pos.y; + while let Some(chunk) = chunks.recv().await { + let chunk = chunk.read().await; + for future_position in &future_positions { + let (section_x, section_z) = ( + get_section_cord(future_position.x.round() as i32), + get_section_cord(future_position.z.round() as i32), + ); + // TODO: Add check for other blocks that affect collision, like water + if chunk.position.x != section_x || chunk.position.z != section_z { + continue; + } + + let block_id = + chunk + .blocks + .get_block(ChunkRelativeBlockCoordinates::from(Vector3 { + x: future_position.x.round(), + z: future_position.z.round(), + y: future_position.y.floor(), + })); + // Air check + + if block_id == 0 { + passed_y_value = passed_y_value.min(future_position.y); + self.on_ground.store(false, Ordering::Relaxed); + } else if pos.y > future_position.y || !self.on_ground.load(Ordering::Relaxed) { + passed_y_value = dbg!(passed_y_value.floor()); + let mut new_pos = pos; + new_pos.y = pos.y.floor(); + self.on_ground.store(true, Ordering::Relaxed); + if snap { + dbg!(passed_y_value); + self.set_pos(new_pos.x, passed_y_value, new_pos.z); + } + } + } + } + } + + #[allow(clippy::cast_precision_loss)] + fn add_velocity_block_by_block(&self) -> Vec> { + let velocity = self.velocity.load(); + let pos = self.pos.load(); + let blocks = |velocity: f64, out: &mut Vec, pos: f64| { + if velocity > 0. { + if velocity > 1. { + for i in (1..=(velocity.ceil() as i32)).rev() { + out.push(f64::from(i)); + } + } else { + out.push(1.); + } + } else if velocity < 0. { + if velocity < -1. { + for i in ((velocity.floor() as i32)..0).rev() { + out.push(f64::from(i)); + } + } else { + out.push(-1.); + } + } + out.iter_mut().for_each(|velocity| *velocity += pos.round()); + }; + + let mut x = vec![]; + let mut y = vec![]; + let mut z = vec![]; + blocks(velocity.x, &mut x, pos.x); + blocks(velocity.y, &mut y, pos.y); + blocks(velocity.z, &mut z, pos.z); + + let fix_length = |length: usize, other: &mut Vec| { + if other.len() < length { + let last = other.last().unwrap_or(&0.); + let first = other.first().unwrap_or(&0.); + let increment = (last - first) / length as f64; + *other = (0..length) + .map(|i| first + increment * i as f64) + .collect_vec(); + } + }; + let (x_len, y_len, z_len) = (x.len(), y.len(), z.len()); + if x_len >= y_len && x_len >= z_len { + fix_length(x_len, &mut y); + fix_length(x_len, &mut z); + } else if y_len >= x_len && y_len >= z_len { + fix_length(y_len, &mut x); + fix_length(y_len, &mut z); + } else if z_len >= x_len && z_len >= y_len { + fix_length(z_len, &mut x); + fix_length(z_len, &mut y); + } + + x.into_iter() + .zip(y) + .zip(z) + .map(|((x, y), z)| Vector3 { x, y, z }) + .collect_vec() + } + + pub async fn send_position(&self, old_position: Vector3, server: &Arc) { + let pos = self.pos.load(); + let (dx, dy, dz) = ( + pos.x.mul_add(4096., -(old_position.x * 4096.)), + pos.y.mul_add(4096., -(old_position.y * 4096.)), + pos.z.mul_add(4096., -(old_position.z * 4096.)), + ); + server + .broadcast_packet_all(&CUpdateEntityPos::new( + self.entity_id.into(), + dx as i16, + dy as i16, + dz as i16, + self.on_ground.load(Ordering::Relaxed), + )) + .await; + } + + pub async fn send_velocity(&self, server: &Arc) { + self.velocity.load(); + let entity_id = self.entity_id.into(); + let packet = CEntityVelocity::new(&entity_id, self.velocity.load()); + server.broadcast_packet_all(&packet).await; + } /// Applies knockback to the entity, following vanilla Minecraft's mechanics. /// /// This function calculates the entity's new velocity based on the specified knockback strength and direction. @@ -278,6 +470,33 @@ impl Entity { ); self.world.broadcast_packet_all(&packet).await; } + + // This gets run once per "tick" (tokio task sleeping to imitate tick) + pub fn apply_gravity(&self) { + let mut velocity = self.velocity.load(); + velocity.y -= self.entity_type.gravity(); + self.velocity.store(velocity); + } + + pub fn get_spawn_entity_packet(&self, data: Option) -> CSpawnEntity { + let pos = self.pos.load(); + let velocity = self.velocity.load(); + CSpawnEntity::new( + self.entity_id.into(), + self.uuid, + (self.entity_type as i32).into(), + pos.x, + pos.y, + pos.z, + self.pitch.load(), + self.yaw.load(), + self.head_yaw.load(), + data.unwrap_or(0).into(), + velocity.x, + velocity.y, + velocity.z, + ) + } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -305,3 +524,8 @@ pub enum Flag { /// Indicates if the entity is flying due to a fall. FallFlying = 7, } + +#[must_use] +pub fn random_float() -> f64 { + rand::thread_rng().gen_range(0.0..=1.0) +} diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index fd5d8619f..562904937 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -153,6 +153,7 @@ impl Player { }; Self { +<<<<<<< HEAD living_entity: LivingEntity::new_with_container( Entity::new( entity_id, @@ -166,6 +167,17 @@ impl Player { ), PlayerInventory::new(), ), +======= + living_entity: LivingEntity::new(Entity::new( + entity_id, + gameprofile.id, + world, + EntityType::Player, + 1.62, + AtomicCell::new(BoundingBox::new_default(&bounding_box_size)), + AtomicCell::new(bounding_box_size), + )), +>>>>>>> origin/item-dropping config: Mutex::new(config), gameprofile, client, @@ -738,7 +750,11 @@ impl Player { .await; } SPlayerAction::PACKET_ID => { +<<<<<<< HEAD self.handle_player_action(SPlayerAction::read(bytebuf)?, server) +======= + self.handle_player_action(server, SPlayerAction::read(bytebuf)?) +>>>>>>> origin/item-dropping .await; } SPlayerCommand::PACKET_ID => { @@ -758,7 +774,7 @@ impl Player { .await; } SSetCreativeSlot::PACKET_ID => { - self.handle_set_creative_slot(SSetCreativeSlot::read(bytebuf)?) + self.handle_set_creative_slot(server, SSetCreativeSlot::read(bytebuf)?) .await?; } SSwingArm::PACKET_ID => { diff --git a/pumpkin/src/net/combat.rs b/pumpkin/src/net/combat.rs index 12cb0a90f..33d826ab4 100644 --- a/pumpkin/src/net/combat.rs +++ b/pumpkin/src/net/combat.rs @@ -79,12 +79,16 @@ pub async fn handle_knockback( let entity_id = VarInt(victim_entity.entity_id); let victim_velocity = victim_entity.velocity.load(); +<<<<<<< HEAD:pumpkin/src/net/combat.rs let packet = &CEntityVelocity::new( &entity_id, victim_velocity.x, victim_velocity.y, victim_velocity.z, ); +======= + let packet = &CEntityVelocity::new(&entity_id, victim_velocity); +>>>>>>> origin/item-dropping:pumpkin/src/client/combat.rs let velocity = attacker_entity.velocity.load(); attacker_entity .velocity diff --git a/pumpkin/src/net/container.rs b/pumpkin/src/net/container.rs index 7132de477..0699929bd 100644 --- a/pumpkin/src/net/container.rs +++ b/pumpkin/src/net/container.rs @@ -3,7 +3,7 @@ use crate::server::Server; use pumpkin_core::text::TextComponent; use pumpkin_core::GameMode; use pumpkin_inventory::container_click::{ - Click, ClickType, KeyClick, MouseClick, MouseDragState, MouseDragType, + Click, ClickType, DropType, KeyClick, MouseClick, MouseDragState, MouseDragType, }; use pumpkin_inventory::drag_handler::DragHandler; use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait}; @@ -272,13 +272,31 @@ impl Player { self.mouse_drag(drag_handler, opened_container, drag_state) .await } - ClickType::DropType(_drop_type) => { - log::debug!("todo"); + ClickType::DropType(drop_type) => { + let slot = match click.slot { + container_click::Slot::Normal(slot) => slot, + container_click::Slot::OutsideInventory => Err(InventoryError::InvalidPacket)?, + }; + self.drop_items(opened_container, slot, drop_type).await?; Ok(()) } } } + pub async fn send_single_slot_inventory_change(&self, slot_index: usize) { + let mut inventory = self.inventory.lock().await; + inventory.state_id += 1; + let slot = Slot::from(inventory.all_combinable_slots()[slot_index]); + self.client + .send_packet(&CSetContainerSlot::new( + 0, + (inventory.state_id) as i32, + slot_index + 9, + &slot, + )) + .await; + } + async fn mouse_click( &self, opened_container: Option<&mut Box>, @@ -469,6 +487,44 @@ impl Player { } } + pub async fn drop_items( + &self, + opened_container: Option<&mut Box>, + slot: usize, + drop_type: DropType, + ) -> Result<(), InventoryError> { + let mut inventory = self.inventory.lock().await; + let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container); + let mut all_slots = container.all_slots(); + let Some(slot) = all_slots.get_mut(slot) else { + return Ok(()); + }; + let Some(item) = slot else { + return Ok(()); + }; + match drop_type { + DropType::FullStack => { + let dropped_item = *item; + **slot = None; + dropped_item + } + DropType::SingleItem => { + if item.item_count == 1 { + let dropped_item = *item; + **slot = None; + dropped_item + } else { + item.item_count -= 1; + let mut dropped_item = *item; + dropped_item.item_count = 1; + dropped_item + } + } + }; + + Ok(()) + } + async fn get_current_players_in_container(&self, server: &Server) -> Vec> { let player_ids: Vec = { let open_containers = server.open_containers.read().await; diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 893fa978c..4da531de4 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -3,6 +3,8 @@ use std::{collections::HashMap, sync::Arc}; pub mod level_time; pub mod player_chunker; +use crate::entity::item::ItemEntity; +use crate::server::Server; use crate::{ command::client_cmd_suggestions, entity::{living::LivingEntity, mob::MobEntity, player::Player, Entity}, @@ -14,7 +16,11 @@ use pumpkin_config::BasicConfiguration; use pumpkin_core::math::vector2::Vector2; use pumpkin_core::math::{position::WorldPosition, vector3::Vector3}; use pumpkin_core::text::{color::NamedColor, TextComponent}; +<<<<<<< HEAD use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId}; +======= +use pumpkin_entity::EntityId; +>>>>>>> origin/item-dropping use pumpkin_protocol::{ client::play::CLevelEvent, codec::{identifier::Identifier, var_int::VarInt}, @@ -26,11 +32,15 @@ use pumpkin_protocol::{ use pumpkin_protocol::{ client::play::{ CChunkData, CGameEvent, CLogin, CPlayerInfoUpdate, CRemoveEntities, CRemovePlayerInfo, - CSetEntityMetadata, CSpawnEntity, GameEvent, Metadata, PlayerAction, + CSetEntityMetadata, GameEvent, Metadata, PlayerAction, }, ClientPacket, }; +<<<<<<< HEAD use pumpkin_registry::DimensionType; +======= +use pumpkin_world::block::block_registry::get_block_by_id; +>>>>>>> origin/item-dropping use pumpkin_world::chunk::ChunkData; use pumpkin_world::level::Level; use pumpkin_world::{ @@ -105,6 +115,7 @@ pub struct World { /// The type of dimension the world is in pub dimension_type: DimensionType, // TODO: entities + pub items: Arc>>>, // TODO: entities } impl World { @@ -113,7 +124,11 @@ impl World { Self { level: Arc::new(level), current_players: Arc::new(Mutex::new(HashMap::new())), +<<<<<<< HEAD current_living_mobs: Arc::new(Mutex::new(HashMap::new())), +======= + items: Arc::new(Mutex::new(HashMap::new())), +>>>>>>> origin/item-dropping scoreboard: Mutex::new(Scoreboard::new()), worldborder: Mutex::new(Worldborder::new(0.0, 0.0, 29_999_984.0, 0, 0, 0)), level_time: Mutex::new(LevelTime::new()), @@ -340,28 +355,12 @@ impl World { .await; }; - let gameprofile = &player.gameprofile; - log::debug!("Broadcasting player spawn for {}", player.gameprofile.name); // spawn player for every client self.broadcast_packet_except( &[player.gameprofile.id], // TODO: add velo - &CSpawnEntity::new( - entity_id.into(), - gameprofile.id, - (EntityType::Player as i32).into(), - position.x, - position.y, - position.z, - pitch, - yaw, - yaw, - 0.into(), - 0.0, - 0.0, - 0.0, - ), + &player.living_entity.entity.get_spawn_entity_packet(None), ) .await; // spawn players for our client @@ -374,26 +373,9 @@ impl World { .filter(|c| c.0 != &id) { let entity = &existing_player.living_entity.entity; - let pos = entity.pos.load(); - let gameprofile = &existing_player.gameprofile; - log::debug!("Sending player entities to {}", player.gameprofile.name); player .client - .send_packet(&CSpawnEntity::new( - existing_player.entity_id().into(), - gameprofile.id, - (EntityType::Player as i32).into(), - pos.x, - pos.y, - pos.z, - entity.yaw.load(), - entity.pitch.load(), - entity.head_yaw.load(), - 0.into(), - 0.0, - 0.0, - 0.0, - )) + .send_packet(&entity.get_spawn_entity_packet(None)) .await; } // entity meta data @@ -877,12 +859,27 @@ impl World { chunk } - pub async fn break_block(&self, position: WorldPosition, cause: Option<&Player>) { + pub async fn break_block( + self: &Arc, + position: WorldPosition, + cause: Option<&Player>, + server: Arc, + ) { let broken_block_state_id = self.set_block_state(position, 0).await; let particles_packet = CWorldEvent::new(2001, &position, broken_block_state_id.into(), false); + if let Some(item) = get_block_by_id(broken_block_state_id).map(|block| block.to_item(1)) { + ItemEntity::spawn( + Vector3::default(), + Vector3::default(), + self.clone(), + item, + server, + ) + .await; + } match cause { Some(player) => { self.broadcast_packet_except(&[player.gameprofile.id], &particles_packet) From d099db72551ab4131170f80b7a452fadd577372f Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:06:13 +0100 Subject: [PATCH 02/34] Update Cargo.toml --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4dfc13f9e..2414b9830 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,11 +55,8 @@ uuid = { version = "1.11.0", features = ["serde", "v3", "v4"] } derive_more = { version = "1.0.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -<<<<<<< HEAD -======= itertools = "0.13.0" [profile.dev] opt-level = 2 ->>>>>>> origin/item-dropping From 34b287c0b193fa78827440820f311bef96f19ab6 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:07:10 +0100 Subject: [PATCH 03/34] Update Cargo.toml --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2414b9830..3fe9fbd0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,3 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" itertools = "0.13.0" - -[profile.dev] -opt-level = 2 From c38a4087046fa32b400ca2c057d9991ce512b5c1 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:10:21 +0100 Subject: [PATCH 04/34] Update entity_type.rs --- pumpkin-entity/src/entity_type.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pumpkin-entity/src/entity_type.rs b/pumpkin-entity/src/entity_type.rs index 9c450601d..e22ca0e9b 100644 --- a/pumpkin-entity/src/entity_type.rs +++ b/pumpkin-entity/src/entity_type.rs @@ -1,10 +1,5 @@ -<<<<<<< HEAD // TODO make this dynamic #[derive(Clone)] -======= -// TODO -#[derive(Clone, Copy)] ->>>>>>> origin/item-dropping #[repr(i32)] pub enum EntityType { AcaciaBoat = 0, From 4afe49e6ae93efbf6fb62ee93a81ec6de318a940 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:13:44 +0100 Subject: [PATCH 05/34] Update position.rs --- pumpkin-core/src/math/position.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pumpkin-core/src/math/position.rs b/pumpkin-core/src/math/position.rs index d9dab5ffe..a3b82cbeb 100644 --- a/pumpkin-core/src/math/position.rs +++ b/pumpkin-core/src/math/position.rs @@ -5,11 +5,7 @@ use crate::math::vector2::Vector2; use num_traits::Euclid; use serde::{Deserialize, Serialize}; -<<<<<<< HEAD #[derive(Clone, Copy, PartialEq, Eq)] -======= -#[derive(Clone, Copy, Default)] ->>>>>>> origin/item-dropping /// Aka Block Position pub struct WorldPosition(pub Vector3); From 10f7337e341c3d46703b920398392cf6e3bc526e Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:21:53 +0100 Subject: [PATCH 06/34] Update vector2.rs --- pumpkin-core/src/math/vector2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin-core/src/math/vector2.rs b/pumpkin-core/src/math/vector2.rs index b386643b4..1f8317917 100644 --- a/pumpkin-core/src/math/vector2.rs +++ b/pumpkin-core/src/math/vector2.rs @@ -4,7 +4,7 @@ use num_traits::Float; use super::vector3::Vector3; -#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq, Default)] +#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)] pub struct Vector2 { pub x: T, pub z: T, From 0e6ff5a688ee093df963ecf2c8b54fdd072c600d Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:23:35 +0100 Subject: [PATCH 07/34] Update vector3.rs --- pumpkin-core/src/math/vector3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin-core/src/math/vector3.rs b/pumpkin-core/src/math/vector3.rs index ec3cf0173..0edb1561e 100644 --- a/pumpkin-core/src/math/vector3.rs +++ b/pumpkin-core/src/math/vector3.rs @@ -3,7 +3,7 @@ use std::ops::{Add, AddAssign, Div, Mul, Sub}; use num_traits::Float; -#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq, Default)] +#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)] pub struct Vector3 { pub x: T, pub y: T, From c709463074f13303d8a49e07eb5cbd77cb2dafce Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:24:57 +0100 Subject: [PATCH 08/34] Update vector3.rs --- pumpkin-core/src/math/vector3.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pumpkin-core/src/math/vector3.rs b/pumpkin-core/src/math/vector3.rs index 0edb1561e..23b877ece 100644 --- a/pumpkin-core/src/math/vector3.rs +++ b/pumpkin-core/src/math/vector3.rs @@ -74,9 +74,9 @@ impl std::iter::Sum for Vector3 { let mut y = T::default(); let mut z = T::default(); for vec in iter { - x = x + vec.x; - y = y + vec.y; - z = z + vec.z; + x += vec.x + y += vec.y + z += vec.z } Vector3 { x, y, z } } From 6e27368e8068ec56ba0ac1577075e023eebd65b9 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:26:51 +0100 Subject: [PATCH 09/34] Update vector3.rs --- pumpkin-core/src/math/vector3.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pumpkin-core/src/math/vector3.rs b/pumpkin-core/src/math/vector3.rs index 23b877ece..1ffbdf821 100644 --- a/pumpkin-core/src/math/vector3.rs +++ b/pumpkin-core/src/math/vector3.rs @@ -74,9 +74,9 @@ impl std::iter::Sum for Vector3 { let mut y = T::default(); let mut z = T::default(); for vec in iter { - x += vec.x - y += vec.y - z += vec.z + x += vec.x; + y += vec.y; + z += vec.z; } Vector3 { x, y, z } } From 6583ee9b76c5b0b9b5750d637f4f824fc30fe0d4 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:31:06 +0100 Subject: [PATCH 10/34] Update item_registry.rs --- pumpkin-world/src/item/item_registry.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pumpkin-world/src/item/item_registry.rs b/pumpkin-world/src/item/item_registry.rs index 222727117..704840c31 100644 --- a/pumpkin-world/src/item/item_registry.rs +++ b/pumpkin-world/src/item/item_registry.rs @@ -36,10 +36,6 @@ pub fn get_spawn_egg(item_id: u16) -> Option { None } -pub fn get_item_by_id(id: u16) -> Option<&'static Item> { - ITEMS.values().find(|item| item.id == id) -} - #[derive(Deserialize, Clone, Debug)] pub struct Item { pub id: u16, From a34fc2f049db5cf33c0c3a9672bf901a38fff1d7 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:34:20 +0100 Subject: [PATCH 11/34] Update c_entity_velocity.rs --- pumpkin-protocol/src/client/play/c_entity_velocity.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pumpkin-protocol/src/client/play/c_entity_velocity.rs b/pumpkin-protocol/src/client/play/c_entity_velocity.rs index 728fd751c..d8f349e2b 100644 --- a/pumpkin-protocol/src/client/play/c_entity_velocity.rs +++ b/pumpkin-protocol/src/client/play/c_entity_velocity.rs @@ -13,11 +13,7 @@ pub struct CEntityVelocity<'a> { } impl<'a> CEntityVelocity<'a> { -<<<<<<< HEAD pub fn new(entity_id: &'a VarInt, velocity_x: f64, velocity_y: f64, velocity_z: f64) -> Self { -======= - pub fn new(entity_id: &'a VarInt, velocity: Vector3) -> Self { ->>>>>>> origin/item-dropping Self { entity_id, velocity_x: (velocity.x.clamp(-3.9, 3.9) * 8000.0) as i16, From 09af356b0aabfcaf82c0d9d106c0c7bb73e641dc Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:44:32 +0100 Subject: [PATCH 12/34] Update c_entity_velocity.rs --- pumpkin-protocol/src/client/play/c_entity_velocity.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pumpkin-protocol/src/client/play/c_entity_velocity.rs b/pumpkin-protocol/src/client/play/c_entity_velocity.rs index d8f349e2b..03bdcb031 100644 --- a/pumpkin-protocol/src/client/play/c_entity_velocity.rs +++ b/pumpkin-protocol/src/client/play/c_entity_velocity.rs @@ -16,9 +16,9 @@ impl<'a> CEntityVelocity<'a> { pub fn new(entity_id: &'a VarInt, velocity_x: f64, velocity_y: f64, velocity_z: f64) -> Self { Self { 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, + 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, } } } From 99f9e2b39fea60f275a689d4aed4d14ae4cb5771 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:49:47 +0100 Subject: [PATCH 13/34] Create c_pickup_item.rs --- .../src/client/play/c_pickup_item.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 pumpkin-protocol/src/client/play/c_pickup_item.rs diff --git a/pumpkin-protocol/src/client/play/c_pickup_item.rs b/pumpkin-protocol/src/client/play/c_pickup_item.rs new file mode 100644 index 000000000..9b4de467e --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_pickup_item.rs @@ -0,0 +1,28 @@ +use crate::VarInt; +use pumpkin_macros::client_packet; +use serde::Serialize; +#[client_packet("play:take_item_entity")] +#[derive(Serialize)] +pub struct CPickupItem { + collected_entity_id: VarInt, + collector_entity_id: VarInt, + amount: VarInt, +} + +impl CPickupItem { + pub fn new_item(item_id: VarInt, player_id: VarInt, item_amount: u8) -> Self { + Self { + collected_entity_id: item_id, + collector_entity_id: player_id, + amount: (item_amount as i32).into(), + } + } + + pub fn new_xp(item_id: VarInt, player_id: VarInt) -> Self { + Self { + collected_entity_id: item_id, + collector_entity_id: player_id, + amount: 1.into(), + } + } +} From 9ab636774de2decc2ec43e85e21d92c07281f0b5 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:53:12 +0100 Subject: [PATCH 14/34] Update c_entity_velocity.rs --- pumpkin-protocol/src/client/play/c_entity_velocity.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pumpkin-protocol/src/client/play/c_entity_velocity.rs b/pumpkin-protocol/src/client/play/c_entity_velocity.rs index 03bdcb031..30266ea87 100644 --- a/pumpkin-protocol/src/client/play/c_entity_velocity.rs +++ b/pumpkin-protocol/src/client/play/c_entity_velocity.rs @@ -1,4 +1,3 @@ -use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::client_packet; use serde::Serialize; use crate::VarInt; From 7ea190f5853d62a5b8b8ff1769df2299765c1a05 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:59:23 +0100 Subject: [PATCH 15/34] Update container_click.rs --- pumpkin-inventory/src/container_click.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/pumpkin-inventory/src/container_click.rs b/pumpkin-inventory/src/container_click.rs index d5bf3ec29..a69aacb44 100644 --- a/pumpkin-inventory/src/container_click.rs +++ b/pumpkin-inventory/src/container_click.rs @@ -8,28 +8,23 @@ pub struct Click { } impl Click { - pub fn new(mode: SlotActionType, button: i8, slot: i16) -> Result { + pub fn new(mode: u8, button: i8, slot: i16) -> Result { match mode { - SlotActionType::Pickup => Self::new_normal_click(button, slot), + 0 => Self::new_normal_click(button, slot), // Both buttons do the same here, so we omit it - SlotActionType::QuickMove => Self::new_shift_click(slot), - SlotActionType::Swap => Self::new_key_click(button, slot), - SlotActionType::Clone => Ok(Self { + 1 => Self::new_shift_click(slot), + 2 => Self::new_key_click(button, slot), + 3 => Ok(Self { click_type: ClickType::CreativePickItem, slot: Slot::Normal(slot.try_into().or(Err(InventoryError::InvalidSlot))?), }), -<<<<<<< HEAD - SlotActionType::Throw => Self::new_drop_item(button), - SlotActionType::QuickCraft => Self::new_drag_item(button, slot), - SlotActionType::PickupAll => Ok(Self { -======= 4 => Self::new_drop_item(button, slot), 5 => Self::new_drag_item(button, slot), 6 => Ok(Self { ->>>>>>> origin/item-dropping click_type: ClickType::DoubleClick, slot: Slot::Normal(slot.try_into().or(Err(InventoryError::InvalidSlot))?), }), + _ => Err(InventoryError::InvalidPacket), } } From 2598e6b891c0bb3debffd07cc067499f16255468 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:12:39 +0100 Subject: [PATCH 16/34] Update Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3fe9fbd0e..6f5653c59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,4 +56,4 @@ derive_more = { version = "1.0.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -itertools = "0.13.0" +itertools = "0.14.0" From f80cbcabf8ae0b9a30fa6813713fdf69acccde07 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:16:19 +0100 Subject: [PATCH 17/34] Update main.rs --- pumpkin/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index fb18b1772..65cbc7163 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -46,6 +46,8 @@ use tokio::signal::unix::{signal, SignalKind}; use std::sync::Arc; +use itertools::Itertools; + use crate::server::CURRENT_MC_VERSION; use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_core::text::{color::NamedColor, TextComponent}; From e6d236f45b0d59aebc5047ef135c6f6afd2d4a3a Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:25:43 +0100 Subject: [PATCH 18/34] Update Cargo.toml --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 6f5653c59..3c47a090a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,9 @@ debug = true inherits = "release" debug = true +[lib] +crate-type = ["cdylib", "rlib"] + [workspace.dependencies] log = "0.4" tokio = { version = "1.42", features = [ From 18f12dafee09e8f7cb7d62caebd577d3102ab057 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:29:10 +0100 Subject: [PATCH 19/34] Update Cargo.toml --- Cargo.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3c47a090a..f2ec3facb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,9 +31,6 @@ debug = true inherits = "release" debug = true -[lib] -crate-type = ["cdylib", "rlib"] - [workspace.dependencies] log = "0.4" tokio = { version = "1.42", features = [ @@ -53,10 +50,9 @@ bytes = "1.9" rayon = "1.10.0" parking_lot = { version = "0.12.3", features = ["send_guard"] } crossbeam = "0.8.4" +itertools = "0.13.0" uuid = { version = "1.11.0", features = ["serde", "v3", "v4"] } derive_more = { version = "1.0.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" - -itertools = "0.14.0" From 199f7e5e9300b246807ac1956bd92c0c9168919d Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:33:19 +0100 Subject: [PATCH 20/34] Update Cargo.toml --- pumpkin-inventory/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pumpkin-inventory/Cargo.toml b/pumpkin-inventory/Cargo.toml index 3fe57edc0..2259d0d90 100644 --- a/pumpkin-inventory/Cargo.toml +++ b/pumpkin-inventory/Cargo.toml @@ -4,6 +4,7 @@ version.workspace = true edition.workspace = true [dependencies] +itertools = "0.13.0" pumpkin-protocol = { path = "../pumpkin-protocol" } pumpkin-world = { path = "../pumpkin-world" } From ff26afa08508e19dd09d970ab25a7ceb22412395 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:35:34 +0100 Subject: [PATCH 21/34] Update cmd_help.rs --- pumpkin/src/command/commands/cmd_help.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pumpkin/src/command/commands/cmd_help.rs b/pumpkin/src/command/commands/cmd_help.rs index 352423d7e..4077bc074 100644 --- a/pumpkin/src/command/commands/cmd_help.rs +++ b/pumpkin/src/command/commands/cmd_help.rs @@ -104,13 +104,8 @@ impl CommandExecutor for BaseHelpExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, -<<<<<<< HEAD server: &Server, args: &ConsumedArgs<'a>, -======= - server: &Arc, - _args: &ConsumedArgs<'a>, ->>>>>>> origin/item-dropping ) -> Result<(), CommandError> { let page_number = match page_number_consumer().find_arg_default_name(args) { Err(_) => 1, From 9394c8009d5ae01c2efafd60a8392ed71fe86a6c Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:37:28 +0100 Subject: [PATCH 22/34] Update cmd_pumpkin.rs --- pumpkin/src/command/commands/cmd_pumpkin.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/pumpkin/src/command/commands/cmd_pumpkin.rs b/pumpkin/src/command/commands/cmd_pumpkin.rs index c0a7b88a1..8d82a52c0 100644 --- a/pumpkin/src/command/commands/cmd_pumpkin.rs +++ b/pumpkin/src/command/commands/cmd_pumpkin.rs @@ -3,11 +3,8 @@ use pumpkin_core::text::click::ClickEvent; use pumpkin_core::text::hover::HoverEvent; use pumpkin_core::text::{color::NamedColor, TextComponent}; use pumpkin_protocol::CURRENT_MC_PROTOCOL; -<<<<<<< HEAD use std::borrow::Cow; -======= use std::sync::Arc; ->>>>>>> origin/item-dropping use crate::{ command::{ From 21d43e74109e9148a55a634f26a5948438ab52f8 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:38:16 +0100 Subject: [PATCH 23/34] Update cmd_transfer.rs --- pumpkin/src/command/commands/cmd_transfer.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/pumpkin/src/command/commands/cmd_transfer.rs b/pumpkin/src/command/commands/cmd_transfer.rs index 661e60711..781d19f2c 100644 --- a/pumpkin/src/command/commands/cmd_transfer.rs +++ b/pumpkin/src/command/commands/cmd_transfer.rs @@ -2,12 +2,9 @@ use async_trait::async_trait; use pumpkin_core::text::color::{Color, NamedColor}; use pumpkin_core::text::TextComponent; use pumpkin_protocol::client::play::CTransfer; -<<<<<<< HEAD use pumpkin_protocol::codec::var_int::VarInt; -======= use pumpkin_protocol::VarInt; use std::sync::Arc; ->>>>>>> origin/item-dropping use crate::command::args::arg_bounded_num::BoundedNumArgumentConsumer; use crate::command::args::arg_players::PlayersArgumentConsumer; From ec634679d2fb82fbb5bf944245a07bab5996e28e Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:41:37 +0100 Subject: [PATCH 24/34] Update player.rs --- pumpkin/src/entity/player.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 562904937..9e9aaebfd 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -153,7 +153,6 @@ impl Player { }; Self { -<<<<<<< HEAD living_entity: LivingEntity::new_with_container( Entity::new( entity_id, @@ -167,17 +166,6 @@ impl Player { ), PlayerInventory::new(), ), -======= - living_entity: LivingEntity::new(Entity::new( - entity_id, - gameprofile.id, - world, - EntityType::Player, - 1.62, - AtomicCell::new(BoundingBox::new_default(&bounding_box_size)), - AtomicCell::new(bounding_box_size), - )), ->>>>>>> origin/item-dropping config: Mutex::new(config), gameprofile, client, @@ -750,11 +738,7 @@ impl Player { .await; } SPlayerAction::PACKET_ID => { -<<<<<<< HEAD self.handle_player_action(SPlayerAction::read(bytebuf)?, server) -======= - self.handle_player_action(server, SPlayerAction::read(bytebuf)?) ->>>>>>> origin/item-dropping .await; } SPlayerCommand::PACKET_ID => { From 8aa6bd7b242a3ba7f950ce73edeed3a6822e6714 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:45:11 +0100 Subject: [PATCH 25/34] Update mod.rs --- pumpkin/src/entity/mod.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 7202552db..d4cea15e7 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -1,15 +1,12 @@ -<<<<<<< HEAD use core::f32; use std::sync::{atomic::AtomicBool, Arc}; use crossbeam::atomic::AtomicCell; -======= use crate::server::Server; use crossbeam::atomic::AtomicCell; use itertools::Itertools; use num_derive::FromPrimitive; use num_traits::real::Real; ->>>>>>> origin/item-dropping use pumpkin_core::math::{ boundingbox::{BoundingBox, BoundingBoxSize}, get_section_cord, @@ -32,13 +29,10 @@ use uuid::Uuid; use crate::world::World; -<<<<<<< HEAD pub mod ai; pub mod mob; -======= pub mod item; ->>>>>>> origin/item-dropping pub mod living; pub mod player; @@ -46,12 +40,9 @@ pub mod player; pub struct Entity { /// A unique identifier for the entity pub entity_id: EntityId, -<<<<<<< HEAD /// A persistant, unique identifier for the entity pub entity_uuid: uuid::Uuid, -======= pub uuid: Uuid, ->>>>>>> origin/item-dropping /// The type of entity (e.g., player, zombie, item) pub entity_type: EntityType, /// The world in which the entity exists. @@ -94,11 +85,8 @@ impl Entity { #[allow(clippy::too_many_arguments)] pub fn new( entity_id: EntityId, -<<<<<<< HEAD entity_uuid: uuid::Uuid, -======= uuid: Uuid, ->>>>>>> origin/item-dropping world: Arc, position: Vector3, entity_type: EntityType, @@ -112,11 +100,8 @@ impl Entity { Self { entity_id, -<<<<<<< HEAD entity_uuid, -======= uuid, ->>>>>>> origin/item-dropping entity_type, in_ground: AtomicBool::new(false), on_ground: AtomicBool::new(false), From d854db4036b27b9408bfa874e63d2692b5148920 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:45:55 +0100 Subject: [PATCH 26/34] Update container_click.rs --- pumpkin-inventory/src/container_click.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pumpkin-inventory/src/container_click.rs b/pumpkin-inventory/src/container_click.rs index a69aacb44..539ccdcaa 100644 --- a/pumpkin-inventory/src/container_click.rs +++ b/pumpkin-inventory/src/container_click.rs @@ -1,5 +1,4 @@ use crate::InventoryError; -use pumpkin_protocol::server::play::SlotActionType; use pumpkin_world::item::ItemStack; pub struct Click { From e62b8ff3e9aaaa582e0436709da9431c5cd9fbea Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:48:01 +0100 Subject: [PATCH 27/34] Update combat.rs --- pumpkin/src/net/combat.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pumpkin/src/net/combat.rs b/pumpkin/src/net/combat.rs index 33d826ab4..12cb0a90f 100644 --- a/pumpkin/src/net/combat.rs +++ b/pumpkin/src/net/combat.rs @@ -79,16 +79,12 @@ pub async fn handle_knockback( let entity_id = VarInt(victim_entity.entity_id); let victim_velocity = victim_entity.velocity.load(); -<<<<<<< HEAD:pumpkin/src/net/combat.rs let packet = &CEntityVelocity::new( &entity_id, victim_velocity.x, victim_velocity.y, victim_velocity.z, ); -======= - let packet = &CEntityVelocity::new(&entity_id, victim_velocity); ->>>>>>> origin/item-dropping:pumpkin/src/client/combat.rs let velocity = attacker_entity.velocity.load(); attacker_entity .velocity From 743e9edae07b5abe782dd38ecf3f24350a198604 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:50:34 +0100 Subject: [PATCH 28/34] Update mod.rs --- pumpkin/src/world/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 4da531de4..d221ebfde 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -16,11 +16,7 @@ use pumpkin_config::BasicConfiguration; use pumpkin_core::math::vector2::Vector2; use pumpkin_core::math::{position::WorldPosition, vector3::Vector3}; use pumpkin_core::text::{color::NamedColor, TextComponent}; -<<<<<<< HEAD use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId}; -======= -use pumpkin_entity::EntityId; ->>>>>>> origin/item-dropping use pumpkin_protocol::{ client::play::CLevelEvent, codec::{identifier::Identifier, var_int::VarInt}, From 7fc8c445167d9e3a53dac6855ddb55df3e8967fc Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:52:13 +0100 Subject: [PATCH 29/34] Update mod.rs --- pumpkin/src/world/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index d221ebfde..a12b37365 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -32,16 +32,12 @@ use pumpkin_protocol::{ }, ClientPacket, }; -<<<<<<< HEAD use pumpkin_registry::DimensionType; -======= -use pumpkin_world::block::block_registry::get_block_by_id; ->>>>>>> origin/item-dropping use pumpkin_world::chunk::ChunkData; use pumpkin_world::level::Level; use pumpkin_world::{ block::block_registry::{ - get_block_and_state_by_state_id, get_block_by_state_id, get_state_by_state_id, + get_block_and_state_by_state_id, get_block_by_id, get_block_by_state_id, get_state_by_state_id, }, coordinates::ChunkRelativeBlockCoordinates, }; From e3650a2734ebd093a4d3495a5256bcf18c117b95 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:54:20 +0100 Subject: [PATCH 30/34] Create item.rs --- pumpkin/src/entity/item.rs | 241 +++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 pumpkin/src/entity/item.rs diff --git a/pumpkin/src/entity/item.rs b/pumpkin/src/entity/item.rs new file mode 100644 index 000000000..d4d097181 --- /dev/null +++ b/pumpkin/src/entity/item.rs @@ -0,0 +1,241 @@ +use crate::entity::player::Player; +use crate::entity::{random_float, Entity}; +use crate::server::Server; +use crate::world::World; +use pumpkin_core::math::boundingbox::{BoundingBox, BoundingBoxSize}; +use pumpkin_core::math::vector3::Vector3; +use pumpkin_entity::entity_type::EntityType; +use pumpkin_entity::EntityId; +use pumpkin_inventory::Container; +use pumpkin_protocol::client::play::{CPickupItem, CSetEntityMetadata, Metadata}; +use pumpkin_protocol::slot::Slot; +use pumpkin_world::item::item_registry::get_item_by_id; +use pumpkin_world::item::ItemStack; +use rayon::prelude::*; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::time::Duration; +use uuid::Uuid; + +pub struct ItemEntity { + pub item_stack: ItemStack, + is_able_to_be_picked_up: Arc, + pub entity: Arc, +} + +impl ItemEntity { + pub async fn spawn( + pos: Vector3, + velocity: Vector3, + world: Arc, + item_stack: ItemStack, + server: Arc, + ) { + let is_able_to_be_picked_up = Arc::new(AtomicBool::new(false)); + { + let is_able_to_be_picked_up = is_able_to_be_picked_up.clone(); + tokio::spawn(async move { + tokio::time::sleep(Duration::from_secs(2)).await; + is_able_to_be_picked_up.store(true, std::sync::atomic::Ordering::Relaxed); + }); + } + + let bounding_box_size = BoundingBoxSize { + width: 0.5, + height: 0.5, + }; + let entity = Arc::new(Entity::new( + server.new_entity_id(), + Uuid::new_v4(), + world, + EntityType::Item, + 0., + BoundingBox::new_default(&bounding_box_size).into(), + bounding_box_size.into(), + )); + entity.velocity.store(velocity); + entity.set_pos(pos.x, pos.y, pos.z); + + let item_entity = Self { + item_stack, + is_able_to_be_picked_up, + entity: entity.clone(), + }; + + server + .broadcast_packet_all(&entity.get_spawn_entity_packet(None)) + .await; + { + let server = server.clone(); + tokio::spawn(async move { item_entity.drop_loop(server).await }); + } + let metadata = Metadata::new(8, 7.into(), Slot::from(&item_stack)); + server + .broadcast_packet_all(&CSetEntityMetadata::new(entity.entity_id.into(), metadata)) + .await; + } + pub async fn spawn_from_player( + player_entity: &Entity, + item_stack: ItemStack, + server: Arc, + ) { + let player_pos = player_entity.pos.load(); + let pos = Vector3 { + x: player_pos.x, + y: player_pos.y + f64::from(player_entity.standing_eye_height) - 0.3, + z: player_pos.z, + }; + Self::spawn( + pos, + toss_velocity(player_entity), + player_entity.world.clone(), + item_stack, + server, + ) + .await; + } + + pub(self) async fn check_pickup(self) -> PickupEvent { + if !self.is_able_to_be_picked_up.load(Ordering::Relaxed) { + return PickupEvent::NotPickedUp(self); + } + + let pos = self.entity.pos.load(); + for player in self.entity.world.current_players.lock().await.values() { + let player_pos = player.living_entity.entity.pos.load(); + if (pos.x - player_pos.x).abs() <= 1. + && (pos.z - player_pos.z).abs() <= 1. + && (pos.y - player_pos.y).abs() <= 1. + { + let inventory = player.inventory.lock().await; + if inventory.all_combinable_slots().par_iter().any(|slot| { + match slot { + None => true, + // TODO: Add check for max stack size here + Some(slot) => { + slot.item_id == self.item_stack.item_id + && slot.item_count + self.item_stack.item_count <= 64 + } + } + }) { + drop(inventory); + return PickupEvent::PickedUp { + entity_id: self.entity.entity_id, + item: self.item_stack, + player: player.clone(), + }; + } + } + } + PickupEvent::NotPickedUp(self) + } + + async fn handle_pickup( + entity_id: EntityId, + player: Arc, + dropped_item: ItemStack, + server: Arc, + ) { + server + .broadcast_packet_all(&CPickupItem::new_item( + entity_id.into(), + player.living_entity.entity.entity_id.into(), + dropped_item.item_count, + )) + .await; + let Some(item) = get_item_by_id(dropped_item.item_id) else { + return; + }; + player + .give_items(item, u32::from(dropped_item.item_count)) + .await; + } + + async fn drop_loop(mut self, server: Arc) { + let mut interval = tokio::time::interval(Duration::from_millis(1000 / 20)); + let mut ticks = 0; + loop { + interval.tick().await; + { + match self.check_pickup().await { + PickupEvent::PickedUp { + entity_id, + player, + item: dropped_item, + } => { + Self::handle_pickup(entity_id, player, dropped_item, server).await; + break; + } + PickupEvent::NotPickedUp(s) => { + self = s; + } + } + } + let old_position = self.entity.pos.load(); + self.entity.apply_gravity(); + /*if self.entity.on_ground.load(Ordering::Relaxed) { + let mut pos = self.entity.pos.load(); + pos.y = pos.y.ceil(); + let velocity = self.entity.velocity.load().multiply(1.,0.,1.); + self.entity.velocity.store(velocity); + self.entity.set_pos(pos.x,pos.y,pos.z); + dbg!(self.entity.pos.load().y); + }*/ + //self.entity.bounds_check().await; + let on_ground = self.entity.on_ground.load(Ordering::Relaxed); + if !on_ground || self.entity.velocity.load().horizontal_length_squared() > 1.0e-5 + //|| ticks % 4 == 0 + { + self.entity.advance_position().await; + let on_ground = self.entity.on_ground.load(Ordering::Relaxed); + let slipperiness = 0.98 * if on_ground { 0.6 } else { 1. }; + + let mut velocity = + self.entity + .velocity + .load() + .multiply(slipperiness, 0.98, slipperiness); + if velocity.length_squared() < 1.0e-10 { + velocity.z = 0.; + velocity.y = 0.; + velocity.x = 0.; + let pos = self.entity.pos.load(); + } + if on_ground && velocity.y.is_sign_negative() { + velocity = velocity.multiply(1., -0.5, 1.); + } + + self.entity.velocity.store(velocity); + self.entity.send_velocity(&server).await; + } + + self.entity.send_position(old_position, &server).await; + ticks += 1; + } + } +} + +enum PickupEvent { + PickedUp { + entity_id: EntityId, + item: ItemStack, + player: Arc, + }, + NotPickedUp(ItemEntity), +} + +fn toss_velocity(player: &Entity) -> Vector3 { + use std::f64::consts::PI; + let pitch_sin = f64::sin(f64::from(player.pitch.load()) * (PI / 180.0)); + let pitch_cos = f64::cos(f64::from(player.pitch.load()) * (PI / 180.0)); + let yaw_sin = f64::sin(f64::from(player.yaw.load()) * (PI / 180.0)); + let yaw_cos = f64::cos(f64::from(player.yaw.load()) * (PI / 180.0)); + let random_angle = random_float() * (2.0 * PI); + let random_offset = 0.02 * random_float(); + + Vector3 { + x: (-yaw_sin * pitch_cos).mul_add(0.3, f64::cos(random_angle) * random_offset), + y: (-pitch_sin).mul_add(0.3, (random_float() - random_float()).mul_add(0.1, 0.1)), + z: (yaw_cos * pitch_cos).mul_add(0.3, f64::sin(random_angle) * random_offset), + } +} From 8d7e1c10037128bafc4da436906e4b816937b2c8 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:55:30 +0100 Subject: [PATCH 31/34] Update mod.rs --- pumpkin/src/world/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index a12b37365..3c42d8188 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -116,11 +116,8 @@ impl World { Self { level: Arc::new(level), current_players: Arc::new(Mutex::new(HashMap::new())), -<<<<<<< HEAD current_living_mobs: Arc::new(Mutex::new(HashMap::new())), -======= items: Arc::new(Mutex::new(HashMap::new())), ->>>>>>> origin/item-dropping scoreboard: Mutex::new(Scoreboard::new()), worldborder: Mutex::new(Worldborder::new(0.0, 0.0, 29_999_984.0, 0, 0, 0)), level_time: Mutex::new(LevelTime::new()), From 665fa0d2bda7bd92dc71becc1c4530a695d40780 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:58:21 +0100 Subject: [PATCH 32/34] Update mod.rs --- pumpkin/src/entity/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index d4cea15e7..597bcb9a9 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -3,7 +3,6 @@ use std::sync::{atomic::AtomicBool, Arc}; use crossbeam::atomic::AtomicCell; use crate::server::Server; -use crossbeam::atomic::AtomicCell; use itertools::Itertools; use num_derive::FromPrimitive; use num_traits::real::Real; From 6bf922497698a454d1e40cf943ba98ac2519fc65 Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:59:55 +0100 Subject: [PATCH 33/34] Update mod.rs --- pumpkin/src/world/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 3c42d8188..129e3b09f 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -9,7 +9,6 @@ use crate::{ command::client_cmd_suggestions, entity::{living::LivingEntity, mob::MobEntity, player::Player, Entity}, error::PumpkinError, - server::Server, }; use level_time::LevelTime; use pumpkin_config::BasicConfiguration; From 3bcacc92e0d7a7f2870d6dc1a585227638f6112c Mon Sep 17 00:00:00 2001 From: Dominik <80042910+tomasalias@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:01:21 +0100 Subject: [PATCH 34/34] Update Cargo.toml --- pumpkin/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 54fe88a13..8be027a17 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -35,6 +35,7 @@ serde_json.workspace = true bytes.workspace = true rand = "0.8.5" +itertools = "0.13.0" num-bigint = "0.4"