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 {
|
pub enum ClickType {
|
||||||
MouseClick(MouseClick),
|
MouseClick(MouseClick),
|
||||||
ShiftClick,
|
ShiftClick,
|
||||||
@ -114,6 +115,7 @@ pub enum MouseClick {
|
|||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum KeyClick {
|
pub enum KeyClick {
|
||||||
Slot(u8),
|
Slot(u8),
|
||||||
Offhand,
|
Offhand,
|
||||||
@ -124,6 +126,7 @@ pub enum Slot {
|
|||||||
OutsideInventory,
|
OutsideInventory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum DropType {
|
pub enum DropType {
|
||||||
SingleItem,
|
SingleItem,
|
||||||
FullStack,
|
FullStack,
|
||||||
@ -134,7 +137,7 @@ pub enum MouseDragType {
|
|||||||
Right,
|
Right,
|
||||||
Middle,
|
Middle,
|
||||||
}
|
}
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum MouseDragState {
|
pub enum MouseDragState {
|
||||||
Start(MouseDragType),
|
Start(MouseDragType),
|
||||||
AddSlot(usize),
|
AddSlot(usize),
|
||||||
|
|||||||
@ -40,7 +40,7 @@ impl ClientPacket for CSetEquipment {
|
|||||||
equipment
|
equipment
|
||||||
.1
|
.1
|
||||||
.serialize(&mut serializer)
|
.serialize(&mut serializer)
|
||||||
.expect("Could not serialize packet");
|
.expect("Could not serialize Equipment Slot");
|
||||||
bytebuf.put(serializer.output);
|
bytebuf.put(serializer.output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::sync::{
|
use std::sync::{
|
||||||
Arc,
|
Arc,
|
||||||
atomic::{AtomicI8, AtomicU8},
|
atomic::{AtomicI8, AtomicU8, AtomicU32},
|
||||||
};
|
};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@ -16,6 +16,7 @@ pub struct ItemEntity {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
item: ItemStack,
|
item: ItemStack,
|
||||||
count: AtomicU8,
|
count: AtomicU8,
|
||||||
|
item_age: AtomicU32,
|
||||||
pickup_delay: AtomicI8,
|
pickup_delay: AtomicI8,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ impl ItemEntity {
|
|||||||
entity,
|
entity,
|
||||||
item: stack,
|
item: stack,
|
||||||
count: AtomicU8::new(stack.item_count),
|
count: AtomicU8::new(stack.item_count),
|
||||||
|
item_age: AtomicU32::new(0),
|
||||||
pickup_delay: AtomicI8::new(10), // Vanilla
|
pickup_delay: AtomicI8::new(10), // Vanilla
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,6 +45,13 @@ impl EntityBase for ItemEntity {
|
|||||||
self.pickup_delay
|
self.pickup_delay
|
||||||
.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
|
.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>) {
|
async fn on_player_collision(&self, player: Arc<Player>) {
|
||||||
if self.pickup_delay.load(std::sync::atomic::Ordering::Relaxed) == 0 {
|
if self.pickup_delay.load(std::sync::atomic::Ordering::Relaxed) == 0 {
|
||||||
|
|||||||
@ -982,22 +982,23 @@ impl Player {
|
|||||||
.await;
|
.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;
|
let mut inv = self.inventory.lock().await;
|
||||||
if let Some(item) = inv.held_item_mut() {
|
if let Some(item) = inv.held_item_mut() {
|
||||||
let drop_amount = if drop_stack { item.item_count } else { 1 };
|
let drop_amount = if drop_stack { item.item_count } else { 1 };
|
||||||
let entity = server.add_entity(
|
self.drop_item(server, ItemStack::new(drop_amount, item.item))
|
||||||
self.living_entity.entity.pos.load(),
|
.await;
|
||||||
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
|
|
||||||
inv.decrease_current_stack(drop_amount);
|
inv.decrease_current_stack(drop_amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1243,7 +1244,7 @@ impl Player {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
SSetCreativeSlot::PACKET_ID => {
|
SSetCreativeSlot::PACKET_ID => {
|
||||||
self.handle_set_creative_slot(SSetCreativeSlot::read(bytebuf)?)
|
self.handle_set_creative_slot(server, SSetCreativeSlot::read(bytebuf)?)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
SSwingArm::PACKET_ID => {
|
SSwingArm::PACKET_ID => {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use pumpkin_data::item::Item;
|
|||||||
use pumpkin_data::screen::WindowType;
|
use pumpkin_data::screen::WindowType;
|
||||||
use pumpkin_inventory::Container;
|
use pumpkin_inventory::Container;
|
||||||
use pumpkin_inventory::container_click::{
|
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::drag_handler::DragHandler;
|
||||||
use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait};
|
use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait};
|
||||||
@ -157,6 +157,7 @@ impl Player {
|
|||||||
|
|
||||||
let click_slot = click.slot;
|
let click_slot = click.slot;
|
||||||
self.match_click_behaviour(
|
self.match_click_behaviour(
|
||||||
|
server,
|
||||||
opened_container.as_deref_mut(),
|
opened_container.as_deref_mut(),
|
||||||
click,
|
click,
|
||||||
drag_handler,
|
drag_handler,
|
||||||
@ -219,6 +220,7 @@ impl Player {
|
|||||||
|
|
||||||
async fn match_click_behaviour(
|
async fn match_click_behaviour(
|
||||||
&self,
|
&self,
|
||||||
|
server: &Server,
|
||||||
opened_container: Option<&mut Box<dyn Container>>,
|
opened_container: Option<&mut Box<dyn Container>>,
|
||||||
click: Click,
|
click: Click,
|
||||||
drag_handler: &DragHandler,
|
drag_handler: &DragHandler,
|
||||||
@ -228,6 +230,7 @@ impl Player {
|
|||||||
match click.click_type {
|
match click.click_type {
|
||||||
ClickType::MouseClick(mouse_click) => {
|
ClickType::MouseClick(mouse_click) => {
|
||||||
self.mouse_click(
|
self.mouse_click(
|
||||||
|
server,
|
||||||
opened_container,
|
opened_container,
|
||||||
mouse_click,
|
mouse_click,
|
||||||
click.slot,
|
click.slot,
|
||||||
@ -273,8 +276,18 @@ impl Player {
|
|||||||
self.mouse_drag(drag_handler, opened_container, drag_state)
|
self.mouse_drag(drag_handler, opened_container, drag_state)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
ClickType::DropType(_drop_type) => {
|
ClickType::DropType(drop_type) => {
|
||||||
log::debug!("todo");
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,6 +295,7 @@ impl Player {
|
|||||||
|
|
||||||
async fn mouse_click(
|
async fn mouse_click(
|
||||||
&self,
|
&self,
|
||||||
|
server: &Server,
|
||||||
opened_container: Option<&mut Box<dyn Container>>,
|
opened_container: Option<&mut Box<dyn Container>>,
|
||||||
mouse_click: MouseClick,
|
mouse_click: MouseClick,
|
||||||
slot: container_click::Slot,
|
slot: container_click::Slot,
|
||||||
@ -289,9 +303,9 @@ impl Player {
|
|||||||
) -> Result<(), InventoryError> {
|
) -> Result<(), InventoryError> {
|
||||||
let mut inventory = self.inventory().lock().await;
|
let mut inventory = self.inventory().lock().await;
|
||||||
let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container);
|
let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container);
|
||||||
|
let mut carried_item = self.carried_item.load();
|
||||||
match slot {
|
match slot {
|
||||||
container_click::Slot::Normal(slot) => {
|
container_click::Slot::Normal(slot) => {
|
||||||
let mut carried_item = self.carried_item.load();
|
|
||||||
let res = container.handle_item_change(
|
let res = container.handle_item_change(
|
||||||
&mut carried_item,
|
&mut carried_item,
|
||||||
slot,
|
slot,
|
||||||
@ -301,7 +315,19 @@ impl Player {
|
|||||||
self.carried_item.store(carried_item);
|
self.carried_item.store(carried_item);
|
||||||
res
|
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);
|
self.update_sequence(player_action.sequence.0);
|
||||||
}
|
}
|
||||||
Status::DropItem => {
|
Status::DropItem => {
|
||||||
self.drop_item(server, false).await;
|
self.drop_held_item(server, false).await;
|
||||||
}
|
}
|
||||||
Status::DropItemStack => {
|
Status::DropItemStack => {
|
||||||
self.drop_item(server, true).await;
|
self.drop_held_item(server, true).await;
|
||||||
}
|
}
|
||||||
Status::ShootArrowOrFinishEating | Status::SwapItem => {
|
Status::ShootArrowOrFinishEating | Status::SwapItem => {
|
||||||
log::debug!("todo");
|
log::debug!("todo");
|
||||||
@ -1149,20 +1149,23 @@ impl Player {
|
|||||||
|
|
||||||
pub async fn handle_set_creative_slot(
|
pub async fn handle_set_creative_slot(
|
||||||
&self,
|
&self,
|
||||||
|
server: &Server,
|
||||||
packet: SSetCreativeSlot,
|
packet: SSetCreativeSlot,
|
||||||
) -> Result<(), InventoryError> {
|
) -> Result<(), InventoryError> {
|
||||||
if self.gamemode.load() != GameMode::Creative {
|
if self.gamemode.load() != GameMode::Creative {
|
||||||
return Err(InventoryError::PermissionError);
|
return Err(InventoryError::PermissionError);
|
||||||
}
|
}
|
||||||
let valid_slot = packet.slot >= 0 && packet.slot <= 45;
|
let valid_slot = packet.slot >= 0 && packet.slot <= 45;
|
||||||
|
let item_stack = packet.clicked_item.to_item();
|
||||||
if valid_slot {
|
if valid_slot {
|
||||||
self.inventory().lock().await.set_slot(
|
self.inventory()
|
||||||
packet.slot as usize,
|
.lock()
|
||||||
packet.clicked_item.to_item(),
|
.await
|
||||||
true,
|
.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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user