feat(bedrock): add container open
This commit is contained in:
parent
e47695d810
commit
b08be9e158
@ -1,4 +1,4 @@
|
|||||||
use std::io::{Error, Write};
|
use std::io::{Error, Read, Write};
|
||||||
use std::num::NonZeroI32;
|
use std::num::NonZeroI32;
|
||||||
|
|
||||||
use pumpkin_data::item::{BedrockItem, JavaToBedrockItemMapping};
|
use pumpkin_data::item::{BedrockItem, JavaToBedrockItemMapping};
|
||||||
@ -7,10 +7,10 @@ use pumpkin_nbt::Nbt;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codec::{var_int::VarInt, var_uint::VarUInt},
|
codec::{var_int::VarInt, var_uint::VarUInt},
|
||||||
serial::PacketWrite,
|
serial::{PacketRead, PacketWrite},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct NetworkItemDescriptor {
|
pub struct NetworkItemDescriptor {
|
||||||
// I hate mojang
|
// I hate mojang
|
||||||
// https://mojang.github.io/bedrock-protocol-docs/html/NetworkItemInstanceDescriptor.html
|
// https://mojang.github.io/bedrock-protocol-docs/html/NetworkItemInstanceDescriptor.html
|
||||||
@ -33,6 +33,36 @@ impl PacketWrite for NetworkItemDescriptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PacketRead for NetworkItemDescriptor {
|
||||||
|
fn read<R: Read>(buf: &mut R) -> Result<Self, Error> {
|
||||||
|
let id = VarInt::read(buf)?;
|
||||||
|
if id.0 == 0 {
|
||||||
|
return Ok(Self::default());
|
||||||
|
}
|
||||||
|
let stack_size = u16::read(buf)?;
|
||||||
|
let aux_value = VarUInt::read(buf)?;
|
||||||
|
|
||||||
|
let has_net_id = bool::read(buf)?;
|
||||||
|
if has_net_id {
|
||||||
|
let _net_id = VarInt::read(buf)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let block_runtime_id = VarInt::read(buf)?;
|
||||||
|
|
||||||
|
let user_data_len = VarUInt::read(buf)?.0;
|
||||||
|
let mut user_data = vec![0u8; user_data_len as usize];
|
||||||
|
buf.read_exact(&mut user_data)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
id,
|
||||||
|
stack_size,
|
||||||
|
aux_value,
|
||||||
|
block_runtime_id,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NetworkItemDescriptor {
|
impl NetworkItemDescriptor {
|
||||||
#[allow(clippy::option_option)]
|
#[allow(clippy::option_option)]
|
||||||
fn write_with_net_id<W: Write>(
|
fn write_with_net_id<W: Write>(
|
||||||
|
|||||||
@ -3,10 +3,12 @@ use std::io::{Error, ErrorKind, Read};
|
|||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
|
||||||
|
use crate::bedrock::network_item::NetworkItemDescriptor;
|
||||||
use crate::{
|
use crate::{
|
||||||
codec::{var_int::VarInt, var_uint::VarUInt, var_ulong::VarULong},
|
codec::{var_int::VarInt, var_uint::VarUInt, var_ulong::VarULong},
|
||||||
serial::PacketRead,
|
serial::PacketRead,
|
||||||
};
|
};
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
pub const WINDOW_ID_INVENTORY: i32 = 0;
|
pub const WINDOW_ID_INVENTORY: i32 = 0;
|
||||||
pub const WINDOW_ID_OFF_HAND: i32 = 119;
|
pub const WINDOW_ID_OFF_HAND: i32 = 119;
|
||||||
@ -55,9 +57,8 @@ pub struct InventoryAction {
|
|||||||
pub window_id: Option<i32>,
|
pub window_id: Option<i32>,
|
||||||
pub source_flags: Option<u32>,
|
pub source_flags: Option<u32>,
|
||||||
pub inventory_slot: u32,
|
pub inventory_slot: u32,
|
||||||
// TODO
|
pub old_item: NetworkItemDescriptor,
|
||||||
pub old_item: (),
|
pub new_item: NetworkItemDescriptor,
|
||||||
pub new_item: (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketRead for InventoryAction {
|
impl PacketRead for InventoryAction {
|
||||||
@ -79,16 +80,16 @@ impl PacketRead for InventoryAction {
|
|||||||
|
|
||||||
let inventory_slot = VarULong::read(buf)?.0 as u32;
|
let inventory_slot = VarULong::read(buf)?.0 as u32;
|
||||||
|
|
||||||
// let old_item = ItemStack::read(buf)?;
|
let old_item = NetworkItemDescriptor::read(buf)?;
|
||||||
// let new_item = ItemStack::read(buf)?;
|
let new_item = NetworkItemDescriptor::read(buf)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
source_type,
|
source_type,
|
||||||
window_id,
|
window_id,
|
||||||
source_flags,
|
source_flags,
|
||||||
inventory_slot,
|
inventory_slot,
|
||||||
old_item: (),
|
old_item,
|
||||||
new_item: (),
|
new_item,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,29 +100,79 @@ pub struct NormalTransactionData;
|
|||||||
#[derive(Debug, PacketRead)]
|
#[derive(Debug, PacketRead)]
|
||||||
pub struct MismatchTransactionData;
|
pub struct MismatchTransactionData;
|
||||||
|
|
||||||
#[derive(Debug, PacketRead)]
|
#[derive(Debug)]
|
||||||
pub struct UseItemTransactionData {
|
pub struct UseItemTransactionData {
|
||||||
pub action_type: VarULong,
|
pub action_type: VarUInt,
|
||||||
pub trigger_type: VarULong,
|
pub trigger_type: VarUInt,
|
||||||
pub block_position: BlockPos,
|
pub block_position: BlockPos,
|
||||||
pub block_face: VarInt,
|
pub block_face: VarInt,
|
||||||
pub hot_bar_slot: VarInt,
|
pub hot_bar_slot: VarInt,
|
||||||
// TODO
|
pub item_in_hand: NetworkItemDescriptor,
|
||||||
|
pub player_position: Vector3<f32>,
|
||||||
|
pub click_position: Vector3<f32>,
|
||||||
|
pub block_runtime_id: VarUInt,
|
||||||
|
pub client_prediction: VarUInt,
|
||||||
|
pub client_cooldown_state: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PacketRead)]
|
impl PacketRead for UseItemTransactionData {
|
||||||
|
fn read<R: Read>(buf: &mut R) -> Result<Self, Error> {
|
||||||
|
Ok(Self {
|
||||||
|
action_type: VarUInt::read(buf)?,
|
||||||
|
trigger_type: VarUInt::read(buf)?,
|
||||||
|
block_position: BlockPos::read(buf)?,
|
||||||
|
block_face: VarInt::read(buf)?,
|
||||||
|
hot_bar_slot: VarInt::read(buf)?,
|
||||||
|
item_in_hand: NetworkItemDescriptor::read(buf)?,
|
||||||
|
player_position: Vector3::read(buf)?,
|
||||||
|
click_position: Vector3::read(buf)?,
|
||||||
|
block_runtime_id: VarUInt::read(buf)?,
|
||||||
|
client_prediction: VarUInt::read(buf)?,
|
||||||
|
client_cooldown_state: u8::read(buf)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct UseItemOnEntityTransactionData {
|
pub struct UseItemOnEntityTransactionData {
|
||||||
pub target_entity_runtime_id: VarULong,
|
pub target_entity_runtime_id: VarULong,
|
||||||
pub action_type: VarULong,
|
pub action_type: VarUInt,
|
||||||
pub hot_bar_slot: VarInt,
|
pub hot_bar_slot: VarInt,
|
||||||
// TODO
|
pub item_in_hand: NetworkItemDescriptor,
|
||||||
|
pub player_position: Vector3<f32>,
|
||||||
|
pub click_position: Vector3<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PacketRead)]
|
impl PacketRead for UseItemOnEntityTransactionData {
|
||||||
|
fn read<R: Read>(buf: &mut R) -> Result<Self, Error> {
|
||||||
|
Ok(Self {
|
||||||
|
target_entity_runtime_id: VarULong::read(buf)?,
|
||||||
|
action_type: VarUInt::read(buf)?,
|
||||||
|
hot_bar_slot: VarInt::read(buf)?,
|
||||||
|
item_in_hand: NetworkItemDescriptor::read(buf)?,
|
||||||
|
player_position: Vector3::read(buf)?,
|
||||||
|
click_position: Vector3::read(buf)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ReleaseItemTransactionData {
|
pub struct ReleaseItemTransactionData {
|
||||||
pub action_type: VarULong,
|
pub action_type: VarUInt,
|
||||||
pub hot_bar_slot: VarInt,
|
pub hot_bar_slot: VarInt,
|
||||||
// TODO
|
pub item_in_hand: NetworkItemDescriptor,
|
||||||
|
pub head_position: Vector3<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PacketRead for ReleaseItemTransactionData {
|
||||||
|
fn read<R: Read>(buf: &mut R) -> Result<Self, Error> {
|
||||||
|
Ok(Self {
|
||||||
|
action_type: VarUInt::read(buf)?,
|
||||||
|
hot_bar_slot: VarInt::read(buf)?,
|
||||||
|
item_in_hand: NetworkItemDescriptor::read(buf)?,
|
||||||
|
head_position: Vector3::read(buf)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@ -40,7 +40,7 @@ use pumpkin_data::item_stack::ItemStack;
|
|||||||
use pumpkin_data::particle::Particle;
|
use pumpkin_data::particle::Particle;
|
||||||
use pumpkin_data::sound::{Sound, SoundCategory};
|
use pumpkin_data::sound::{Sound, SoundCategory};
|
||||||
use pumpkin_data::tag::Taggable;
|
use pumpkin_data::tag::Taggable;
|
||||||
use pumpkin_data::{Block, BlockState, Enchantment, tag, translation};
|
use pumpkin_data::{Block, BlockState, Enchantment, screen::WindowType, tag, translation};
|
||||||
use pumpkin_inventory::player::{
|
use pumpkin_inventory::player::{
|
||||||
player_inventory::PlayerInventory, player_screen_handler::PlayerScreenHandler,
|
player_inventory::PlayerInventory, player_screen_handler::PlayerScreenHandler,
|
||||||
};
|
};
|
||||||
@ -54,7 +54,9 @@ use pumpkin_nbt::compound::NbtCompound;
|
|||||||
use pumpkin_nbt::tag::NbtTag;
|
use pumpkin_nbt::tag::NbtTag;
|
||||||
use pumpkin_protocol::IdOr;
|
use pumpkin_protocol::IdOr;
|
||||||
use pumpkin_protocol::SoundEvent;
|
use pumpkin_protocol::SoundEvent;
|
||||||
|
use pumpkin_protocol::bedrock::client::container_open::CContainerOpen;
|
||||||
use pumpkin_protocol::codec::var_int::VarInt;
|
use pumpkin_protocol::codec::var_int::VarInt;
|
||||||
|
use pumpkin_protocol::codec::var_long::VarLong;
|
||||||
use pumpkin_protocol::java::client::play::{
|
use pumpkin_protocol::java::client::play::{
|
||||||
Animation, CAcknowledgeBlockChange, CActionBar, CChangeDifficulty, CCloseContainer,
|
Animation, CAcknowledgeBlockChange, CActionBar, CChangeDifficulty, CCloseContainer,
|
||||||
CCombatDeath, CCustomPayload, CDisguisedChatMessage, CEntityAnimation, CEntityPositionSync,
|
CCombatDeath, CCustomPayload, CDisguisedChatMessage, CEntityAnimation, CEntityPositionSync,
|
||||||
@ -3326,16 +3328,44 @@ impl Player {
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let screen_handler_temp = screen_handler.lock().await;
|
let screen_handler_temp = screen_handler.lock().await;
|
||||||
self.client
|
let sync_id = screen_handler_temp.sync_id();
|
||||||
.enqueue_packet(&COpenScreen::new(
|
let window_type = screen_handler_temp
|
||||||
screen_handler_temp.sync_id().into(),
|
|
||||||
(screen_handler_temp
|
|
||||||
.window_type()
|
.window_type()
|
||||||
.expect("Can't open PlayerScreenHandler") as i32)
|
.expect("Can't open PlayerScreenHandler");
|
||||||
.into(),
|
|
||||||
&screen_handler_factory.get_display_name(),
|
let display_name = screen_handler_factory.get_display_name();
|
||||||
))
|
let java_packet =
|
||||||
|
COpenScreen::new(sync_id.into(), (window_type as i32).into(), &display_name);
|
||||||
|
|
||||||
|
let bedrock_window_type = match window_type {
|
||||||
|
WindowType::Crafting => 1,
|
||||||
|
WindowType::Furnace => 2,
|
||||||
|
WindowType::Enchantment => 3,
|
||||||
|
WindowType::BrewingStand => 4,
|
||||||
|
WindowType::Anvil => 5,
|
||||||
|
WindowType::Hopper => 8,
|
||||||
|
WindowType::Beacon => 13,
|
||||||
|
WindowType::BlastFurnace => 27,
|
||||||
|
WindowType::Smoker => 28,
|
||||||
|
WindowType::Stonecutter => 29,
|
||||||
|
WindowType::CartographyTable => 30,
|
||||||
|
WindowType::Grindstone => 26,
|
||||||
|
WindowType::Loom => 24,
|
||||||
|
WindowType::Smithing => 34,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let bedrock_packet = CContainerOpen {
|
||||||
|
container_id: sync_id,
|
||||||
|
container_type: bedrock_window_type,
|
||||||
|
position: block_pos.unwrap_or(BlockPos::ZERO),
|
||||||
|
target_entity_id: VarLong(-1),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.enqueue_packet_editioned(&java_packet, &bedrock_packet)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
drop(screen_handler_temp);
|
drop(screen_handler_temp);
|
||||||
self.on_screen_handler_opened(screen_handler.clone()).await;
|
self.on_screen_handler_opened(screen_handler.clone()).await;
|
||||||
*self.current_screen_handler.lock().await = screen_handler;
|
*self.current_screen_handler.lock().await = screen_handler;
|
||||||
@ -3366,16 +3396,42 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let screen_handler_temp = screen_handler.lock().await;
|
let screen_handler_temp = screen_handler.lock().await;
|
||||||
self.client
|
let sync_id = screen_handler_temp.sync_id();
|
||||||
.enqueue_packet(&COpenScreen::new(
|
let window_type = screen_handler_temp
|
||||||
screen_handler_temp.sync_id().into(),
|
|
||||||
(screen_handler_temp
|
|
||||||
.window_type()
|
.window_type()
|
||||||
.expect("Can't open PlayerScreenHandler") as i32)
|
.expect("Can't open PlayerScreenHandler");
|
||||||
.into(),
|
|
||||||
&title,
|
let java_packet = COpenScreen::new(sync_id.into(), (window_type as i32).into(), &title);
|
||||||
))
|
|
||||||
|
let bedrock_window_type = match window_type {
|
||||||
|
WindowType::Crafting => 1,
|
||||||
|
WindowType::Furnace => 2,
|
||||||
|
WindowType::Enchantment => 3,
|
||||||
|
WindowType::BrewingStand => 4,
|
||||||
|
WindowType::Anvil => 5,
|
||||||
|
WindowType::Hopper => 8,
|
||||||
|
WindowType::Beacon => 13,
|
||||||
|
WindowType::BlastFurnace => 27,
|
||||||
|
WindowType::Smoker => 28,
|
||||||
|
WindowType::Stonecutter => 29,
|
||||||
|
WindowType::CartographyTable => 30,
|
||||||
|
WindowType::Grindstone => 26,
|
||||||
|
WindowType::Loom => 24,
|
||||||
|
WindowType::Smithing => 34,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let bedrock_packet = CContainerOpen {
|
||||||
|
container_id: sync_id,
|
||||||
|
container_type: bedrock_window_type,
|
||||||
|
position: BlockPos::ZERO,
|
||||||
|
target_entity_id: VarLong(-1),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.enqueue_packet_editioned(&java_packet, &bedrock_packet)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
drop(screen_handler_temp);
|
drop(screen_handler_temp);
|
||||||
self.on_screen_handler_opened(screen_handler.clone()).await;
|
self.on_screen_handler_opened(screen_handler.clone()).await;
|
||||||
*self.current_screen_handler.lock().await = screen_handler;
|
*self.current_screen_handler.lock().await = screen_handler;
|
||||||
|
|||||||
@ -29,6 +29,7 @@ use pumpkin_util::{GameMode, math::position::BlockPos, text::TextComponent};
|
|||||||
use pumpkin_world::world::BlockFlags;
|
use pumpkin_world::world::BlockFlags;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
block::{BlockHitResult, registry::BlockActionResult},
|
||||||
entity::{EntityBase, player::Player},
|
entity::{EntityBase, player::Player},
|
||||||
net::{DisconnectReason, bedrock::BedrockClient},
|
net::{DisconnectReason, bedrock::BedrockClient},
|
||||||
plugin::player::{
|
plugin::player::{
|
||||||
@ -38,6 +39,7 @@ use crate::{
|
|||||||
server::{Server, seasonal_events},
|
server::{Server, seasonal_events},
|
||||||
world::chunker::{self},
|
world::chunker::{self},
|
||||||
};
|
};
|
||||||
|
use pumpkin_data::BlockDirection;
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
impl BedrockClient {
|
impl BedrockClient {
|
||||||
@ -386,8 +388,60 @@ impl BedrockClient {
|
|||||||
TransactionData::Mismatch(_data) => {
|
TransactionData::Mismatch(_data) => {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
TransactionData::UseItem(_data) => {
|
TransactionData::UseItem(data) => {
|
||||||
// TODO
|
let face = match data.block_face.0 {
|
||||||
|
0 => BlockDirection::Down,
|
||||||
|
2 => BlockDirection::North,
|
||||||
|
3 => BlockDirection::South,
|
||||||
|
4 => BlockDirection::West,
|
||||||
|
5 => BlockDirection::East,
|
||||||
|
_ => BlockDirection::Up,
|
||||||
|
};
|
||||||
|
let world = player.world();
|
||||||
|
let block = world.get_block(&data.block_position);
|
||||||
|
let server = world.server.upgrade().expect("Server is gone");
|
||||||
|
|
||||||
|
if data.action_type.0 == 0 {
|
||||||
|
// Click block
|
||||||
|
let held_item = player.inventory.held_item();
|
||||||
|
|
||||||
|
let result = server
|
||||||
|
.block_registry
|
||||||
|
.use_with_item(
|
||||||
|
block,
|
||||||
|
player,
|
||||||
|
&data.block_position,
|
||||||
|
&BlockHitResult {
|
||||||
|
face: &face,
|
||||||
|
cursor_pos: &data.click_position,
|
||||||
|
},
|
||||||
|
&held_item,
|
||||||
|
&server,
|
||||||
|
&world,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if result.consumes_action() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(result, BlockActionResult::PassToDefaultBlockAction) {
|
||||||
|
server
|
||||||
|
.block_registry
|
||||||
|
.on_use(
|
||||||
|
block,
|
||||||
|
player,
|
||||||
|
&data.block_position,
|
||||||
|
&BlockHitResult {
|
||||||
|
face: &face,
|
||||||
|
cursor_pos: &data.click_position,
|
||||||
|
},
|
||||||
|
&server,
|
||||||
|
&world,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TransactionData::UseItemOnEntity(data) => {
|
TransactionData::UseItemOnEntity(data) => {
|
||||||
let target_runtime_id = data.target_entity_runtime_id.0 as i32;
|
let target_runtime_id = data.target_entity_runtime_id.0 as i32;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user