diff --git a/pumpkin-data/build/build.rs b/pumpkin-data/build/build.rs index 1b0e9372e..eec66566c 100644 --- a/pumpkin-data/build/build.rs +++ b/pumpkin-data/build/build.rs @@ -83,5 +83,10 @@ pub fn write_generated_file(content: TokenStream, out_file: &str) { // Try to format the output for debugging purposes. // Doesn't matter if rustfmt is unavailable. - let _ = Command::new("rustfmt").arg(path).output(); + let _ = Command::new("rustfmt").arg(&path).output(); + // Try to auto optimize using clippy. + // Doesn't matter if rustfmt is unavailable. + let _ = Command::new("cargo clippy --fix --allow-dirty") + .arg(&path) + .output(); } diff --git a/pumpkin-inventory/src/equipment_slot.rs b/pumpkin-inventory/src/equipment_slot.rs index 6c8e0d52d..b70c6790e 100644 --- a/pumpkin-inventory/src/equipment_slot.rs +++ b/pumpkin-inventory/src/equipment_slot.rs @@ -125,7 +125,7 @@ impl EquipmentSlot { ) } - pub fn discriminant(&self) -> i8 { + pub const fn discriminant(&self) -> i8 { match self { Self::MainHand(_) => 0, Self::OffHand(_) => 1, diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index b46ebd0a3..2a3c97a88 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -41,11 +41,9 @@ use pumpkin_data::{ world::{RAW, WorldEvent}, }; use pumpkin_data::{BlockDirection, block_properties::get_block_outline_shapes}; +use pumpkin_inventory::equipment_slot::EquipmentSlot; use pumpkin_macros::send_cancellable; use pumpkin_nbt::{compound::NbtCompound, to_bytes_unnamed}; -use pumpkin_protocol::client::play::{ - CBlockEvent, CRemoveMobEffect, CSetEntityMetadata, MetaDataType, Metadata, -}; use pumpkin_protocol::codec::identifier::Identifier; use pumpkin_protocol::ser::serializer::Serializer; use pumpkin_protocol::{ @@ -57,6 +55,12 @@ use pumpkin_protocol::{ }, server::play::SChatMessage, }; +use pumpkin_protocol::{ + client::play::{ + CBlockEvent, CRemoveMobEffect, CSetEntityMetadata, CSetEquipment, MetaDataType, Metadata, + }, + codec::item_stack_seralizer::ItemStackSerializer, +}; use pumpkin_protocol::{ client::play::{ CBlockUpdate, CDisguisedChatMessage, CExplosion, CRespawn, CSetBlockDestroyStage, @@ -324,6 +328,15 @@ impl World { where P: ClientPacket, { + let current_players = self.players.read().await; + let players: Vec<_> = current_players + .iter() + .filter(|c| !except.contains(c.0)) + .collect(); + if players.is_empty() { + return; + } + let mut packet_buf = Vec::new(); if let Err(err) = packet.write(&mut packet_buf) { log::error!("Failed to serialize packet {}: {}", P::PACKET_ID, err); @@ -331,8 +344,7 @@ impl World { } let packet_data: Bytes = packet_buf.into(); - let current_players = self.players.read().await; - for (_, player) in current_players.iter().filter(|c| !except.contains(c.0)) { + for (_, player) in players { player.client.enqueue_packet_data(packet_data.clone()).await; } } @@ -828,6 +840,32 @@ impl World { .await; player.send_active_effects().await; + self.send_player_equipment(&player).await; + } + + 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().lock().await, + )); + + for (slot, item_arc_mutex) in &from.inventory.entity_equipment.lock().await.equipment { + let item_guard = item_arc_mutex.lock().await; + let item_stack = *item_guard; + equipment_list.push((slot.discriminant(), item_stack)); + } + + let equipment: Vec<(i8, ItemStackSerializer)> = equipment_list + .iter() + .map(|(slot, stack)| (*slot, ItemStackSerializer::from(*stack))) + .collect(); + self.broadcast_packet_except( + &[from.get_entity().entity_uuid], + &CSetEquipment::new(from.entity_id().into(), equipment), + ) + .await; } pub async fn send_world_info( @@ -1127,9 +1165,8 @@ impl World { /// Gets a `Player` by a username pub async fn get_player_by_name(&self, name: &str) -> Option> { - let lowercase = name.to_lowercase(); for player in self.players.read().await.values() { - if player.gameprofile.name.to_lowercase() == lowercase { + if player.gameprofile.name.eq_ignore_ascii_case(name) { return Some(player.clone()); } }