diff --git a/examples/conway.rs b/examples/conway.rs index 3f1abdb..b351e4e 100644 --- a/examples/conway.rs +++ b/examples/conway.rs @@ -7,7 +7,7 @@ use std::sync::Mutex; use log::LevelFilter; use num::Integer; use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator}; -use valence::client::{ClientId, ClientEvent, GameMode, EntityEvent}; +use valence::client::{ClientId, ClientEvent, GameMode}; use valence::config::{Config, ServerListPing}; use valence::text::Color; use valence::{ diff --git a/src/client.rs b/src/client.rs index 8b8d072..63cec1e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -145,7 +145,7 @@ pub struct Client { settings: Option, dug_blocks: Vec, msgs_to_send: Vec, - entity_events: Vec<(Option, EntityEvent)>, + entity_events: Vec, /// The metadata for the client's own player entity. player_meta: Player, } @@ -316,8 +316,8 @@ impl Client { self.events.pop_front() } - pub fn push_entity_event(&mut self, target: Option, event: EntityEvent) { - self.entity_events.push((target, event)); + pub fn push_entity_event(&mut self, event: EntityEvent) { + self.entity_events.push(event); } /// The current view distance of this client measured in chunks. @@ -838,9 +838,7 @@ impl Client { self.loaded_entities.retain(|&id| { if let Some(entity) = entities.get(id) { debug_assert!(entity.typ() != EntityType::Marker); - if self.new_position.distance(entity.position()) <= view_dist as f64 * 16.0 - && !entity.flags().type_modified() - { + if self.new_position.distance(entity.position()) <= view_dist as f64 * 16.0 { if let Some(meta) = entity.updated_metadata_packet(id) { send_packet(&mut self.send, meta); } @@ -921,6 +919,16 @@ impl Client { ) } + for &e in entity.events() { + send_packet( + &mut self.send, + EntityEventPacket { + entity_id: id.to_network_id(), + entity_status: e, + }, + ); + } + return true; } } @@ -954,44 +962,41 @@ impl Client { world.spatial_index.query::<_, _, ()>( |bb| bb.projected_point(pos).distance(pos) <= view_dist as f64 * 16.0, |id, _| { - if self.loaded_entities.insert(id) { - let entity = entities.get(id).unwrap(); - if entity.typ() != EntityType::Marker { - self.send_packet( - entity - .spawn_packet(id) - .expect("should not be a marker entity"), - ); + let entity = entities.get(id).unwrap(); + if entity.typ() != EntityType::Marker && self.loaded_entities.insert(id) { + self.send_packet( + entity + .spawn_packet(id) + .expect("should not be a marker entity"), + ); - if let Some(meta) = entity.initial_metadata_packet(id) { - self.send_packet(meta); - } + if let Some(meta) = entity.initial_metadata_packet(id) { + self.send_packet(meta); + } + + for &e in entity.events() { + send_packet( + &mut self.send, + EntityEventPacket { + entity_id: id.to_network_id(), + entity_status: e, + }, + ); } } None }, ); - for (target, event) in self.entity_events.drain(..) { - if let Some(target) = target { - if self.loaded_entities.contains(&target) { - send_packet( - &mut self.send, - EntityEventPacket { - entity_id: target.to_network_id(), - entity_status: event, - }, - ) - } - } else { - send_packet( - &mut self.send, - EntityEventPacket { - entity_id: 0, - entity_status: event, - }, - ); - } + // Send entity events for the client's own player entity. + for event in self.entity_events.drain(..) { + send_packet( + &mut self.send, + EntityEventPacket { + entity_id: 0, + entity_status: event, + }, + ); } self.old_position = self.new_position; diff --git a/src/entity.rs b/src/entity.rs index 416c4aa..d225b05 100644 --- a/src/entity.rs +++ b/src/entity.rs @@ -12,6 +12,7 @@ pub use types::{EntityMeta, EntityType}; use uuid::Uuid; use vek::{Aabb, Vec3}; +pub use crate::protocol::packets::play::s2c::EntityEventStatus as EntityEvent; use crate::protocol::packets::play::s2c::{ AddEntity, AddExperienceOrb, AddPlayer, S2cPlayPacket, SetEntityMetadata, }; @@ -66,6 +67,7 @@ impl Entities { head_yaw: 0.0, velocity: Vec3::default(), uuid, + events: Vec::new(), }); ve.insert(EntityId(k)); @@ -157,10 +159,11 @@ impl Entities { for (_, e) in self.iter_mut() { e.old_position = e.new_position; e.meta.clear_modifications(); + e.events.clear(); - let on_ground = e.flags.on_ground(); - e.flags = EntityFlags(0); - e.flags.set_on_ground(on_ground); + e.flags.set_yaw_or_pitch_modified(false); + e.flags.set_head_yaw_modified(false); + e.flags.set_velocity_modified(false); } } } @@ -187,19 +190,18 @@ pub struct Entity { head_yaw: f32, velocity: Vec3, uuid: Uuid, + events: Vec, } /// Contains a bit for certain fields in [`Entity`] to track if they have been /// modified. #[bitfield(u8)] pub(crate) struct EntityFlags { - /// When the type of this entity changes. - pub type_modified: bool, pub yaw_or_pitch_modified: bool, pub head_yaw_modified: bool, pub velocity_modified: bool, pub on_ground: bool, - #[bits(3)] + #[bits(4)] _pad: u8, } @@ -308,56 +310,12 @@ impl Entity { self.flags.set_on_ground(on_ground); } - /// Gets the metadata packet to send to clients after this entity has been - /// spawned. - /// - /// Is `None` if there is no initial metadata. - pub(crate) fn initial_metadata_packet(&self, this_id: EntityId) -> Option { - self.meta.initial_metadata().map(|meta| SetEntityMetadata { - entity_id: VarInt(this_id.to_network_id()), - metadata: RawBytes(meta), - }) + pub fn push_event(&mut self, event: EntityEvent) { + self.events.push(event); } - /// Gets the metadata packet to send to clients when the entity is modified. - /// - /// Is `None` if this entity's metadata has not been modified. - pub(crate) fn updated_metadata_packet(&self, this_id: EntityId) -> Option { - self.meta.updated_metadata().map(|meta| SetEntityMetadata { - entity_id: VarInt(this_id.to_network_id()), - metadata: RawBytes(meta), - }) - } - - pub(crate) fn spawn_packet(&self, this_id: EntityId) -> Option { - match &self.meta { - EntityMeta::Marker(_) => None, - EntityMeta::ExperienceOrb(_) => { - Some(EntitySpawnPacket::SpawnExperienceOrb(AddExperienceOrb { - entity_id: VarInt(this_id.to_network_id()), - position: self.new_position, - count: 0, // TODO - })) - } - EntityMeta::Player(_) => Some(EntitySpawnPacket::SpawnPlayer(AddPlayer { - entity_id: VarInt(this_id.to_network_id()), - player_uuid: self.uuid, - position: self.new_position, - yaw: ByteAngle::from_degrees(self.yaw), - pitch: ByteAngle::from_degrees(self.pitch), - })), - _ => Some(EntitySpawnPacket::SpawnEntity(AddEntity { - entity_id: VarInt(this_id.to_network_id()), - object_uuid: self.uuid, - typ: VarInt(self.typ() as i32), - position: self.new_position, - pitch: ByteAngle::from_degrees(self.pitch), - yaw: ByteAngle::from_degrees(self.yaw), - head_yaw: ByteAngle::from_degrees(self.head_yaw), - data: VarInt(1), // TODO - velocity: velocity_to_packet_units(self.velocity), - })), - } + pub(crate) fn events(&self) -> &[EntityEvent] { + &self.events } pub fn hitbox(&self) -> Aabb { @@ -502,6 +460,58 @@ impl Entity { aabb_from_bottom_and_size(self.new_position, dims.into()) } + + /// Gets the metadata packet to send to clients after this entity has been + /// spawned. + /// + /// Is `None` if there is no initial metadata. + pub(crate) fn initial_metadata_packet(&self, this_id: EntityId) -> Option { + self.meta.initial_metadata().map(|meta| SetEntityMetadata { + entity_id: VarInt(this_id.to_network_id()), + metadata: RawBytes(meta), + }) + } + + /// Gets the metadata packet to send to clients when the entity is modified. + /// + /// Is `None` if this entity's metadata has not been modified. + pub(crate) fn updated_metadata_packet(&self, this_id: EntityId) -> Option { + self.meta.updated_metadata().map(|meta| SetEntityMetadata { + entity_id: VarInt(this_id.to_network_id()), + metadata: RawBytes(meta), + }) + } + + pub(crate) fn spawn_packet(&self, this_id: EntityId) -> Option { + match &self.meta { + EntityMeta::Marker(_) => None, + EntityMeta::ExperienceOrb(_) => { + Some(EntitySpawnPacket::SpawnExperienceOrb(AddExperienceOrb { + entity_id: VarInt(this_id.to_network_id()), + position: self.new_position, + count: 0, // TODO + })) + } + EntityMeta::Player(_) => Some(EntitySpawnPacket::SpawnPlayer(AddPlayer { + entity_id: VarInt(this_id.to_network_id()), + player_uuid: self.uuid, + position: self.new_position, + yaw: ByteAngle::from_degrees(self.yaw), + pitch: ByteAngle::from_degrees(self.pitch), + })), + _ => Some(EntitySpawnPacket::SpawnEntity(AddEntity { + entity_id: VarInt(this_id.to_network_id()), + object_uuid: self.uuid, + typ: VarInt(self.typ() as i32), + position: self.new_position, + pitch: ByteAngle::from_degrees(self.pitch), + yaw: ByteAngle::from_degrees(self.yaw), + head_yaw: ByteAngle::from_degrees(self.head_yaw), + data: VarInt(1), // TODO + velocity: velocity_to_packet_units(self.velocity), + })), + } + } } pub(crate) fn velocity_to_packet_units(vel: Vec3) -> Vec3 {