mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
feat(bedrock): add CMobEquipment
This commit is contained in:
45
crates/pumpkin-protocol/src/bedrock/client/mob_equipment.rs
Normal file
45
crates/pumpkin-protocol/src/bedrock/client/mob_equipment.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use crate::{
|
||||
bedrock::network_item::NetworkItemStackDescriptor, codec::var_ulong::VarULong,
|
||||
serial::PacketWrite,
|
||||
};
|
||||
use pumpkin_macros::packet;
|
||||
|
||||
#[derive(PacketWrite, Debug)]
|
||||
#[packet(31)]
|
||||
pub struct CMobEquipment {
|
||||
pub entity_runtime_id: VarULong,
|
||||
pub item: NetworkItemStackDescriptor,
|
||||
pub inventory_slot: u8,
|
||||
pub hotbar_slot: u8,
|
||||
pub window_id: u8,
|
||||
}
|
||||
|
||||
impl CMobEquipment {
|
||||
#[must_use]
|
||||
pub const fn new(
|
||||
entity_runtime_id: u64,
|
||||
item: NetworkItemStackDescriptor,
|
||||
inventory_slot: u8,
|
||||
hotbar_slot: u8,
|
||||
window_id: u8,
|
||||
) -> Self {
|
||||
Self {
|
||||
entity_runtime_id: VarULong(entity_runtime_id),
|
||||
item,
|
||||
inventory_slot,
|
||||
hotbar_slot,
|
||||
window_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::packet::Packet;
|
||||
|
||||
#[test]
|
||||
fn mob_equipment_packet_id() {
|
||||
assert_eq!(CMobEquipment::PACKET_ID, 31);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ pub mod item_registry;
|
||||
pub mod item_stack_response;
|
||||
pub mod level_chunk;
|
||||
pub mod level_event;
|
||||
pub mod mob_equipment;
|
||||
pub mod modal_form_request;
|
||||
pub mod move_actor_absolute;
|
||||
pub mod move_actor_delta;
|
||||
@@ -73,6 +74,7 @@ pub use item_stack_response::*;
|
||||
pub use level_chunk::*;
|
||||
pub use level_event::*;
|
||||
pub use level_sound_event::*;
|
||||
pub use mob_equipment::*;
|
||||
pub use modal_form_request::*;
|
||||
pub use move_actor_absolute::*;
|
||||
pub use move_actor_delta::*;
|
||||
|
||||
@@ -193,7 +193,7 @@ impl LivingEntity {
|
||||
if equipment.is_empty() {
|
||||
return;
|
||||
}
|
||||
let equipment: Vec<(i8, ItemStackSerializer)> = equipment
|
||||
let equipment_java: Vec<(i8, ItemStackSerializer)> = equipment
|
||||
.iter()
|
||||
.map(|(slot, stack)| {
|
||||
(
|
||||
@@ -202,10 +202,43 @@ impl LivingEntity {
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
self.entity.world.load().broadcast_packet_except(
|
||||
&[self.entity.entity_uuid],
|
||||
&CSetEquipment::new(self.entity_id().into(), equipment),
|
||||
);
|
||||
let je_packet = CSetEquipment::new(self.entity_id().into(), equipment_java);
|
||||
|
||||
let mut sent_editioned = false;
|
||||
for (slot, stack) in equipment {
|
||||
if *slot == EquipmentSlot::MAIN_HAND || *slot == EquipmentSlot::OFF_HAND {
|
||||
let window_id = if *slot == EquipmentSlot::OFF_HAND {
|
||||
120
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let be_packet = pumpkin_protocol::bedrock::client::CMobEquipment::new(
|
||||
self.entity_id() as u64,
|
||||
pumpkin_protocol::bedrock::network_item::NetworkItemStackDescriptor::from(
|
||||
stack,
|
||||
),
|
||||
0,
|
||||
0,
|
||||
window_id,
|
||||
);
|
||||
self.entity
|
||||
.world
|
||||
.load()
|
||||
.broadcast_packet_except_editioned_sync(
|
||||
&[self.entity.entity_uuid],
|
||||
&je_packet,
|
||||
&be_packet,
|
||||
);
|
||||
sent_editioned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !sent_editioned {
|
||||
self.entity
|
||||
.world
|
||||
.load()
|
||||
.broadcast_packet_except(&[self.entity.entity_uuid], &je_packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// Picks up and Item entity or XP Orb
|
||||
|
||||
@@ -68,11 +68,11 @@ use pumpkin_protocol::java::client::play::{
|
||||
CCustomPayload, CDisguisedChatMessage, CEntityAnimation, CEntityPositionSync, CGameEvent,
|
||||
CItemCooldown, CMapItemData, COpenScreen, CParticle, CPlayerAbilities, CPlayerInfoUpdate,
|
||||
CPlayerPosition, CPlayerSpawnPosition, CRespawn, CSetCamera, CSetContainerContent,
|
||||
CSetContainerProperty, CSetContainerSlot, CSetCursorItem, CSetEquipment, CSetExperience,
|
||||
CSetHealth, CSetPlayerInventory, CSetSelectedSlot, CSoundEffect, CStopSound, CSubtitle,
|
||||
CSystemChatMessage, CTabList, CTitleAnimation, CTitleText, CUnloadChunk, CUpdateMobEffect,
|
||||
CUpdateTime, GameEvent, MapIcon, MapPatch, Metadata, PlayerAction, PlayerInfoFlags,
|
||||
PlayerSpawnData, PreviousMessage, Statistic,
|
||||
CSetContainerProperty, CSetContainerSlot, CSetCursorItem, CSetExperience, CSetHealth,
|
||||
CSetPlayerInventory, CSetSelectedSlot, CSoundEffect, CStopSound, CSubtitle, CSystemChatMessage,
|
||||
CTabList, CTitleAnimation, CTitleText, CUnloadChunk, CUpdateMobEffect, CUpdateTime, GameEvent,
|
||||
MapIcon, MapPatch, Metadata, PlayerAction, PlayerInfoFlags, PlayerSpawnData, PreviousMessage,
|
||||
Statistic,
|
||||
};
|
||||
use pumpkin_protocol::java::server::play::{
|
||||
SClickSlot, SContainerButtonClick, SRenameItem, SlotActionType,
|
||||
@@ -5790,18 +5790,8 @@ impl InventoryPlayer for Player {
|
||||
stack: &'a ItemStack,
|
||||
) -> PlayerFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
let chunk_pos = self.living_entity.entity.chunk_pos.load();
|
||||
self.world().broadcast_to_chunk_except(
|
||||
chunk_pos,
|
||||
&[self.get_entity().entity_uuid],
|
||||
&CSetEquipment::new(
|
||||
self.entity_id().into(),
|
||||
vec![(
|
||||
slot.discriminant(),
|
||||
ItemStackSerializer::from(stack.clone()),
|
||||
)],
|
||||
),
|
||||
);
|
||||
self.living_entity
|
||||
.send_equipment_changes(&[(slot.clone(), stack.clone())]);
|
||||
|
||||
if let Some(equippable) = stack.get_data_component::<EquippableImpl>() {
|
||||
self.world().play_sound_event(
|
||||
|
||||
@@ -6,7 +6,7 @@ use pumpkin_data::item::{BedrockItem, BedrockItemVersion};
|
||||
use pumpkin_protocol::bedrock::client::EntityProperties;
|
||||
use pumpkin_protocol::bedrock::client::item_registry::{CItemRegistry, ItemDefinition};
|
||||
use pumpkin_protocol::bedrock::client::level_event::{CLevelEvent, LevelEvent};
|
||||
use pumpkin_protocol::bedrock::network_item::NetworkItemDescriptor;
|
||||
use pumpkin_protocol::bedrock::network_item::{NetworkItemDescriptor, NetworkItemStackDescriptor};
|
||||
use pumpkin_protocol::codec::data_component::data_to_proto_sound;
|
||||
use pumpkin_world::generation::proto_chunk::GenerationCache;
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
@@ -2527,6 +2527,22 @@ impl World {
|
||||
&bedrock_add_player,
|
||||
);
|
||||
|
||||
let held_item = player.inventory().held_item().await;
|
||||
|
||||
let be_mob_equipment = pumpkin_protocol::bedrock::client::CMobEquipment::new(
|
||||
runtime_id,
|
||||
NetworkItemStackDescriptor::from(&held_item),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
self.broadcast_packet_except_editioned_sync(
|
||||
&[gameprofile.id],
|
||||
&CSetEquipment::new((runtime_id as i32).into(), vec![]),
|
||||
&be_mob_equipment,
|
||||
);
|
||||
|
||||
// Broadcast metadata to Java players so they can correctly interact with the new player
|
||||
let skin_parts = player.config.load().skin_parts;
|
||||
|
||||
@@ -2606,6 +2622,18 @@ impl World {
|
||||
};
|
||||
|
||||
client.send_game_packet(&ex_add_player).await;
|
||||
|
||||
let ex_held_item = existing_player.inventory().held_item().await;
|
||||
|
||||
let ex_be_mob_equipment = pumpkin_protocol::bedrock::client::CMobEquipment::new(
|
||||
existing_player.entity_id() as u64,
|
||||
NetworkItemStackDescriptor::from(&ex_held_item),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
client.send_game_packet(&ex_be_mob_equipment).await;
|
||||
}
|
||||
|
||||
// 3. Trigger Join Event and Broadcast Join Message
|
||||
@@ -2981,6 +3009,22 @@ impl World {
|
||||
&bedrock_add_player,
|
||||
);
|
||||
|
||||
let held_item = player.inventory().held_item().await;
|
||||
|
||||
let be_mob_equipment = pumpkin_protocol::bedrock::client::CMobEquipment::new(
|
||||
entity_id as u64,
|
||||
NetworkItemStackDescriptor::from(&held_item),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
self.broadcast_packet_except_editioned_sync(
|
||||
&[player.gameprofile.id],
|
||||
&CSetEquipment::new(entity_id.into(), vec![]),
|
||||
&be_mob_equipment,
|
||||
);
|
||||
|
||||
// Broadcast metadata to Java players so they can correctly interact with the new player
|
||||
let skin_parts = player.config.load().skin_parts;
|
||||
|
||||
@@ -3153,12 +3197,9 @@ impl World {
|
||||
};
|
||||
|
||||
{
|
||||
let mut equipment_list = Vec::new();
|
||||
|
||||
equipment_list.push((
|
||||
EquipmentSlot::MAIN_HAND.discriminant(),
|
||||
existing_player.inventory.held_item().await,
|
||||
));
|
||||
let held_item = existing_player.inventory.held_item().await;
|
||||
let mut equipment_list =
|
||||
vec![(EquipmentSlot::MAIN_HAND.discriminant(), held_item.clone())];
|
||||
|
||||
let equipment_guard = existing_player.inventory.entity_equipment.lock().await;
|
||||
for (slot, item_stack) in &equipment_guard.equipment {
|
||||
@@ -3170,11 +3211,19 @@ impl World {
|
||||
.map(|(slot, stack)| (*slot, ItemStackSerializer::from(stack.clone())))
|
||||
.collect();
|
||||
|
||||
client
|
||||
.enqueue_packet(&CSetEquipment::new(
|
||||
existing_player.entity_id().into(),
|
||||
equipment,
|
||||
))
|
||||
let je_packet = CSetEquipment::new(existing_player.entity_id().into(), equipment);
|
||||
|
||||
let be_mob_equipment = pumpkin_protocol::bedrock::client::CMobEquipment::new(
|
||||
existing_player.entity_id() as u64,
|
||||
NetworkItemStackDescriptor::from(&held_item),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
player
|
||||
.client
|
||||
.enqueue_packet_editioned(&je_packet, &be_mob_equipment)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
@@ -3291,12 +3340,8 @@ impl World {
|
||||
}
|
||||
|
||||
async fn send_player_equipment(&self, from: &Player) {
|
||||
let mut equipment_list = Vec::new();
|
||||
|
||||
equipment_list.push((
|
||||
EquipmentSlot::MAIN_HAND.discriminant(),
|
||||
from.inventory.held_item().await,
|
||||
));
|
||||
let held_item = from.inventory.held_item().await;
|
||||
let mut equipment_list = vec![(EquipmentSlot::MAIN_HAND.discriminant(), held_item.clone())];
|
||||
|
||||
let equipment_guard = from.inventory.entity_equipment.lock().await;
|
||||
for (slot, item_stack) in &equipment_guard.equipment {
|
||||
@@ -3307,12 +3352,24 @@ impl World {
|
||||
.iter()
|
||||
.map(|(slot, stack)| (*slot, ItemStackSerializer::from(stack.clone())))
|
||||
.collect();
|
||||
let je_packet = CSetEquipment::new(from.entity_id().into(), equipment);
|
||||
|
||||
let be_mob_equipment = pumpkin_protocol::bedrock::client::CMobEquipment::new(
|
||||
from.entity_id() as u64,
|
||||
NetworkItemStackDescriptor::from(&held_item),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
let chunk_pos = from.get_entity().chunk_pos.load();
|
||||
self.broadcast_to_chunk_except(
|
||||
self.broadcast_to_chunk_except_editioned(
|
||||
chunk_pos,
|
||||
&[from.get_entity().entity_uuid],
|
||||
&CSetEquipment::new(from.entity_id().into(), equipment),
|
||||
);
|
||||
&je_packet,
|
||||
&be_mob_equipment,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn send_world_info(
|
||||
|
||||
Reference in New Issue
Block a user