From 1aa4ca878ed413abf7e23de1ab734e1bb94bf38b Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 29 Jun 2022 13:00:41 -0700 Subject: [PATCH] Add player metadata to client --- build/entity.rs | 102 ++++++++++++++++++----------------------- examples/cow_sphere.rs | 4 +- src/client.rs | 39 +++++++++++++--- 3 files changed, 79 insertions(+), 66 deletions(-) diff --git a/build/entity.rs b/build/entity.rs index 0a3abc0..87f82cc 100644 --- a/build/entity.rs +++ b/build/entity.rs @@ -2105,6 +2105,34 @@ pub fn build() -> anyhow::Result<()> { }) .collect::(); + let initial_metadata_fields = fields.iter().enumerate().map(|(idx, f)| { + let name = ident(f.name.to_snake_case()); + let default = f.typ.default_expr(); + let index: u8 = idx.try_into().unwrap(); + let type_id = f.typ.type_id(); + quote! { + if self.#name != #default { + data.push(#index); + VarInt(#type_id).encode(data).unwrap(); + self.#name.encode(data).unwrap(); + } + } + }).collect::(); + + let updated_metadata_fields = fields.iter().enumerate().map(|(idx, f)| { + let name = ident(f.name.to_snake_case()); + let u8_index: u8 = idx.try_into().unwrap(); + let u32_index = idx as u32; + let type_id = f.typ.type_id(); + quote! { + if (self.modified_flags >> #u32_index) & 1 == 1 { + data.push(#u8_index); + VarInt(#type_id).encode(data).unwrap(); + self.#name.encode(data).unwrap(); + } + } + }).collect::(); + quote! { pub struct #name { /// Contains a set bit for each modified field. @@ -2113,7 +2141,7 @@ pub fn build() -> anyhow::Result<()> { } impl #name { - pub(super) fn new() -> Self { + pub(crate) fn new() -> Self { Self { modified_flags: 0, #(#constructor_fields)* @@ -2121,62 +2149,22 @@ pub fn build() -> anyhow::Result<()> { } #getter_setters - } - } - }); - let initial_metadata_arms = entities.iter().map(|&entity| { - let name = ident(entity.name.to_pascal_case()); - let mut fields = Vec::new(); - collect_class_fields(entity, &mut fields); - - let check_fields = fields.into_iter().enumerate().map(|(idx, f)| { - let name = ident(f.name.to_snake_case()); - let default = f.typ.default_expr(); - let index: u8 = idx.try_into().unwrap(); - let type_id = f.typ.type_id(); - quote! { - if m.#name != #default { - data.push(#index); - VarInt(#type_id).encode(&mut data).unwrap(); - m.#name.encode(&mut data).unwrap(); - } - } - }); - - quote! { - Self::#name(m) => { - #(#check_fields)* - } - } - }); - - let updated_metadata_arms = entities.iter().map(|&entity| { - let name = ident(entity.name.to_pascal_case()); - let mut fields = Vec::new(); - collect_class_fields(entity, &mut fields); - - let update_fields = fields.into_iter().enumerate().map(|(idx, f)| { - let name = ident(f.name.to_snake_case()); - let u8_index: u8 = idx.try_into().unwrap(); - let u32_index = idx as u32; - let type_id = f.typ.type_id(); - quote! { - if (m.modified_flags >> #u32_index) & 1 == 1 { - data.push(#u8_index); - VarInt(#type_id).encode(&mut data).unwrap(); - m.#name.encode(&mut data).unwrap(); - } - } - }); - - quote! { - Self::#name(m) => { - if m.modified_flags == 0 { - return None; + pub(crate) fn initial_metadata(&self, data: &mut Vec) { + #initial_metadata_fields } - #(#update_fields)* + pub(crate) fn updated_metadata(&self, data: &mut Vec) { + if self.modified_flags == 0 { + return; + } + + #updated_metadata_fields + } + + pub(crate) fn clear_modifications(&mut self) { + self.modified_flags = 0; + } } } }); @@ -2221,7 +2209,7 @@ pub fn build() -> anyhow::Result<()> { let mut data = Vec::new(); match self { - #(#initial_metadata_arms)* + #(Self::#entity_type_variants(e) => e.initial_metadata(&mut data),)* } if data.is_empty() { @@ -2236,7 +2224,7 @@ pub fn build() -> anyhow::Result<()> { let mut data = Vec::new(); match self { - #(#updated_metadata_arms)* + #(Self::#entity_type_variants(e) => e.updated_metadata(&mut data),)* } if data.is_empty() { @@ -2249,7 +2237,7 @@ pub fn build() -> anyhow::Result<()> { pub(super) fn clear_modifications(&mut self) { match self { - #(Self::#entity_type_variants(m) => m.modified_flags = 0,)* + #(Self::#entity_type_variants(e) => e.clear_modifications(),)* } } } diff --git a/examples/cow_sphere.rs b/examples/cow_sphere.rs index 700ecd2..bfee1e4 100644 --- a/examples/cow_sphere.rs +++ b/examples/cow_sphere.rs @@ -9,8 +9,8 @@ use valence::config::{Config, ServerListPing}; use valence::text::Color; use valence::util::to_yaw_and_pitch; use valence::{ - async_trait, DimensionId, EntityId, EntityType, Server, ShutdownResult, Text, - TextFormat, WorldId, Worlds, Client, + async_trait, Client, DimensionId, EntityId, EntityType, Server, ShutdownResult, Text, + TextFormat, WorldId, Worlds, }; use vek::{Mat3, Vec3}; diff --git a/src/client.rs b/src/client.rs index 4e50c8d..d94268a 100644 --- a/src/client.rs +++ b/src/client.rs @@ -13,19 +13,20 @@ use crate::biome::{Biome, BiomeGrassColorModifier, BiomePrecipitation}; use crate::block_pos::BlockPos; use crate::byte_angle::ByteAngle; use crate::dimension::{Dimension, DimensionEffects}; +use crate::entity::types::Player; use crate::entity::{velocity_to_packet_units, EntityType}; use crate::packets::play::c2s::{C2sPlayPacket, DiggingStatus}; use crate::packets::play::s2c::{ AcknowledgeBlockChanges, Biome as BiomeRegistryBiome, BiomeAdditionsSound, BiomeEffects, BiomeMoodSound, BiomeMusic, BiomeParticle, BiomeParticleOptions, BiomeProperty, BiomeRegistry, ChangeGameState, ChangeGameStateReason, ChatTypeRegistry, DestroyEntities, DimensionType, - DimensionTypeRegistry, DimensionTypeRegistryEntry, Disconnect, EntityHeadLook, EntityPosition, - EntityPositionAndRotation, EntityRotation, EntityTeleport, EntityVelocity, JoinGame, KeepAlive, - PlayerPositionAndLook, PlayerPositionAndLookFlags, RegistryCodec, S2cPlayPacket, SpawnPosition, - UnloadChunk, UpdateViewDistance, UpdateViewPosition, + DimensionTypeRegistry, DimensionTypeRegistryEntry, Disconnect, EntityHeadLook, EntityMetadata, + EntityPosition, EntityPositionAndRotation, EntityRotation, EntityTeleport, EntityVelocity, + JoinGame, KeepAlive, PlayerPositionAndLook, PlayerPositionAndLookFlags, RegistryCodec, + S2cPlayPacket, SpawnPosition, UnloadChunk, UpdateViewDistance, UpdateViewPosition, }; use crate::player_textures::SignedPlayerTextures; -use crate::protocol::{BoundedInt, Nbt}; +use crate::protocol::{BoundedInt, Nbt, RawBytes}; use crate::server::C2sPacketChannels; use crate::slotmap::{Key, SlotMap}; use crate::util::{chunks_in_view_distance, is_chunk_in_view_distance}; @@ -135,8 +136,8 @@ pub struct Client { old_game_mode: GameMode, settings: Option, dug_blocks: Vec, - // /// The metadata for the client's own player entity. - // player_meta: Player, + /// The metadata for the client's own player entity. + player_meta: Player, } impl Client { @@ -177,6 +178,7 @@ impl Client { old_game_mode: GameMode::Survival, settings: None, dug_blocks: Vec::new(), + player_meta: Player::new(), } } @@ -328,6 +330,14 @@ impl Client { } } + pub fn meta(&self) -> &Player { + &self.player_meta + } + + pub fn meta_mut(&mut self) -> &mut Player { + &mut self.player_meta + } + /// Attempts to enqueue a play packet to be sent to this client. The client /// is disconnected if the clientbound packet buffer is full. pub(crate) fn send_packet(&mut self, packet: impl Into) { @@ -813,6 +823,21 @@ impl Client { }); } + // Update the client's own player metadata. + { + let mut data = Vec::new(); + self.player_meta.updated_metadata(&mut data); + + if !data.is_empty() { + data.push(0xff); + + self.send_packet(EntityMetadata { + entity_id: VarInt(0), + metadata: RawBytes(data), + }); + } + } + // Spawn new entities within the view distance. let pos = self.position(); spatial_index.query::<_, _, ()>(