From 3b93892f269588870dc163b70812e16d8187f54e Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Fri, 6 Sep 2024 18:48:06 +0200 Subject: [PATCH] start trying to drag, it doesn't work though --- pumpkin-inventory/src/container_click.rs | 2 +- pumpkin-inventory/src/drag_handler.rs | 85 ++++++++++++------------ pumpkin/src/client/container.rs | 80 +++++++++++++++++++--- 3 files changed, 113 insertions(+), 54 deletions(-) diff --git a/pumpkin-inventory/src/container_click.rs b/pumpkin-inventory/src/container_click.rs index 0c4897d30..9ec1beda3 100644 --- a/pumpkin-inventory/src/container_click.rs +++ b/pumpkin-inventory/src/container_click.rs @@ -142,7 +142,7 @@ pub enum MouseDragType { Right, Middle, } - +#[derive(PartialEq)] pub enum MouseDragState { Start(MouseDragType), AddSlot(usize), diff --git a/pumpkin-inventory/src/drag_handler.rs b/pumpkin-inventory/src/drag_handler.rs index c34d423a8..11d8b2f82 100644 --- a/pumpkin-inventory/src/drag_handler.rs +++ b/pumpkin-inventory/src/drag_handler.rs @@ -58,13 +58,13 @@ impl DragHandler { pub fn apply_drag( &self, - carried_item: &mut Option, + maybe_carried_item: &mut Option, container: &mut T, container_id: &u64, player: i32, ) -> Result<(), InventoryError> { // Minecraft client does still send dragging packets when not carrying an item! - if carried_item.is_none() { + if maybe_carried_item.is_none() { return Ok(()); } @@ -84,60 +84,60 @@ impl DragHandler { .iter() .map(|stack| stack.map(|item| item.to_owned())) .collect_vec(); + let Some(carried_item) = maybe_carried_item else { + return Ok(()); + }; match drag.drag_type { // This is only valid in Creative GameMode. // Checked in any function that uses this function. MouseDragType::Middle => { for slot in &drag.slots { - *slots[*slot] = *carried_item; + *slots[*slot] = *maybe_carried_item; } } MouseDragType::Right => { - let amount_of_items = carried_item.unwrap().item_count as usize; - let mut single_item = carried_item.unwrap(); + let mut single_item = *carried_item; single_item.item_count = 1; - let changing_slots = drag.changing_slots( - amount_of_items, - &slots_cloned, - carried_item.as_ref().unwrap(), - ); - let mut amount_removed = 0; + + let changing_slots = + drag.possibly_changing_slots(&slots_cloned, carried_item.item_id); changing_slots.for_each(|slot| { - amount_removed += 1; - *slots[slot] = Some(single_item) + if carried_item.item_count != 0 { + carried_item.item_count -= 1; + if let Some(stack) = &mut slots[slot] { + // TODO: Check for stack max here + if stack.item_count + 1 < 64 { + stack.item_count += 1; + } else { + carried_item.item_count += 1; + } + } else { + *slots[slot] = Some(single_item) + } + } }); - let mut remaining = carried_item.unwrap(); - if remaining.item_count == amount_removed { - *carried_item = None - } else { - remaining.item_count -= amount_removed; - *carried_item = Some(remaining) + if carried_item.item_count == 0 { + *maybe_carried_item = None } } MouseDragType::Left => { - let amount_of_items = carried_item.unwrap().item_count as usize; // TODO: Handle dragging a stack with greater amount than item allows as max unstackable // In that specific case, follow MouseDragType::Right behaviours instead! - let changing_slots = drag.changing_slots( - amount_of_items, - &slots_cloned, - carried_item.as_ref().unwrap(), - ); + let changing_slots = + drag.possibly_changing_slots(&slots_cloned, carried_item.item_id); let amount_of_slots = changing_slots.clone().count(); let (amount_per_slot, remainder) = - (carried_item.unwrap().item_count as usize).div_rem_euclid(&amount_of_slots); - let mut item_in_each_slot = carried_item.unwrap(); + (carried_item.item_count as usize).div_rem_euclid(&amount_of_slots); + let mut item_in_each_slot = *carried_item; item_in_each_slot.item_count = amount_per_slot as u8; changing_slots.for_each(|slot| *slots[slot] = Some(item_in_each_slot)); if remainder > 0 { - let mut remaining = carried_item.unwrap(); - remaining.item_count = remainder as u8; - *carried_item = Some(remaining) + carried_item.item_count = remainder as u8; } else { - *carried_item = None + *maybe_carried_item = None } } } @@ -152,25 +152,24 @@ struct Drag { } impl Drag { - fn changing_slots<'a>( + fn possibly_changing_slots<'a>( &'a self, - amount_of_items: usize, slots: &'a [Option], - carried_item: &'a ItemStack, + carried_item_id: u32, ) -> impl Iterator + 'a + Clone { - self.slots - .iter() - .enumerate() - .take_while(move |(slot_number, _)| *slot_number <= amount_of_items) - .filter_map(move |(_, slot)| match &slots[*slot] { + self.slots.iter().filter_map(move |slot_index| { + let slot = &slots[*slot_index]; + + match slot { Some(item_slot) => { - if *item_slot == *carried_item { - Some(*slot) + if item_slot.item_id == carried_item_id { + Some(*slot_index) } else { None } } - None => Some(*slot), - }) + None => Some(*slot_index), + } + }) } } diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index a02926b43..eadbbeac0 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -16,7 +16,7 @@ use pumpkin_protocol::client::play::{ use pumpkin_protocol::server::play::SClickContainer; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::ItemStack; -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; impl Player { pub fn open_container( @@ -135,6 +135,7 @@ impl Player { packet.button, packet.slot, ); + let mut update_whole_container = false; match click.click_type { ClickType::MouseClick(mouse_click) => { @@ -157,19 +158,26 @@ impl Player { } } ClickType::DoubleClick => { + update_whole_container = true; if let container_click::Slot::Normal(slot) = click.slot { - self.double_click(slot) + self.double_click(opened_container.as_deref_mut(), slot) } else { Err(InventoryError::InvalidPacket) } } ClickType::MouseDrag { drag_state } => { + if drag_state == MouseDragState::End { + update_whole_container = true; + } self.mouse_drag(drag_handler, opened_container.as_deref_mut(), drag_state) } ClickType::DropType(_drop_type) => todo!(), }?; if let Some(mut opened_container) = opened_container { - if let container_click::Slot::Normal(slot_index) = click.slot { + if update_whole_container { + drop(opened_container); + self.send_whole_container_change(server).await?; + } else if let container_click::Slot::Normal(slot_index) = click.slot { let combined_container = OptionallyCombinedContainer::new( &mut self.inventory, Some(&mut opened_container), @@ -280,7 +288,40 @@ impl Player { Ok(()) } - fn double_click(&mut self, _slot: usize) -> Result<(), InventoryError> { + fn double_click( + &mut self, + opened_container: Option<&mut Box>, + slot: usize, + ) -> Result<(), InventoryError> { + let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); + let mut slots = container.all_slots(); + + let Some(item) = slots.get_mut(slot) else { + return Ok(()); + }; + let Some(mut carried_item) = **item else { + return Ok(()); + }; + **item = None; + + for slot in slots.iter_mut().filter_map(|slot| slot.as_mut()) { + if slot.item_id == carried_item.item_id { + // TODO: Check for max stack size + if slot.item_count + carried_item.item_count <= 64 { + slot.item_count = 0; + carried_item.item_count = 64; + } else { + let to_remove = slot.item_count - (64 - carried_item.item_count); + slot.item_count -= to_remove; + carried_item.item_count += to_remove; + } + + if carried_item.item_count == 64 { + break; + } + } + } + self.carried_item = Some(carried_item); Ok(()) } @@ -316,12 +357,10 @@ impl Player { } } - async fn send_container_changes( + async fn get_current_players_in_container( &mut self, server: &Server, - slot_index: usize, - slot: Slot, - ) -> Result<(), InventoryError> { + ) -> Vec>> { let player_ids = server .open_containers .get(&self.open_container.unwrap()) @@ -352,8 +391,16 @@ impl Player { } }) .collect_vec(); - drop(world); - for player in players { + players + } + + async fn send_container_changes( + &mut self, + server: &Server, + slot_index: usize, + slot: Slot, + ) -> Result<(), InventoryError> { + for player in self.get_current_players_in_container(server).await { let mut player = player.lock().unwrap(); let total_opened_containers = player.inventory.total_opened_containers; @@ -366,7 +413,20 @@ impl Player { ); player.client.send_packet(&packet); } + Ok(()) + } + async fn send_whole_container_change(&mut self, server: &Server) -> Result<(), InventoryError> { + let players = self.get_current_players_in_container(server).await; + + for player in players { + let mut player = player.lock().unwrap(); + let mut container = player + .get_open_container(server) + .map(|container| container.lock().unwrap()); + player.set_container_content(container.as_deref_mut()); + drop(container) + } Ok(()) }