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,
Middle,
}
#[derive(PartialEq)]
pub enum MouseDragState {
Start(MouseDragType),
AddSlot(usize),

View File

@ -58,13 +58,13 @@ impl DragHandler {
pub fn apply_drag<T: Container>(
&self,
carried_item: &mut Option<ItemStack>,
maybe_carried_item: &mut Option<ItemStack>,
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<ItemStack>],
carried_item: &'a ItemStack,
carried_item_id: u32,
) -> impl Iterator<Item = usize> + '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),
}
})
}
}

View File

@ -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<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(())
}
@ -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<Arc<Mutex<Player>>> {
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(())
}