1use std::borrow::Cow;
2use std::collections::BTreeSet;
3use std::fmt;
4use std::net::IpAddr;
5use std::time::Instant;
6
7use bevy_app::prelude::*;
8use bevy_ecs::prelude::*;
9use bevy_ecs::query::QueryData;
10use bevy_ecs::world::Command;
11use byteorder::{NativeEndian, ReadBytesExt};
12use bytes::{Bytes, BytesMut};
13use derive_more::{Deref, DerefMut, From, Into};
14use tracing::warn;
15use uuid::Uuid;
16use valence_entity::attributes::{EntityAttributes, TrackedEntityAttributes};
17use valence_entity::living::Health;
18use valence_entity::player::{Food, PlayerEntityBundle, Saturation};
19use valence_entity::query::EntityInitQuery;
20use valence_entity::tracked_data::TrackedData;
21use valence_entity::{
22 ClearEntityChangesSet, EntityId, EntityStatus, OldPosition, Position, Velocity,
23};
24use valence_math::{DVec3, Vec3};
25use valence_protocol::encode::{PacketEncoder, WritePacket};
26use valence_protocol::packets::play::chunk_biome_data_s2c::ChunkBiome;
27use valence_protocol::packets::play::game_state_change_s2c::GameEventKind;
28use valence_protocol::packets::play::particle_s2c::Particle;
29use valence_protocol::packets::play::{
30 ChunkBiomeDataS2c, ChunkLoadDistanceS2c, ChunkRenderDistanceCenterS2c, DeathMessageS2c,
31 DisconnectS2c, EntitiesDestroyS2c, EntityAttributesS2c, EntityStatusS2c,
32 EntityTrackerUpdateS2c, EntityVelocityUpdateS2c, GameStateChangeS2c, HealthUpdateS2c,
33 ParticleS2c, PlaySoundS2c, UnloadChunkS2c,
34};
35use valence_protocol::profile::Property;
36use valence_protocol::sound::{Sound, SoundCategory, SoundId};
37use valence_protocol::text::{IntoText, Text};
38use valence_protocol::var_int::VarInt;
39use valence_protocol::{BlockPos, ChunkPos, Encode, GameMode, Packet};
40use valence_registry::RegistrySet;
41use valence_server_common::{Despawned, UniqueId};
42
43use crate::layer::{ChunkLayer, EntityLayer, UpdateLayersPostClientSet, UpdateLayersPreClientSet};
44use crate::ChunkView;
45
46pub struct ClientPlugin;
47
48#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
52pub struct FlushPacketsSet;
53
54#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
58pub struct SpawnClientsSet;
59
60#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
63pub struct UpdateClientsSet;
64
65impl Plugin for ClientPlugin {
66 fn build(&self, app: &mut App) {
67 app.add_systems(
68 PostUpdate,
69 (
70 (
71 crate::spawn::initial_join.after(RegistrySet),
72 update_chunk_load_dist,
73 handle_layer_messages.after(update_chunk_load_dist),
74 update_view_and_layers
75 .after(crate::spawn::initial_join)
76 .after(handle_layer_messages),
77 cleanup_chunks_after_client_despawn.after(update_view_and_layers),
78 crate::spawn::update_respawn_position.after(update_view_and_layers),
79 crate::spawn::respawn.after(crate::spawn::update_respawn_position),
80 update_old_view_dist.after(update_view_and_layers),
81 update_game_mode,
82 update_food_saturation_health,
83 update_tracked_data,
84 init_tracked_data,
85 update_tracked_attributes,
86 init_tracked_attributes,
87 )
88 .in_set(UpdateClientsSet),
89 flush_packets.in_set(FlushPacketsSet),
90 ),
91 )
92 .configure_sets(PreUpdate, SpawnClientsSet)
93 .configure_sets(
94 PostUpdate,
95 (
96 UpdateClientsSet
97 .after(UpdateLayersPreClientSet)
98 .before(UpdateLayersPostClientSet)
99 .before(FlushPacketsSet),
100 ClearEntityChangesSet.after(UpdateClientsSet),
101 FlushPacketsSet,
102 ),
103 )
104 .add_event::<LoadEntityForClientEvent>()
105 .add_event::<UnloadEntityForClientEvent>();
106 }
107}
108
109#[derive(Bundle)]
112pub struct ClientBundle {
113 pub marker: ClientMarker,
114 pub client: Client,
115 pub settings: crate::client_settings::ClientSettings,
116 pub entity_remove_buf: EntityRemoveBuf,
117 pub username: Username,
118 pub ip: Ip,
119 pub properties: Properties,
120 pub respawn_pos: crate::spawn::RespawnPosition,
121 pub op_level: crate::op_level::OpLevel,
122 pub action_sequence: crate::action::ActionSequence,
123 pub view_distance: ViewDistance,
124 pub old_view_distance: OldViewDistance,
125 pub visible_chunk_layer: VisibleChunkLayer,
126 pub old_visible_chunk_layer: OldVisibleChunkLayer,
127 pub visible_entity_layers: VisibleEntityLayers,
128 pub old_visible_entity_layers: OldVisibleEntityLayers,
129 pub keepalive_state: crate::keepalive::KeepaliveState,
130 pub ping: crate::keepalive::Ping,
131 pub teleport_state: crate::teleport::TeleportState,
132 pub game_mode: GameMode,
133 pub prev_game_mode: crate::spawn::PrevGameMode,
134 pub death_location: crate::spawn::DeathLocation,
135 pub is_hardcore: crate::spawn::IsHardcore,
136 pub hashed_seed: crate::spawn::HashedSeed,
137 pub reduced_debug_info: crate::spawn::ReducedDebugInfo,
138 pub has_respawn_screen: crate::spawn::HasRespawnScreen,
139 pub is_debug: crate::spawn::IsDebug,
140 pub is_flat: crate::spawn::IsFlat,
141 pub portal_cooldown: crate::spawn::PortalCooldown,
142 pub flying_speed: crate::abilities::FlyingSpeed,
143 pub fov_modifier: crate::abilities::FovModifier,
144 pub player_abilities_flags: crate::abilities::PlayerAbilitiesFlags,
145 pub player: PlayerEntityBundle,
146}
147
148impl ClientBundle {
149 pub fn new(args: ClientBundleArgs) -> Self {
150 Self {
151 marker: ClientMarker,
152 client: Client {
153 conn: args.conn,
154 enc: args.enc,
155 },
156 settings: Default::default(),
157 entity_remove_buf: Default::default(),
158 username: Username(args.username),
159 ip: Ip(args.ip),
160 properties: Properties(args.properties),
161 respawn_pos: Default::default(),
162 op_level: Default::default(),
163 action_sequence: Default::default(),
164 view_distance: Default::default(),
165 old_view_distance: OldViewDistance(2),
166 visible_chunk_layer: Default::default(),
167 old_visible_chunk_layer: OldVisibleChunkLayer(Entity::PLACEHOLDER),
168 visible_entity_layers: Default::default(),
169 old_visible_entity_layers: OldVisibleEntityLayers(BTreeSet::new()),
170 keepalive_state: crate::keepalive::KeepaliveState::new(),
171 ping: Default::default(),
172 teleport_state: crate::teleport::TeleportState::new(),
173 game_mode: GameMode::default(),
174 prev_game_mode: Default::default(),
175 death_location: Default::default(),
176 is_hardcore: Default::default(),
177 is_flat: Default::default(),
178 has_respawn_screen: Default::default(),
179 hashed_seed: Default::default(),
180 reduced_debug_info: Default::default(),
181 is_debug: Default::default(),
182 portal_cooldown: Default::default(),
183 flying_speed: Default::default(),
184 fov_modifier: Default::default(),
185 player_abilities_flags: Default::default(),
186 player: PlayerEntityBundle {
187 uuid: UniqueId(args.uuid),
188 ..Default::default()
189 },
190 }
191 }
192}
193
194pub struct ClientBundleArgs {
196 pub username: String,
198 pub uuid: Uuid,
200 pub ip: IpAddr,
202 pub properties: Vec<Property>,
204 pub conn: Box<dyn ClientConnection>,
206 pub enc: PacketEncoder,
208}
209
210#[derive(Component, Copy, Clone)]
213pub struct ClientMarker;
214
215#[derive(Component)]
221pub struct Client {
222 conn: Box<dyn ClientConnection>,
223 pub(crate) enc: PacketEncoder,
224}
225
226pub trait ClientConnection: Send + Sync + 'static {
229 fn try_send(&mut self, bytes: BytesMut) -> anyhow::Result<()>;
232 fn try_recv(&mut self) -> anyhow::Result<Option<ReceivedPacket>>;
235 fn len(&self) -> usize;
238
239 fn is_empty(&self) -> bool {
240 self.len() == 0
241 }
242}
243
244#[derive(Clone, Debug)]
245pub struct ReceivedPacket {
246 pub timestamp: Instant,
249 pub id: i32,
251 pub body: Bytes,
253}
254
255impl Drop for Client {
256 fn drop(&mut self) {
257 _ = self.flush_packets();
258 }
259}
260
261impl WritePacket for Client {
264 fn write_packet_fallible<P>(&mut self, packet: &P) -> anyhow::Result<()>
265 where
266 P: Packet + Encode,
267 {
268 self.enc.write_packet_fallible(packet)
269 }
270
271 fn write_packet_bytes(&mut self, bytes: &[u8]) {
272 self.enc.write_packet_bytes(bytes)
273 }
274}
275
276impl Client {
277 pub fn connection(&self) -> &dyn ClientConnection {
278 self.conn.as_ref()
279 }
280
281 pub fn connection_mut(&mut self) -> &mut dyn ClientConnection {
282 self.conn.as_mut()
283 }
284
285 pub fn flush_packets(&mut self) -> anyhow::Result<()> {
293 let bytes = self.enc.take();
294 if !bytes.is_empty() {
295 self.conn.try_send(bytes)
296 } else {
297 Ok(())
298 }
299 }
300
301 pub fn kill<'a, M: IntoText<'a>>(&mut self, message: M) {
304 self.write_packet(&DeathMessageS2c {
305 player_id: VarInt(0),
306 message: message.into_cow_text(),
307 });
308 }
309
310 pub fn win_game(&mut self, show_credits: bool) {
312 self.write_packet(&GameStateChangeS2c {
313 kind: GameEventKind::WinGame,
314 value: if show_credits { 1.0 } else { 0.0 },
315 });
316 }
317
318 pub fn play_particle<P, O>(
320 &mut self,
321 particle: &Particle,
322 long_distance: bool,
323 position: P,
324 offset: O,
325 max_speed: f32,
326 count: i32,
327 ) where
328 P: Into<DVec3>,
329 O: Into<Vec3>,
330 {
331 self.write_packet(&ParticleS2c {
332 particle: Cow::Borrowed(particle),
333 long_distance,
334 position: position.into(),
335 offset: offset.into(),
336 max_speed,
337 count,
338 })
339 }
340
341 pub fn play_sound<P: Into<DVec3>>(
343 &mut self,
344 sound: Sound,
345 category: SoundCategory,
346 position: P,
347 volume: f32,
348 pitch: f32,
349 ) {
350 let position = position.into();
351
352 self.write_packet(&PlaySoundS2c {
353 id: SoundId::Direct {
354 id: sound.to_ident().into(),
355 range: None,
356 },
357 category,
358 position: (position * 8.0).as_ivec3(),
359 volume,
360 pitch,
361 seed: rand::random(),
362 });
363 }
364
365 pub fn set_velocity<V: Into<Vec3>>(&mut self, velocity: V) {
367 self.write_packet(&EntityVelocityUpdateS2c {
368 entity_id: VarInt(0),
369 velocity: Velocity(velocity.into()).to_packet_units(),
370 });
371 }
372
373 pub fn trigger_status(&mut self, status: EntityStatus) {
377 self.write_packet(&EntityStatusS2c {
378 entity_id: 0,
379 entity_status: status as u8,
380 });
381 }
382}
383
384#[derive(Clone, PartialEq, Debug)]
386pub struct DisconnectClient {
387 pub client: Entity,
388 pub reason: Text,
389}
390
391impl Command for DisconnectClient {
392 fn apply(self, world: &mut World) {
393 if let Some(mut entity) = world.get_entity_mut(self.client) {
394 if let Some(mut client) = entity.get_mut::<Client>() {
395 client.write_packet(&DisconnectS2c {
396 reason: self.reason.into(),
397 });
398
399 entity.insert(Despawned);
402 }
403 }
404 }
405}
406
407#[derive(Component, Default, Debug)]
412pub struct EntityRemoveBuf(Vec<VarInt>);
413
414impl EntityRemoveBuf {
415 pub fn push(&mut self, entity_id: i32) {
416 debug_assert!(
417 entity_id != 0,
418 "removing entity with protocol ID 0 (which should be reserved for clients)"
419 );
420
421 self.0.push(VarInt(entity_id));
422 }
423
424 pub fn send_and_clear<W: WritePacket>(&mut self, mut w: W) {
427 if !self.0.is_empty() {
428 w.write_packet(&EntitiesDestroyS2c {
429 entity_ids: Cow::Borrowed(&self.0),
430 });
431
432 self.0.clear();
433 }
434 }
435}
436
437#[derive(Component, Clone, PartialEq, Eq, Default, Debug, Deref)]
438pub struct Username(pub String);
439
440impl fmt::Display for Username {
441 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
442 self.0.fmt(f)
443 }
444}
445
446#[derive(Component, Clone, PartialEq, Eq, Default, Debug, Deref, DerefMut, From, Into)]
448pub struct Properties(pub Vec<Property>);
449
450impl Properties {
451 pub fn textures(&self) -> Option<&Property> {
453 self.0.iter().find(|p| p.name == "textures")
454 }
455
456 pub fn textures_mut(&mut self) -> Option<&mut Property> {
458 self.0.iter_mut().find(|p| p.name == "textures")
459 }
460
461 pub fn skin(&self) -> Option<&str> {
464 self.textures().map(|p| p.value.as_str())
465 }
466
467 pub fn set_skin<Sk: Into<String>, Si: Into<String>>(&mut self, skin: Sk, signature: Si) {
475 if let Some(prop) = self.textures_mut() {
476 prop.value = skin.into();
477 prop.signature = Some(signature.into());
478 } else {
479 self.0.push(Property {
480 name: "textures".to_owned(),
481 value: skin.into(),
482 signature: Some(signature.into()),
483 });
484 }
485 }
486}
487
488#[derive(Clone, PartialEq, Eq, Debug)]
489pub struct PropertyValue {
490 pub value: String,
491 pub signature: Option<String>,
492}
493
494#[derive(Component, Clone, PartialEq, Eq, Debug, Deref)]
495pub struct Ip(pub IpAddr);
496
497#[derive(Component, Clone, PartialEq, Eq, Debug, Deref)]
498pub struct ViewDistance(u8);
499
500impl ViewDistance {
501 pub fn new(dist: u8) -> Self {
502 let mut new = Self(0);
503 new.set(dist);
504 new
505 }
506
507 pub fn get(&self) -> u8 {
508 self.0
509 }
510
511 pub fn set(&mut self, dist: u8) {
513 self.0 = dist.clamp(2, 32);
514 }
515}
516
517impl Default for ViewDistance {
518 fn default() -> Self {
519 Self(2)
520 }
521}
522
523#[derive(Component, Clone, PartialEq, Eq, Default, Debug, Deref)]
526pub struct OldViewDistance(u8);
527
528impl OldViewDistance {
529 pub fn get(&self) -> u8 {
530 self.0
531 }
532}
533
534#[derive(QueryData, Copy, Clone, Debug)]
535pub struct View {
536 pub pos: &'static Position,
537 pub view_dist: &'static ViewDistance,
538}
539
540impl ViewItem<'_> {
541 pub fn get(&self) -> ChunkView {
542 ChunkView::new(self.pos.0.into(), self.view_dist.0)
543 }
544}
545
546#[derive(QueryData, Copy, Clone, Debug)]
547pub struct OldView {
548 pub old_pos: &'static OldPosition,
549 pub old_view_dist: &'static OldViewDistance,
550}
551
552impl OldViewItem<'_> {
553 pub fn get(&self) -> ChunkView {
554 ChunkView::new(self.old_pos.get().into(), self.old_view_dist.0)
555 }
556}
557
558#[derive(Component, Copy, Clone, PartialEq, Eq, Debug, Deref, DerefMut)]
564pub struct VisibleChunkLayer(pub Entity);
565
566impl Default for VisibleChunkLayer {
567 fn default() -> Self {
568 Self(Entity::PLACEHOLDER)
569 }
570}
571
572#[derive(Component, PartialEq, Eq, Debug, Deref)]
574pub struct OldVisibleChunkLayer(Entity);
575
576impl OldVisibleChunkLayer {
577 pub fn get(&self) -> Entity {
578 self.0
579 }
580}
581
582#[derive(Component, Default, Debug)]
590pub struct VisibleEntityLayers(pub BTreeSet<Entity>);
591
592#[derive(Component, Default, Debug, Deref)]
594pub struct OldVisibleEntityLayers(BTreeSet<Entity>);
595
596impl OldVisibleEntityLayers {
597 pub fn get(&self) -> &BTreeSet<Entity> {
598 &self.0
599 }
600}
601
602pub fn despawn_disconnected_clients(
605 mut commands: Commands,
606 mut disconnected_clients: RemovedComponents<Client>,
607) {
608 for entity in disconnected_clients.read() {
609 if let Some(mut entity) = commands.get_entity(entity) {
610 entity.insert(Despawned);
611 }
612 }
613}
614
615fn update_chunk_load_dist(
616 mut clients: Query<(&mut Client, &ViewDistance, &OldViewDistance), Changed<ViewDistance>>,
617) {
618 for (mut client, dist, old_dist) in &mut clients {
619 if client.is_added() {
620 continue;
622 }
623
624 if dist.0 != old_dist.0 {
625 client.write_packet(&ChunkLoadDistanceS2c {
627 view_distance: VarInt(dist.0.into()),
628 });
629 }
630 }
631}
632
633fn handle_layer_messages(
634 mut clients: Query<(
635 Entity,
636 &EntityId,
637 &mut Client,
638 &mut EntityRemoveBuf,
639 OldView,
640 &OldVisibleChunkLayer,
641 &mut VisibleEntityLayers,
642 &OldVisibleEntityLayers,
643 )>,
644 chunk_layers: Query<&ChunkLayer>,
645 entity_layers: Query<&EntityLayer>,
646 entities: Query<(EntityInitQuery, &OldPosition)>,
647) {
648 clients.par_iter_mut().for_each(
649 |(
650 self_entity,
651 self_entity_id,
652 mut client,
653 mut remove_buf,
654 old_view,
655 old_visible_chunk_layer,
656 mut visible_entity_layers,
657 old_visible_entity_layers,
658 )| {
659 let block_pos = BlockPos::from(old_view.old_pos.get());
660 let old_view = old_view.get();
661
662 fn in_radius(p0: BlockPos, p1: BlockPos, radius_squared: u32) -> bool {
663 let dist_squared =
664 (p1.x - p0.x).pow(2) + (p1.y - p0.y).pow(2) + (p1.z - p0.z).pow(2);
665
666 dist_squared as u32 <= radius_squared
667 }
668
669 if let Ok(chunk_layer) = chunk_layers.get(old_visible_chunk_layer.get()) {
671 let messages = chunk_layer.messages();
672 let bytes = messages.bytes();
673
674 for (msg, range) in messages.iter_global() {
676 match msg {
677 crate::layer::chunk::GlobalMsg::Packet => {
678 client.write_packet_bytes(&bytes[range]);
679 }
680 crate::layer::chunk::GlobalMsg::PacketExcept { except } => {
681 if self_entity != except {
682 client.write_packet_bytes(&bytes[range]);
683 }
684 }
685 }
686 }
687
688 let mut chunk_biome_buf = vec![];
689
690 messages.query_local(old_view, |msg, range| match msg {
692 crate::layer::chunk::LocalMsg::PacketAt { .. } => {
693 client.write_packet_bytes(&bytes[range]);
694 }
695 crate::layer::chunk::LocalMsg::PacketAtExcept { except, .. } => {
696 if self_entity != except {
697 client.write_packet_bytes(&bytes[range]);
698 }
699 }
700 crate::layer::chunk::LocalMsg::RadiusAt {
701 center,
702 radius_squared,
703 } => {
704 if in_radius(block_pos, center, radius_squared) {
705 client.write_packet_bytes(&bytes[range]);
706 }
707 }
708 crate::layer::chunk::LocalMsg::RadiusAtExcept {
709 center,
710 radius_squared,
711 except,
712 } => {
713 if self_entity != except && in_radius(block_pos, center, radius_squared) {
714 client.write_packet_bytes(&bytes[range]);
715 }
716 }
717 crate::layer::chunk::LocalMsg::ChangeBiome { pos } => {
718 chunk_biome_buf.push(ChunkBiome {
719 pos,
720 data: &bytes[range],
721 });
722 }
723 crate::layer::chunk::LocalMsg::ChangeChunkState { pos } => {
724 match &bytes[range] {
725 [ChunkLayer::LOAD, .., ChunkLayer::UNLOAD] => {
726 debug_assert!(chunk_layer.chunk(pos).is_none());
729 }
730 [.., ChunkLayer::LOAD | ChunkLayer::OVERWRITE] => {
731 let chunk = chunk_layer.chunk(pos).expect("chunk must exist");
733 chunk.write_init_packets(&mut *client, pos, chunk_layer.info());
734 chunk.inc_viewer_count();
735 }
736 [.., ChunkLayer::UNLOAD] => {
737 client.write_packet(&UnloadChunkS2c { pos });
739 debug_assert!(chunk_layer.chunk(pos).is_none());
740 }
741 _ => unreachable!("invalid message data while changing chunk state"),
742 }
743 }
744 });
745
746 if !chunk_biome_buf.is_empty() {
747 client.write_packet(&ChunkBiomeDataS2c {
748 chunks: chunk_biome_buf.into(),
749 });
750 }
751 }
752
753 for &layer_id in &old_visible_entity_layers.0 {
755 if let Ok(layer) = entity_layers.get(layer_id) {
756 let messages = layer.messages();
757 let bytes = messages.bytes();
758
759 for (msg, range) in messages.iter_global() {
761 match msg {
762 crate::layer::entity::GlobalMsg::Packet => {
763 client.write_packet_bytes(&bytes[range]);
764 }
765 crate::layer::entity::GlobalMsg::PacketExcept { except } => {
766 if self_entity != except {
767 client.write_packet_bytes(&bytes[range]);
768 }
769 }
770 crate::layer::entity::GlobalMsg::DespawnLayer => {
771 visible_entity_layers.0.remove(&layer_id);
775 }
776 }
777 }
778
779 messages.query_local(old_view, |msg, range| match msg {
781 crate::layer::entity::LocalMsg::DespawnEntity { dest_layer, .. } => {
782 if !old_visible_entity_layers.0.contains(&dest_layer) {
783 let mut bytes = &bytes[range];
784
785 while let Ok(id) = bytes.read_i32::<NativeEndian>() {
786 if self_entity_id.get() != id {
787 remove_buf.push(id);
788 }
789 }
790 }
791 }
792 crate::layer::entity::LocalMsg::DespawnEntityTransition {
793 dest_pos,
794 ..
795 } => {
796 if !old_view.contains(dest_pos) {
797 let mut bytes = &bytes[range];
798
799 while let Ok(id) = bytes.read_i32::<NativeEndian>() {
800 if self_entity_id.get() != id {
801 remove_buf.push(id);
802 }
803 }
804 }
805 }
806 crate::layer::entity::LocalMsg::SpawnEntity { src_layer, .. } => {
807 if !old_visible_entity_layers.0.contains(&src_layer) {
808 let mut bytes = &bytes[range];
809
810 while let Ok(u64) = bytes.read_u64::<NativeEndian>() {
811 let entity = Entity::from_bits(u64);
812
813 if self_entity != entity {
814 if let Ok((init, old_pos)) = entities.get(entity) {
815 remove_buf.send_and_clear(&mut *client);
816
817 init.write_init_packets(old_pos.get(), &mut *client);
821 }
822 }
823 }
824 }
825 }
826 crate::layer::entity::LocalMsg::SpawnEntityTransition {
827 src_pos, ..
828 } => {
829 if !old_view.contains(src_pos) {
830 let mut bytes = &bytes[range];
831
832 while let Ok(u64) = bytes.read_u64::<NativeEndian>() {
833 let entity = Entity::from_bits(u64);
834
835 if self_entity != entity {
836 if let Ok((init, old_pos)) = entities.get(entity) {
837 remove_buf.send_and_clear(&mut *client);
838
839 init.write_init_packets(old_pos.get(), &mut *client);
843 }
844 }
845 }
846 }
847 }
848 crate::layer::entity::LocalMsg::PacketAt { .. } => {
849 client.write_packet_bytes(&bytes[range]);
850 }
851 crate::layer::entity::LocalMsg::PacketAtExcept { except, .. } => {
852 if self_entity != except {
853 client.write_packet_bytes(&bytes[range]);
854 }
855 }
856 crate::layer::entity::LocalMsg::RadiusAt {
857 center,
858 radius_squared,
859 } => {
860 if in_radius(block_pos, center, radius_squared) {
861 client.write_packet_bytes(&bytes[range]);
862 }
863 }
864 crate::layer::entity::LocalMsg::RadiusAtExcept {
865 center,
866 radius_squared,
867 except,
868 } => {
869 if self_entity != except && in_radius(block_pos, center, radius_squared)
870 {
871 client.write_packet_bytes(&bytes[range]);
872 }
873 }
874 });
875
876 remove_buf.send_and_clear(&mut *client);
877 }
878 }
879 },
880 );
881}
882
883#[derive(Debug, Clone, PartialEq, Event)]
886pub struct UnloadEntityForClientEvent {
887 pub client: Entity,
889 pub entity_unloaded: Entity,
891}
892
893#[derive(Debug, Clone, PartialEq, Event)]
896pub struct LoadEntityForClientEvent {
897 pub client: Entity,
899 pub entity_loaded: Entity,
901}
902
903pub(crate) fn update_view_and_layers(
904 mut clients: Query<
905 (
906 Entity,
907 &mut Client,
908 &mut EntityRemoveBuf,
909 &VisibleChunkLayer,
910 &mut OldVisibleChunkLayer,
911 Ref<VisibleEntityLayers>,
912 &mut OldVisibleEntityLayers,
913 &Position,
914 &OldPosition,
915 &ViewDistance,
916 &OldViewDistance,
917 ),
918 Or<(
919 Changed<VisibleChunkLayer>,
920 Changed<VisibleEntityLayers>,
921 Changed<Position>,
922 Changed<ViewDistance>,
923 )>,
924 >,
925 chunk_layers: Query<&ChunkLayer>,
926 entity_layers: Query<&EntityLayer>,
927 entity_ids: Query<&EntityId>,
928 entity_init: Query<(EntityInitQuery, &Position)>,
929
930 mut unload_entity_writer: EventWriter<UnloadEntityForClientEvent>,
931 mut load_entity_writer: EventWriter<LoadEntityForClientEvent>,
932) {
933 enum ChannelEvent {
935 UnloadEntity(UnloadEntityForClientEvent),
936 LoadEntity(LoadEntityForClientEvent),
937 }
938
939 let (tx, rx) = std::sync::mpsc::channel();
940
941 (clients).par_iter_mut().for_each(
942 |(
943 self_entity,
944 mut client,
945 mut remove_buf,
946 chunk_layer,
947 mut old_chunk_layer,
948 visible_entity_layers,
949 mut old_visible_entity_layers,
950 pos,
951 old_pos,
952 view_dist,
953 old_view_dist,
954 )| {
955 let view = ChunkView::new(ChunkPos::from(pos.0), view_dist.0);
956 let old_view = ChunkView::new(ChunkPos::from(old_pos.get()), old_view_dist.0);
957
958 if old_view.pos != view.pos {
961 client.write_packet(&ChunkRenderDistanceCenterS2c {
962 chunk_x: VarInt(view.pos.x),
963 chunk_z: VarInt(view.pos.z),
964 });
965 }
966
967 if old_chunk_layer.0 != chunk_layer.0 {
969 if let Ok(layer) = chunk_layers.get(old_chunk_layer.0) {
972 for pos in old_view.iter() {
973 if let Some(chunk) = layer.chunk(pos) {
974 client.write_packet(&UnloadChunkS2c { pos });
975 chunk.dec_viewer_count();
976 }
977 }
978 }
979
980 if let Ok(layer) = chunk_layers.get(chunk_layer.0) {
982 for pos in view.iter() {
983 if let Some(chunk) = layer.chunk(pos) {
984 chunk.write_init_packets(&mut *client, pos, layer.info());
985 chunk.inc_viewer_count();
986 }
987 }
988 }
989
990 for &layer in &old_visible_entity_layers.0 {
993 if let Ok(layer) = entity_layers.get(layer) {
994 for pos in old_view.iter() {
995 for entity in layer.entities_at(pos) {
996 if self_entity != entity {
997 if let Ok(id) = entity_ids.get(entity) {
998 tx.send(ChannelEvent::UnloadEntity(
999 UnloadEntityForClientEvent {
1000 client: self_entity,
1001 entity_unloaded: entity,
1002 },
1003 ))
1004 .unwrap();
1005
1006 remove_buf.push(id.get());
1007 }
1008 }
1009 }
1010 }
1011 }
1012 }
1013
1014 remove_buf.send_and_clear(&mut *client);
1015
1016 for &layer in &visible_entity_layers.0 {
1018 if let Ok(layer) = entity_layers.get(layer) {
1019 for pos in view.iter() {
1020 for entity in layer.entities_at(pos) {
1021 if self_entity != entity {
1022 if let Ok((init, pos)) = entity_init.get(entity) {
1023 tx.send(ChannelEvent::LoadEntity(
1024 LoadEntityForClientEvent {
1025 client: self_entity,
1026 entity_loaded: entity,
1027 },
1028 ))
1029 .unwrap();
1030
1031 init.write_init_packets(pos.get(), &mut *client);
1032 }
1033 }
1034 }
1035 }
1036 }
1037 }
1038 } else {
1039 if visible_entity_layers.is_changed() {
1041 for &layer in old_visible_entity_layers
1043 .0
1044 .difference(&visible_entity_layers.0)
1045 {
1046 if let Ok(layer) = entity_layers.get(layer) {
1047 for pos in old_view.iter() {
1048 for entity in layer.entities_at(pos) {
1049 if self_entity != entity {
1050 if let Ok(id) = entity_ids.get(entity) {
1051 tx.send(ChannelEvent::UnloadEntity(
1052 UnloadEntityForClientEvent {
1053 client: self_entity,
1054 entity_unloaded: entity,
1055 },
1056 ))
1057 .unwrap();
1058
1059 remove_buf.push(id.get());
1060 }
1061 }
1062 }
1063 }
1064 }
1065 }
1066
1067 remove_buf.send_and_clear(&mut *client);
1068
1069 for &layer in visible_entity_layers
1071 .0
1072 .difference(&old_visible_entity_layers.0)
1073 {
1074 if let Ok(layer) = entity_layers.get(layer) {
1075 for pos in old_view.iter() {
1076 for entity in layer.entities_at(pos) {
1077 if self_entity != entity {
1078 if let Ok((init, pos)) = entity_init.get(entity) {
1079 tx.send(ChannelEvent::LoadEntity(
1080 LoadEntityForClientEvent {
1081 client: self_entity,
1082 entity_loaded: entity,
1083 },
1084 ))
1085 .unwrap();
1086
1087 init.write_init_packets(pos.get(), &mut *client);
1088 }
1089 }
1090 }
1091 }
1092 }
1093 }
1094 }
1095
1096 if old_view != view {
1098 if let Ok(layer) = chunk_layers.get(chunk_layer.0) {
1104 for pos in old_view.diff(view) {
1105 if let Some(chunk) = layer.chunk(pos) {
1106 client.write_packet(&UnloadChunkS2c { pos });
1107 chunk.dec_viewer_count();
1108 }
1109 }
1110 }
1111
1112 if let Ok(layer) = chunk_layers.get(chunk_layer.0) {
1114 for pos in view.diff(old_view) {
1115 if let Some(chunk) = layer.chunk(pos) {
1116 chunk.write_init_packets(&mut *client, pos, layer.info());
1117 chunk.inc_viewer_count();
1118 }
1119 }
1120 }
1121
1122 for &layer in &visible_entity_layers.0 {
1124 if let Ok(layer) = entity_layers.get(layer) {
1125 for pos in old_view.diff(view) {
1126 for entity in layer.entities_at(pos) {
1127 if self_entity != entity {
1128 if let Ok(id) = entity_ids.get(entity) {
1129 tx.send(ChannelEvent::UnloadEntity(
1130 UnloadEntityForClientEvent {
1131 client: self_entity,
1132 entity_unloaded: entity,
1133 },
1134 ))
1135 .unwrap();
1136
1137 remove_buf.push(id.get());
1138 }
1139 }
1140 }
1141 }
1142 }
1143 }
1144
1145 for &layer in &visible_entity_layers.0 {
1147 if let Ok(layer) = entity_layers.get(layer) {
1148 for pos in view.diff(old_view) {
1149 for entity in layer.entities_at(pos) {
1150 if self_entity != entity {
1151 if let Ok((init, pos)) = entity_init.get(entity) {
1152 tx.send(ChannelEvent::LoadEntity(
1153 LoadEntityForClientEvent {
1154 client: self_entity,
1155 entity_loaded: entity,
1156 },
1157 ))
1158 .unwrap();
1159
1160 init.write_init_packets(pos.get(), &mut *client);
1161 }
1162 }
1163 }
1164 }
1165 }
1166 }
1167 }
1168 }
1169
1170 old_chunk_layer.0 = chunk_layer.0;
1173
1174 if visible_entity_layers.is_changed() {
1175 old_visible_entity_layers
1176 .0
1177 .clone_from(&visible_entity_layers.0);
1178 }
1179 },
1180 );
1181
1182 for event in rx.try_iter() {
1184 match event {
1185 ChannelEvent::UnloadEntity(event) => {
1186 unload_entity_writer.send(event);
1187 }
1188 ChannelEvent::LoadEntity(event) => {
1189 load_entity_writer.send(event);
1190 }
1191 };
1192 }
1193}
1194
1195pub(crate) fn update_game_mode(mut clients: Query<(&mut Client, &GameMode), Changed<GameMode>>) {
1196 for (mut client, game_mode) in &mut clients {
1197 if client.is_added() {
1198 continue;
1200 }
1201
1202 client.write_packet(&GameStateChangeS2c {
1203 kind: GameEventKind::ChangeGameMode,
1204 value: *game_mode as i32 as f32,
1205 })
1206 }
1207}
1208
1209fn update_food_saturation_health(
1210 mut clients: Query<
1211 (&mut Client, &Food, &Saturation, &Health),
1212 Or<(Changed<Food>, Changed<Saturation>, Changed<Health>)>,
1213 >,
1214) {
1215 for (mut client, food, saturation, health) in &mut clients {
1216 client.write_packet(&HealthUpdateS2c {
1217 health: health.0,
1218 food: VarInt(food.0),
1219 food_saturation: saturation.0,
1220 });
1221 }
1222}
1223
1224fn update_old_view_dist(
1225 mut clients: Query<(&mut OldViewDistance, &ViewDistance), Changed<ViewDistance>>,
1226) {
1227 for (mut old_dist, dist) in &mut clients {
1228 old_dist.0 = dist.0;
1229 }
1230}
1231
1232fn flush_packets(
1233 mut clients: Query<(Entity, &mut Client), Changed<Client>>,
1234 mut commands: Commands,
1235) {
1236 for (entity, mut client) in &mut clients {
1237 if let Err(e) = client.flush_packets() {
1238 warn!("Failed to flush packet queue for client {entity:?}: {e:#}.");
1239 commands.entity(entity).remove::<Client>();
1240 }
1241 }
1242}
1243
1244fn init_tracked_data(mut clients: Query<(&mut Client, &TrackedData), Added<TrackedData>>) {
1245 for (mut client, tracked_data) in &mut clients {
1246 if let Some(init_data) = tracked_data.init_data() {
1247 client.write_packet(&EntityTrackerUpdateS2c {
1248 entity_id: VarInt(0),
1249 tracked_values: init_data.into(),
1250 });
1251 }
1252 }
1253}
1254
1255fn update_tracked_data(mut clients: Query<(&mut Client, &TrackedData)>) {
1256 for (mut client, tracked_data) in &mut clients {
1257 if let Some(update_data) = tracked_data.update_data() {
1258 client.write_packet(&EntityTrackerUpdateS2c {
1259 entity_id: VarInt(0),
1260 tracked_values: update_data.into(),
1261 });
1262 }
1263 }
1264}
1265
1266fn init_tracked_attributes(
1267 mut clients: Query<(&mut Client, &EntityAttributes), Added<EntityAttributes>>,
1268) {
1269 for (mut client, attributes) in &mut clients {
1270 client.write_packet(&EntityAttributesS2c {
1271 entity_id: VarInt(0),
1272 properties: attributes.to_properties(),
1273 });
1274 }
1275}
1276
1277fn update_tracked_attributes(mut clients: Query<(&mut Client, &TrackedEntityAttributes)>) {
1278 for (mut client, attributes) in &mut clients {
1279 let properties = attributes.get_properties();
1280 if !properties.is_empty() {
1281 client.write_packet(&EntityAttributesS2c {
1282 entity_id: VarInt(0),
1283 properties,
1284 });
1285 }
1286 }
1287}
1288
1289fn cleanup_chunks_after_client_despawn(
1291 mut clients: Query<(View, &VisibleChunkLayer), (With<ClientMarker>, With<Despawned>)>,
1292 chunk_layers: Query<&ChunkLayer>,
1293) {
1294 for (view, layer) in &mut clients {
1295 if let Ok(layer) = chunk_layers.get(layer.0) {
1296 for pos in view.get().iter() {
1297 if let Some(chunk) = layer.chunk(pos) {
1298 chunk.dec_viewer_count();
1299 }
1300 }
1301 }
1302 }
1303}