Support dropping items out of Inventory
This commit is contained in:
parent
1fb2be46d4
commit
1f414f347c
@ -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),
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Player>) {
|
||||
if self.pickup_delay.load(std::sync::atomic::Ordering::Relaxed) == 0 {
|
||||
|
||||
@ -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 => {
|
||||
|
||||
@ -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<dyn Container>>,
|
||||
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<dyn Container>>,
|
||||
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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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(())
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user