diff --git a/pumpkin-inventory/src/container_click.rs b/pumpkin-inventory/src/container_click.rs index d93ba3d3c..ec1d70fea 100644 --- a/pumpkin-inventory/src/container_click.rs +++ b/pumpkin-inventory/src/container_click.rs @@ -99,6 +99,7 @@ impl Click { } } +#[derive(Debug)] pub enum ClickType { MouseClick(MouseClick), ShiftClick, @@ -114,6 +115,7 @@ pub enum MouseClick { Right, } +#[derive(Debug)] pub enum KeyClick { Slot(u8), Offhand, @@ -124,6 +126,7 @@ pub enum Slot { OutsideInventory, } +#[derive(Debug)] pub enum DropType { SingleItem, FullStack, @@ -134,7 +137,7 @@ pub enum MouseDragType { Right, Middle, } -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum MouseDragState { Start(MouseDragType), AddSlot(usize), diff --git a/pumpkin-protocol/src/client/play/set_equipment.rs b/pumpkin-protocol/src/client/play/set_equipment.rs index 5a226dc90..ec79e4415 100644 --- a/pumpkin-protocol/src/client/play/set_equipment.rs +++ b/pumpkin-protocol/src/client/play/set_equipment.rs @@ -40,7 +40,7 @@ impl ClientPacket for CSetEquipment { equipment .1 .serialize(&mut serializer) - .expect("Could not serialize packet"); + .expect("Could not serialize Equipment Slot"); bytebuf.put(serializer.output); } } diff --git a/pumpkin/src/entity/item.rs b/pumpkin/src/entity/item.rs index a404264d0..c894e6ce5 100644 --- a/pumpkin/src/entity/item.rs +++ b/pumpkin/src/entity/item.rs @@ -1,6 +1,6 @@ use std::sync::{ Arc, - atomic::{AtomicI8, AtomicU8}, + atomic::{AtomicI8, AtomicU8, AtomicU32}, }; use async_trait::async_trait; @@ -16,6 +16,7 @@ pub struct ItemEntity { entity: Entity, item: ItemStack, count: AtomicU8, + item_age: AtomicU32, pickup_delay: AtomicI8, } @@ -25,6 +26,7 @@ impl ItemEntity { entity, item: stack, count: AtomicU8::new(stack.item_count), + item_age: AtomicU32::new(0), pickup_delay: AtomicI8::new(10), // Vanilla } } @@ -43,6 +45,13 @@ impl EntityBase for ItemEntity { self.pickup_delay .fetch_sub(1, std::sync::atomic::Ordering::Relaxed); } + + let age = self + .item_age + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + if age >= 6000 { + self.entity.remove().await; + } } async fn on_player_collision(&self, player: Arc) { if self.pickup_delay.load(std::sync::atomic::Ordering::Relaxed) == 0 { diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index db47e40e3..f21dd3473 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -982,22 +982,23 @@ impl Player { .await; } - pub async fn drop_item(&self, server: &Server, drop_stack: bool) { + pub async fn drop_item(&self, server: &Server, stack: ItemStack) { + let entity = server.add_entity( + self.living_entity.entity.pos.load(), + EntityType::ITEM, + &self.world().await, + ); + let item_entity = Arc::new(ItemEntity::new(entity, stack)); + self.world().await.spawn_entity(item_entity.clone()).await; + item_entity.send_meta_packet().await; + } + + pub async fn drop_held_item(&self, server: &Server, drop_stack: bool) { let mut inv = self.inventory.lock().await; if let Some(item) = inv.held_item_mut() { let drop_amount = if drop_stack { item.item_count } else { 1 }; - let entity = server.add_entity( - self.living_entity.entity.pos.load(), - EntityType::ITEM, - &self.world().await, - ); - let item_entity = Arc::new(ItemEntity::new( - entity, - ItemStack::new(drop_amount, item.item), - )); - self.world().await.spawn_entity(item_entity.clone()).await; - item_entity.send_meta_packet().await; - // decrase item in hotbar + self.drop_item(server, ItemStack::new(drop_amount, item.item)) + .await; inv.decrease_current_stack(drop_amount); } } @@ -1243,7 +1244,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/container.rs b/pumpkin/src/net/container.rs index 9a2498fba..afeff1ff0 100644 --- a/pumpkin/src/net/container.rs +++ b/pumpkin/src/net/container.rs @@ -4,7 +4,7 @@ use pumpkin_data::item::Item; use pumpkin_data::screen::WindowType; use pumpkin_inventory::Container; 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}; @@ -157,6 +157,7 @@ impl Player { let click_slot = click.slot; self.match_click_behaviour( + server, opened_container.as_deref_mut(), click, drag_handler, @@ -219,6 +220,7 @@ impl Player { async fn match_click_behaviour( &self, + server: &Server, opened_container: Option<&mut Box>, click: Click, drag_handler: &DragHandler, @@ -228,6 +230,7 @@ impl Player { match click.click_type { ClickType::MouseClick(mouse_click) => { self.mouse_click( + server, opened_container, mouse_click, click.slot, @@ -273,8 +276,18 @@ impl Player { self.mouse_drag(drag_handler, opened_container, drag_state) .await } - ClickType::DropType(_drop_type) => { - log::debug!("todo"); + ClickType::DropType(drop_type) => { + let carried_item = self.carried_item.load(); + if let Some(item) = carried_item { + match drop_type { + DropType::FullStack => self.drop_item(server, item).await, + DropType::SingleItem => { + let mut item = item; + item.item_count = 1; + self.drop_item(server, item).await; + } + }; + } Ok(()) } } @@ -282,6 +295,7 @@ impl Player { async fn mouse_click( &self, + server: &Server, opened_container: Option<&mut Box>, mouse_click: MouseClick, slot: container_click::Slot, @@ -289,9 +303,9 @@ impl Player { ) -> Result<(), InventoryError> { let mut inventory = self.inventory().lock().await; let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container); + let mut carried_item = self.carried_item.load(); match slot { container_click::Slot::Normal(slot) => { - let mut carried_item = self.carried_item.load(); let res = container.handle_item_change( &mut carried_item, slot, @@ -301,7 +315,19 @@ impl Player { self.carried_item.store(carried_item); res } - container_click::Slot::OutsideInventory => Ok(()), + container_click::Slot::OutsideInventory => { + if let Some(item) = carried_item { + match mouse_click { + MouseClick::Left => self.drop_item(server, item).await, + MouseClick::Right => { + let mut item = item; + item.item_count = 1; + self.drop_item(server, item).await; + } + }; + } + Ok(()) + } } } diff --git a/pumpkin/src/net/packet/play.rs b/pumpkin/src/net/packet/play.rs index eaa11ffe7..2f9a6033c 100644 --- a/pumpkin/src/net/packet/play.rs +++ b/pumpkin/src/net/packet/play.rs @@ -928,10 +928,10 @@ impl Player { self.update_sequence(player_action.sequence.0); } Status::DropItem => { - self.drop_item(server, false).await; + self.drop_held_item(server, false).await; } Status::DropItemStack => { - self.drop_item(server, true).await; + self.drop_held_item(server, true).await; } Status::ShootArrowOrFinishEating | Status::SwapItem => { log::debug!("todo"); @@ -1149,20 +1149,23 @@ impl Player { pub async fn handle_set_creative_slot( &self, + server: &Server, packet: SSetCreativeSlot, ) -> Result<(), InventoryError> { if self.gamemode.load() != GameMode::Creative { return Err(InventoryError::PermissionError); } let valid_slot = packet.slot >= 0 && packet.slot <= 45; + let item_stack = packet.clicked_item.to_item(); if valid_slot { - self.inventory().lock().await.set_slot( - packet.slot as usize, - packet.clicked_item.to_item(), - true, - )?; + self.inventory() + .lock() + .await + .set_slot(packet.slot as usize, item_stack, true)?; + } else { + // Item drop + self.drop_item(server, item_stack.unwrap()).await; }; - // TODO: The Item was dropped per drag and drop, Ok(()) }