mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-31 08:22:33 +00:00
* initial test for pickupall (cherry picked from commita939804eff) * added quickcraft right click and throw (cherry picked from commitcdcbccd962) * comments (cherry picked from commitf23bc8fd4d) * fix: QuickCraft handling and add drag slot support * fix: enhance quick craft item handling in inventory * fix * fix clippy * fix: drag * fix: improve item throwing logic in screen handler * fix: fix drag & throw * fix: throw * fix * fix * fix * fix: PickupAll * fix * fix --------- Co-authored-by: azomDev <dev@azom.ca>
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
use std::{any::Any, collections::HashMap, sync::Arc};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::warn;
|
||||
use pumpkin_data::screen::WindowType;
|
||||
@@ -14,6 +12,8 @@ use pumpkin_protocol::{
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use pumpkin_world::inventory::{ComparableInventory, Inventory};
|
||||
use pumpkin_world::item::ItemStack;
|
||||
use std::cmp::max;
|
||||
use std::{any::Any, collections::HashMap, sync::Arc};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
@@ -45,6 +45,7 @@ impl ScreenProperty {
|
||||
pub trait InventoryPlayer: Send + Sync {
|
||||
async fn drop_item(&self, item: ItemStack, retain_ownership: bool);
|
||||
fn get_inventory(&self) -> Arc<PlayerInventory>;
|
||||
fn has_infinite_materials(&self) -> bool;
|
||||
async fn enqueue_inventory_packet(&self, packet: &CSetContainerContent);
|
||||
async fn enqueue_slot_packet(&self, packet: &CSetContainerSlot);
|
||||
async fn enqueue_cursor_packet(&self, packet: &CSetCursorItem);
|
||||
@@ -466,8 +467,150 @@ pub trait ScreenHandler: Send + Sync {
|
||||
action_type: SlotActionType,
|
||||
player: &dyn InventoryPlayer,
|
||||
) {
|
||||
//TODO: Implement quickcraft, Clone, PickupAll, Throw
|
||||
if (action_type == SlotActionType::Pickup || action_type == SlotActionType::QuickMove)
|
||||
if action_type == SlotActionType::PickupAll && button == 0 {
|
||||
let behavior = self.get_behaviour_mut();
|
||||
let mut cursor_stack = behavior.cursor_stack.lock().await;
|
||||
let mut to_pick_up = cursor_stack.get_max_stack_size() - cursor_stack.item_count;
|
||||
|
||||
for slot in behavior.slots.iter() {
|
||||
if to_pick_up == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let stack_lock = slot.get_stack().await;
|
||||
let item_stack = stack_lock.lock().await;
|
||||
if !item_stack.are_items_and_components_equal(&cursor_stack) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !slot.can_take_items(player).await {
|
||||
continue;
|
||||
}
|
||||
|
||||
let take = item_stack.item_count.min(to_pick_up);
|
||||
to_pick_up -= take;
|
||||
|
||||
if item_stack.item_count == take {
|
||||
drop(item_stack);
|
||||
slot.set_stack(ItemStack::EMPTY).await;
|
||||
} else {
|
||||
let mut stack_clone = *item_stack;
|
||||
drop(item_stack);
|
||||
stack_clone.decrement(take);
|
||||
slot.set_stack(stack_clone).await;
|
||||
}
|
||||
cursor_stack.increment(take);
|
||||
}
|
||||
} else if action_type == SlotActionType::QuickCraft {
|
||||
let drag_type = button & 3;
|
||||
let drag_button = (button >> 2) & 3;
|
||||
let behaviour = self.get_behaviour_mut();
|
||||
if drag_type == 0 {
|
||||
behaviour.drag_slots.clear();
|
||||
} else if drag_type == 1 {
|
||||
if slot_index < 0 {
|
||||
warn!("Invalid slot index for drag action: {slot_index}. Must be >= 0");
|
||||
return;
|
||||
}
|
||||
let cursor_stack = behaviour.cursor_stack.lock().await;
|
||||
|
||||
let slot = &behaviour.slots[slot_index as usize];
|
||||
let stack_lock = slot.get_stack().await;
|
||||
let stack = stack_lock.lock().await;
|
||||
if !cursor_stack.is_empty()
|
||||
&& slot.can_insert(&cursor_stack).await
|
||||
&& (stack.are_items_and_components_equal(&cursor_stack) || stack.is_empty())
|
||||
&& slot.get_max_item_count_for_stack(&stack).await > stack.item_count
|
||||
{
|
||||
behaviour.drag_slots.push(slot_index as u32);
|
||||
}
|
||||
} else if drag_type == 2 && !behaviour.drag_slots.is_empty() {
|
||||
// process drag end
|
||||
if behaviour.drag_slots.len() == 1 {
|
||||
let slot = behaviour.drag_slots[0] as i32;
|
||||
behaviour.drag_slots.clear();
|
||||
let _ = behaviour;
|
||||
self.internal_on_slot_click(slot, drag_button, SlotActionType::Pickup, player)
|
||||
.await;
|
||||
|
||||
return;
|
||||
}
|
||||
if drag_button == 2 && !player.has_infinite_materials() {
|
||||
return; // Only creative
|
||||
}
|
||||
|
||||
let mut cursor_stack = behaviour.cursor_stack.lock().await;
|
||||
let initial_count = cursor_stack.item_count;
|
||||
for slot_index in behaviour.drag_slots.iter() {
|
||||
let slot = behaviour.slots[*slot_index as usize].clone();
|
||||
let stack_lock = slot.get_stack().await;
|
||||
let stack = stack_lock.lock().await;
|
||||
|
||||
if (stack.are_items_and_components_equal(&cursor_stack) || stack.is_empty())
|
||||
&& slot.can_insert(&cursor_stack).await
|
||||
{
|
||||
let mut inserting_count = if drag_button == 0 {
|
||||
initial_count / behaviour.drag_slots.len() as u8
|
||||
} else if drag_button == 1 {
|
||||
1
|
||||
} else if drag_button == 2 {
|
||||
cursor_stack.get_max_stack_size()
|
||||
} else {
|
||||
panic!("Invalid drag button: {drag_button}");
|
||||
};
|
||||
inserting_count = inserting_count
|
||||
.min(max(
|
||||
0,
|
||||
slot.get_max_item_count_for_stack(&stack).await - stack.item_count,
|
||||
))
|
||||
.min(cursor_stack.item_count);
|
||||
if inserting_count > 0 {
|
||||
let mut stack_clone = *stack;
|
||||
drop(stack);
|
||||
if stack_clone.is_empty() {
|
||||
stack_clone = cursor_stack.copy_with_count(0);
|
||||
}
|
||||
stack_clone.increment(inserting_count);
|
||||
slot.set_stack(stack_clone).await;
|
||||
if drag_button != 2 {
|
||||
cursor_stack.decrement(inserting_count);
|
||||
}
|
||||
if cursor_stack.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
behaviour.drag_slots.clear();
|
||||
}
|
||||
} else if action_type == SlotActionType::Throw {
|
||||
if slot_index >= 0 && self.get_behaviour().cursor_stack.lock().await.is_empty() {
|
||||
let slot = self.get_behaviour().slots[slot_index as usize].clone();
|
||||
let stack_lock = slot.get_stack().await;
|
||||
let mut target_stack = stack_lock.lock().await;
|
||||
if !target_stack.is_empty() {
|
||||
if button == 1 {
|
||||
let stack_clone = *target_stack;
|
||||
player.drop_item(stack_clone, true).await;
|
||||
drop(target_stack);
|
||||
slot.set_stack(ItemStack::EMPTY).await;
|
||||
} else {
|
||||
player.drop_item(target_stack.split(1), true).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if action_type == SlotActionType::Clone {
|
||||
if player.has_infinite_materials() && slot_index >= 0 {
|
||||
let behaviour = self.get_behaviour_mut();
|
||||
let slot = behaviour.slots[slot_index as usize].clone();
|
||||
let stack_lock = slot.get_stack().await;
|
||||
let stack = stack_lock.lock().await;
|
||||
let mut cursor_stack = behaviour.cursor_stack.lock().await;
|
||||
*cursor_stack = stack.copy_with_count(stack.get_max_stack_size());
|
||||
}
|
||||
} else if (action_type == SlotActionType::Pickup
|
||||
|| action_type == SlotActionType::QuickMove)
|
||||
&& (button == 0 || button == 1)
|
||||
{
|
||||
let click_type = if button == 0 {
|
||||
@@ -538,7 +681,6 @@ pub trait ScreenHandler: Send + Sync {
|
||||
|
||||
if slot_stack.is_empty() {
|
||||
if !cursor_stack.is_empty() {
|
||||
//println!("Cursor -> Slot");
|
||||
let transfer_count = if click_type == MouseClick::Left {
|
||||
cursor_stack.item_count
|
||||
} else {
|
||||
@@ -549,7 +691,6 @@ pub trait ScreenHandler: Send + Sync {
|
||||
}
|
||||
} else if slot.can_take_items(player).await {
|
||||
if cursor_stack.is_empty() {
|
||||
//println!("Slot -> Cursor");
|
||||
let take_count = if click_type == MouseClick::Left {
|
||||
slot_stack.item_count
|
||||
} else {
|
||||
@@ -717,6 +858,7 @@ pub struct ScreenHandlerBehaviour {
|
||||
pub properties: Vec<ScreenProperty>,
|
||||
pub tracked_property_values: Vec<i32>,
|
||||
pub window_type: Option<WindowType>,
|
||||
pub drag_slots: Vec<u32>,
|
||||
}
|
||||
|
||||
impl ScreenHandlerBehaviour {
|
||||
@@ -735,6 +877,7 @@ impl ScreenHandlerBehaviour {
|
||||
properties: Vec::new(),
|
||||
tracked_property_values: Vec::new(),
|
||||
window_type,
|
||||
drag_slots: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2481,6 +2481,10 @@ impl InventoryPlayer for Player {
|
||||
self.drop_item(item).await;
|
||||
}
|
||||
|
||||
fn has_infinite_materials(&self) -> bool {
|
||||
self.gamemode.load() == GameMode::Creative
|
||||
}
|
||||
|
||||
fn get_inventory(&self) -> Arc<PlayerInventory> {
|
||||
self.inventory.clone()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user