mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
feat(bedrock): add container open
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use std::io::{Error, Write};
|
||||
use std::io::{Error, Read, Write};
|
||||
use std::num::NonZeroI32;
|
||||
|
||||
use pumpkin_data::item::{BedrockItem, JavaToBedrockItemMapping};
|
||||
@@ -7,10 +7,10 @@ use pumpkin_nbt::Nbt;
|
||||
|
||||
use crate::{
|
||||
codec::{var_int::VarInt, var_uint::VarUInt},
|
||||
serial::PacketWrite,
|
||||
serial::{PacketRead, PacketWrite},
|
||||
};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct NetworkItemDescriptor {
|
||||
// I hate mojang
|
||||
// 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 {
|
||||
#[allow(clippy::option_option)]
|
||||
fn write_with_net_id<W: Write>(
|
||||
|
||||
@@ -3,10 +3,12 @@ use std::io::{Error, ErrorKind, Read};
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
|
||||
use crate::bedrock::network_item::NetworkItemDescriptor;
|
||||
use crate::{
|
||||
codec::{var_int::VarInt, var_uint::VarUInt, var_ulong::VarULong},
|
||||
serial::PacketRead,
|
||||
};
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
|
||||
pub const WINDOW_ID_INVENTORY: i32 = 0;
|
||||
pub const WINDOW_ID_OFF_HAND: i32 = 119;
|
||||
@@ -55,9 +57,8 @@ pub struct InventoryAction {
|
||||
pub window_id: Option<i32>,
|
||||
pub source_flags: Option<u32>,
|
||||
pub inventory_slot: u32,
|
||||
// TODO
|
||||
pub old_item: (),
|
||||
pub new_item: (),
|
||||
pub old_item: NetworkItemDescriptor,
|
||||
pub new_item: NetworkItemDescriptor,
|
||||
}
|
||||
|
||||
impl PacketRead for InventoryAction {
|
||||
@@ -79,16 +80,16 @@ impl PacketRead for InventoryAction {
|
||||
|
||||
let inventory_slot = VarULong::read(buf)?.0 as u32;
|
||||
|
||||
// let old_item = ItemStack::read(buf)?;
|
||||
// let new_item = ItemStack::read(buf)?;
|
||||
let old_item = NetworkItemDescriptor::read(buf)?;
|
||||
let new_item = NetworkItemDescriptor::read(buf)?;
|
||||
|
||||
Ok(Self {
|
||||
source_type,
|
||||
window_id,
|
||||
source_flags,
|
||||
inventory_slot,
|
||||
old_item: (),
|
||||
new_item: (),
|
||||
old_item,
|
||||
new_item,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -99,29 +100,79 @@ pub struct NormalTransactionData;
|
||||
#[derive(Debug, PacketRead)]
|
||||
pub struct MismatchTransactionData;
|
||||
|
||||
#[derive(Debug, PacketRead)]
|
||||
#[derive(Debug)]
|
||||
pub struct UseItemTransactionData {
|
||||
pub action_type: VarULong,
|
||||
pub trigger_type: VarULong,
|
||||
pub action_type: VarUInt,
|
||||
pub trigger_type: VarUInt,
|
||||
pub block_position: BlockPos,
|
||||
pub block_face: 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 target_entity_runtime_id: VarULong,
|
||||
pub action_type: VarULong,
|
||||
pub action_type: VarUInt,
|
||||
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 action_type: VarULong,
|
||||
pub action_type: VarUInt,
|
||||
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)]
|
||||
|
||||
@@ -40,7 +40,7 @@ use pumpkin_data::item_stack::ItemStack;
|
||||
use pumpkin_data::particle::Particle;
|
||||
use pumpkin_data::sound::{Sound, SoundCategory};
|
||||
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::{
|
||||
player_inventory::PlayerInventory, player_screen_handler::PlayerScreenHandler,
|
||||
};
|
||||
@@ -54,7 +54,9 @@ use pumpkin_nbt::compound::NbtCompound;
|
||||
use pumpkin_nbt::tag::NbtTag;
|
||||
use pumpkin_protocol::IdOr;
|
||||
use pumpkin_protocol::SoundEvent;
|
||||
use pumpkin_protocol::bedrock::client::container_open::CContainerOpen;
|
||||
use pumpkin_protocol::codec::var_int::VarInt;
|
||||
use pumpkin_protocol::codec::var_long::VarLong;
|
||||
use pumpkin_protocol::java::client::play::{
|
||||
Animation, CAcknowledgeBlockChange, CActionBar, CChangeDifficulty, CCloseContainer,
|
||||
CCombatDeath, CCustomPayload, CDisguisedChatMessage, CEntityAnimation, CEntityPositionSync,
|
||||
@@ -3326,16 +3328,44 @@ impl Player {
|
||||
.await
|
||||
{
|
||||
let screen_handler_temp = screen_handler.lock().await;
|
||||
let sync_id = screen_handler_temp.sync_id();
|
||||
let window_type = screen_handler_temp
|
||||
.window_type()
|
||||
.expect("Can't open PlayerScreenHandler");
|
||||
|
||||
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(&COpenScreen::new(
|
||||
screen_handler_temp.sync_id().into(),
|
||||
(screen_handler_temp
|
||||
.window_type()
|
||||
.expect("Can't open PlayerScreenHandler") as i32)
|
||||
.into(),
|
||||
&screen_handler_factory.get_display_name(),
|
||||
))
|
||||
.enqueue_packet_editioned(&java_packet, &bedrock_packet)
|
||||
.await;
|
||||
|
||||
drop(screen_handler_temp);
|
||||
self.on_screen_handler_opened(screen_handler.clone()).await;
|
||||
*self.current_screen_handler.lock().await = screen_handler;
|
||||
@@ -3366,16 +3396,42 @@ impl Player {
|
||||
}
|
||||
|
||||
let screen_handler_temp = screen_handler.lock().await;
|
||||
let sync_id = screen_handler_temp.sync_id();
|
||||
let window_type = screen_handler_temp
|
||||
.window_type()
|
||||
.expect("Can't open PlayerScreenHandler");
|
||||
|
||||
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(&COpenScreen::new(
|
||||
screen_handler_temp.sync_id().into(),
|
||||
(screen_handler_temp
|
||||
.window_type()
|
||||
.expect("Can't open PlayerScreenHandler") as i32)
|
||||
.into(),
|
||||
&title,
|
||||
))
|
||||
.enqueue_packet_editioned(&java_packet, &bedrock_packet)
|
||||
.await;
|
||||
|
||||
drop(screen_handler_temp);
|
||||
self.on_screen_handler_opened(screen_handler.clone()).await;
|
||||
*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 crate::{
|
||||
block::{BlockHitResult, registry::BlockActionResult},
|
||||
entity::{EntityBase, player::Player},
|
||||
net::{DisconnectReason, bedrock::BedrockClient},
|
||||
plugin::player::{
|
||||
@@ -38,6 +39,7 @@ use crate::{
|
||||
server::{Server, seasonal_events},
|
||||
world::chunker::{self},
|
||||
};
|
||||
use pumpkin_data::BlockDirection;
|
||||
use tracing::{debug, info};
|
||||
|
||||
impl BedrockClient {
|
||||
@@ -386,8 +388,60 @@ impl BedrockClient {
|
||||
TransactionData::Mismatch(_data) => {
|
||||
// TODO
|
||||
}
|
||||
TransactionData::UseItem(_data) => {
|
||||
// TODO
|
||||
TransactionData::UseItem(data) => {
|
||||
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) => {
|
||||
let target_runtime_id = data.target_entity_runtime_id.0 as i32;
|
||||
|
||||
Reference in New Issue
Block a user