start trying to drag, it doesn't work though

This commit is contained in:
Edvin Bryntesson 2024-09-06 18:48:06 +02:00
parent 2acd1ed02a
commit 3b93892f26
No known key found for this signature in database
3 changed files with 113 additions and 54 deletions

View File

@ -142,7 +142,7 @@ pub enum MouseDragType {
Right, Right,
Middle, Middle,
} }
#[derive(PartialEq)]
pub enum MouseDragState { pub enum MouseDragState {
Start(MouseDragType), Start(MouseDragType),
AddSlot(usize), AddSlot(usize),

View File

@ -58,13 +58,13 @@ impl DragHandler {
pub fn apply_drag<T: Container>( pub fn apply_drag<T: Container>(
&self, &self,
carried_item: &mut Option<ItemStack>, maybe_carried_item: &mut Option<ItemStack>,
container: &mut T, container: &mut T,
container_id: &u64, container_id: &u64,
player: i32, player: i32,
) -> Result<(), InventoryError> { ) -> Result<(), InventoryError> {
// Minecraft client does still send dragging packets when not carrying an item! // 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(()); return Ok(());
} }
@ -84,60 +84,60 @@ impl DragHandler {
.iter() .iter()
.map(|stack| stack.map(|item| item.to_owned())) .map(|stack| stack.map(|item| item.to_owned()))
.collect_vec(); .collect_vec();
let Some(carried_item) = maybe_carried_item else {
return Ok(());
};
match drag.drag_type { match drag.drag_type {
// This is only valid in Creative GameMode. // This is only valid in Creative GameMode.
// Checked in any function that uses this function. // Checked in any function that uses this function.
MouseDragType::Middle => { MouseDragType::Middle => {
for slot in &drag.slots { for slot in &drag.slots {
*slots[*slot] = *carried_item; *slots[*slot] = *maybe_carried_item;
} }
} }
MouseDragType::Right => { MouseDragType::Right => {
let amount_of_items = carried_item.unwrap().item_count as usize; let mut single_item = *carried_item;
let mut single_item = carried_item.unwrap();
single_item.item_count = 1; single_item.item_count = 1;
let changing_slots = drag.changing_slots(
amount_of_items, let changing_slots =
&slots_cloned, drag.possibly_changing_slots(&slots_cloned, carried_item.item_id);
carried_item.as_ref().unwrap(),
);
let mut amount_removed = 0;
changing_slots.for_each(|slot| { changing_slots.for_each(|slot| {
amount_removed += 1; if carried_item.item_count != 0 {
*slots[slot] = Some(single_item) 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 carried_item.item_count == 0 {
if remaining.item_count == amount_removed { *maybe_carried_item = None
*carried_item = None
} else {
remaining.item_count -= amount_removed;
*carried_item = Some(remaining)
} }
} }
MouseDragType::Left => { 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 // TODO: Handle dragging a stack with greater amount than item allows as max unstackable
// In that specific case, follow MouseDragType::Right behaviours instead! // In that specific case, follow MouseDragType::Right behaviours instead!
let changing_slots = drag.changing_slots( let changing_slots =
amount_of_items, drag.possibly_changing_slots(&slots_cloned, carried_item.item_id);
&slots_cloned,
carried_item.as_ref().unwrap(),
);
let amount_of_slots = changing_slots.clone().count(); let amount_of_slots = changing_slots.clone().count();
let (amount_per_slot, remainder) = let (amount_per_slot, remainder) =
(carried_item.unwrap().item_count as usize).div_rem_euclid(&amount_of_slots); (carried_item.item_count as usize).div_rem_euclid(&amount_of_slots);
let mut item_in_each_slot = carried_item.unwrap(); let mut item_in_each_slot = *carried_item;
item_in_each_slot.item_count = amount_per_slot as u8; item_in_each_slot.item_count = amount_per_slot as u8;
changing_slots.for_each(|slot| *slots[slot] = Some(item_in_each_slot)); changing_slots.for_each(|slot| *slots[slot] = Some(item_in_each_slot));
if remainder > 0 { if remainder > 0 {
let mut remaining = carried_item.unwrap(); carried_item.item_count = remainder as u8;
remaining.item_count = remainder as u8;
*carried_item = Some(remaining)
} else { } else {
*carried_item = None *maybe_carried_item = None
} }
} }
} }
@ -152,25 +152,24 @@ struct Drag {
} }
impl Drag { impl Drag {
fn changing_slots<'a>( fn possibly_changing_slots<'a>(
&'a self, &'a self,
amount_of_items: usize,
slots: &'a [Option<ItemStack>], slots: &'a [Option<ItemStack>],
carried_item: &'a ItemStack, carried_item_id: u32,
) -> impl Iterator<Item = usize> + 'a + Clone { ) -> impl Iterator<Item = usize> + 'a + Clone {
self.slots self.slots.iter().filter_map(move |slot_index| {
.iter() let slot = &slots[*slot_index];
.enumerate()
.take_while(move |(slot_number, _)| *slot_number <= amount_of_items) match slot {
.filter_map(move |(_, slot)| match &slots[*slot] {
Some(item_slot) => { Some(item_slot) => {
if *item_slot == *carried_item { if item_slot.item_id == carried_item_id {
Some(*slot) Some(*slot_index)
} else { } else {
None None
} }
} }
None => Some(*slot), None => Some(*slot_index),
}) }
})
} }
} }

View File

@ -16,7 +16,7 @@ use pumpkin_protocol::client::play::{
use pumpkin_protocol::server::play::SClickContainer; use pumpkin_protocol::server::play::SClickContainer;
use pumpkin_protocol::slot::Slot; use pumpkin_protocol::slot::Slot;
use pumpkin_world::item::ItemStack; use pumpkin_world::item::ItemStack;
use std::sync::Mutex; use std::sync::{Arc, Mutex};
impl Player { impl Player {
pub fn open_container( pub fn open_container(
@ -135,6 +135,7 @@ impl Player {
packet.button, packet.button,
packet.slot, packet.slot,
); );
let mut update_whole_container = false;
match click.click_type { match click.click_type {
ClickType::MouseClick(mouse_click) => { ClickType::MouseClick(mouse_click) => {
@ -157,19 +158,26 @@ impl Player {
} }
} }
ClickType::DoubleClick => { ClickType::DoubleClick => {
update_whole_container = true;
if let container_click::Slot::Normal(slot) = click.slot { if let container_click::Slot::Normal(slot) = click.slot {
self.double_click(slot) self.double_click(opened_container.as_deref_mut(), slot)
} else { } else {
Err(InventoryError::InvalidPacket) Err(InventoryError::InvalidPacket)
} }
} }
ClickType::MouseDrag { drag_state } => { 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) self.mouse_drag(drag_handler, opened_container.as_deref_mut(), drag_state)
} }
ClickType::DropType(_drop_type) => todo!(), ClickType::DropType(_drop_type) => todo!(),
}?; }?;
if let Some(mut opened_container) = opened_container { 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( let combined_container = OptionallyCombinedContainer::new(
&mut self.inventory, &mut self.inventory,
Some(&mut opened_container), Some(&mut opened_container),
@ -280,7 +288,40 @@ impl Player {
Ok(()) Ok(())
} }
fn double_click(&mut self, _slot: usize) -> Result<(), InventoryError> { fn double_click(
&mut self,
opened_container: Option<&mut Box<dyn Container>>,
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(()) Ok(())
} }
@ -316,12 +357,10 @@ impl Player {
} }
} }
async fn send_container_changes( async fn get_current_players_in_container(
&mut self, &mut self,
server: &Server, server: &Server,
slot_index: usize, ) -> Vec<Arc<Mutex<Player>>> {
slot: Slot,
) -> Result<(), InventoryError> {
let player_ids = server let player_ids = server
.open_containers .open_containers
.get(&self.open_container.unwrap()) .get(&self.open_container.unwrap())
@ -352,8 +391,16 @@ impl Player {
} }
}) })
.collect_vec(); .collect_vec();
drop(world); players
for player in 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 mut player = player.lock().unwrap();
let total_opened_containers = player.inventory.total_opened_containers; let total_opened_containers = player.inventory.total_opened_containers;
@ -366,7 +413,20 @@ impl Player {
); );
player.client.send_packet(&packet); 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(()) Ok(())
} }