valence_server/layer/
entity.rs

1use std::collections::hash_map::Entry;
2use std::collections::BTreeSet;
3
4use bevy_app::prelude::*;
5use bevy_ecs::prelude::*;
6use rustc_hash::FxHashMap;
7use valence_entity::query::UpdateEntityQuery;
8use valence_entity::{EntityId, EntityLayerId, OldEntityLayerId, OldPosition, Position};
9use valence_protocol::encode::{PacketWriter, WritePacket};
10use valence_protocol::{BlockPos, ChunkPos, CompressionThreshold, Encode, Packet};
11use valence_server_common::{Despawned, Server};
12
13use super::bvh::GetChunkPos;
14use super::message::Messages;
15use super::{Layer, UpdateLayersPostClientSet, UpdateLayersPreClientSet};
16use crate::client::Client;
17
18/// A [`Component`] containing Minecraft entities.
19#[derive(Component, Debug)]
20pub struct EntityLayer {
21    messages: EntityLayerMessages,
22    entities: FxHashMap<ChunkPos, BTreeSet<Entity>>,
23    threshold: CompressionThreshold,
24}
25
26type EntityLayerMessages = Messages<GlobalMsg, LocalMsg>;
27
28#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
29pub(crate) enum GlobalMsg {
30    /// Send packet data to all clients viewing the layer. Message data is
31    /// serialized packet data.
32    Packet,
33    /// Send packet data to all clients viewing layer, except the client
34    /// identified by `except`.
35    PacketExcept { except: Entity },
36    /// This layer was despawned and should be removed from the set of visible
37    /// entity layers. Message data is empty.
38    DespawnLayer,
39}
40
41#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
42// NOTE: Variant order is significant. Despawns should be ordered before spawns.
43pub(crate) enum LocalMsg {
44    /// Despawn entities if the client is not already viewing `dest_layer`.
45    /// Message data is the serialized form of `EntityId`.
46    DespawnEntity { pos: ChunkPos, dest_layer: Entity },
47    /// Despawn entities if the client is not in view of `dest_pos`. Message
48    /// data is the serialized form of `EntityId`.
49    DespawnEntityTransition { pos: ChunkPos, dest_pos: ChunkPos },
50    /// Spawn entities if the client is not already viewing `src_layer`. Message
51    /// data is the serialized form of [`Entity`].
52    SpawnEntity { pos: ChunkPos, src_layer: Entity },
53    /// Spawn entities if the client is not in view of `src_pos`. Message data
54    /// is the serialized form of [`Entity`].
55    SpawnEntityTransition { pos: ChunkPos, src_pos: ChunkPos },
56    /// Send packet data to all clients viewing the layer in view of `pos`.
57    /// Message data is serialized packet data.
58    PacketAt { pos: ChunkPos },
59    /// Send packet data to all clients viewing the layer in view of `pos`,
60    /// except the client identified by `except`. Message data is serialized
61    /// packet data.
62    PacketAtExcept { pos: ChunkPos, except: Entity },
63    /// Send packet data to all clients in a sphere.
64    RadiusAt {
65        center: BlockPos,
66        radius_squared: u32,
67    },
68    /// Send packet data to all clients in a sphere, except the client `except`.
69    RadiusAtExcept {
70        center: BlockPos,
71        radius_squared: u32,
72        except: Entity,
73    },
74}
75
76impl GetChunkPos for LocalMsg {
77    fn chunk_pos(&self) -> ChunkPos {
78        match *self {
79            LocalMsg::PacketAt { pos } => pos,
80            LocalMsg::PacketAtExcept { pos, .. } => pos,
81            LocalMsg::RadiusAt { center, .. } => center.into(),
82            LocalMsg::RadiusAtExcept { center, .. } => center.into(),
83            LocalMsg::SpawnEntity { pos, .. } => pos,
84            LocalMsg::SpawnEntityTransition { pos, .. } => pos,
85            LocalMsg::DespawnEntity { pos, .. } => pos,
86            LocalMsg::DespawnEntityTransition { pos, .. } => pos,
87        }
88    }
89}
90
91impl EntityLayer {
92    /// Creates a new entity layer.
93    pub fn new(server: &Server) -> Self {
94        Self {
95            messages: Messages::new(),
96            entities: Default::default(),
97            threshold: server.compression_threshold(),
98        }
99    }
100
101    /// Returns an iterator over all entities contained within the given chunk
102    /// position in this layer.
103    pub fn entities_at<P: Into<ChunkPos>>(
104        &self,
105        pos: P,
106    ) -> impl Iterator<Item = Entity> + Clone + '_ {
107        self.entities
108            .get(&pos.into())
109            .into_iter()
110            .flat_map(|entities| entities.iter().copied())
111    }
112
113    pub(crate) fn messages(&self) -> &EntityLayerMessages {
114        &self.messages
115    }
116}
117
118impl Layer for EntityLayer {
119    type ExceptWriter<'a> = ExceptWriter<'a>;
120
121    type ViewWriter<'a> = ViewWriter<'a>;
122
123    type ViewExceptWriter<'a> = ViewExceptWriter<'a>;
124
125    type RadiusWriter<'a> = RadiusWriter<'a>;
126
127    type RadiusExceptWriter<'a> = RadiusExceptWriter<'a>;
128
129    fn except_writer(&mut self, except: Entity) -> Self::ExceptWriter<'_> {
130        ExceptWriter {
131            layer: self,
132            except,
133        }
134    }
135
136    fn view_writer(&mut self, pos: impl Into<ChunkPos>) -> Self::ViewWriter<'_> {
137        ViewWriter {
138            layer: self,
139            pos: pos.into(),
140        }
141    }
142
143    fn view_except_writer(
144        &mut self,
145        pos: impl Into<ChunkPos>,
146        except: Entity,
147    ) -> Self::ViewExceptWriter<'_> {
148        ViewExceptWriter {
149            layer: self,
150            pos: pos.into(),
151            except,
152        }
153    }
154
155    fn radius_writer(
156        &mut self,
157        center: impl Into<BlockPos>,
158        radius: u32,
159    ) -> Self::RadiusWriter<'_> {
160        RadiusWriter {
161            layer: self,
162            center: center.into(),
163            radius_squared: radius.saturating_mul(radius),
164        }
165    }
166
167    fn radius_except_writer(
168        &mut self,
169        center: impl Into<BlockPos>,
170        radius: u32,
171        except: Entity,
172    ) -> Self::RadiusExceptWriter<'_> {
173        RadiusExceptWriter {
174            layer: self,
175            center: center.into(),
176            radius_squared: radius.saturating_mul(radius),
177            except,
178        }
179    }
180}
181
182impl WritePacket for EntityLayer {
183    fn write_packet_fallible<P>(&mut self, packet: &P) -> anyhow::Result<()>
184    where
185        P: Packet + Encode,
186    {
187        self.messages.send_global(GlobalMsg::Packet, |b| {
188            PacketWriter::new(b, self.threshold).write_packet_fallible(packet)
189        })
190    }
191
192    fn write_packet_bytes(&mut self, bytes: &[u8]) {
193        self.messages
194            .send_global_infallible(GlobalMsg::Packet, |b| b.extend_from_slice(bytes));
195    }
196}
197
198pub struct ExceptWriter<'a> {
199    layer: &'a mut EntityLayer,
200    except: Entity,
201}
202
203impl WritePacket for ExceptWriter<'_> {
204    fn write_packet_fallible<P>(&mut self, packet: &P) -> anyhow::Result<()>
205    where
206        P: Packet + Encode,
207    {
208        self.layer.messages.send_global(
209            GlobalMsg::PacketExcept {
210                except: self.except,
211            },
212            |b| PacketWriter::new(b, self.layer.threshold).write_packet_fallible(packet),
213        )
214    }
215
216    fn write_packet_bytes(&mut self, bytes: &[u8]) {
217        self.layer.messages.send_global_infallible(
218            GlobalMsg::PacketExcept {
219                except: self.except,
220            },
221            |b| b.extend_from_slice(bytes),
222        )
223    }
224}
225
226pub struct ViewWriter<'a> {
227    layer: &'a mut EntityLayer,
228    pos: ChunkPos,
229}
230
231impl WritePacket for ViewWriter<'_> {
232    fn write_packet_fallible<P>(&mut self, packet: &P) -> anyhow::Result<()>
233    where
234        P: Packet + Encode,
235    {
236        self.layer
237            .messages
238            .send_local(LocalMsg::PacketAt { pos: self.pos }, |b| {
239                PacketWriter::new(b, self.layer.threshold).write_packet_fallible(packet)
240            })
241    }
242
243    fn write_packet_bytes(&mut self, bytes: &[u8]) {
244        self.layer
245            .messages
246            .send_local_infallible(LocalMsg::PacketAt { pos: self.pos }, |b| {
247                b.extend_from_slice(bytes)
248            });
249    }
250}
251
252pub struct ViewExceptWriter<'a> {
253    layer: &'a mut EntityLayer,
254    pos: ChunkPos,
255    except: Entity,
256}
257
258impl WritePacket for ViewExceptWriter<'_> {
259    fn write_packet_fallible<P>(&mut self, packet: &P) -> anyhow::Result<()>
260    where
261        P: Packet + Encode,
262    {
263        self.layer.messages.send_local(
264            LocalMsg::PacketAtExcept {
265                pos: self.pos,
266                except: self.except,
267            },
268            |b| PacketWriter::new(b, self.layer.threshold).write_packet_fallible(packet),
269        )
270    }
271
272    fn write_packet_bytes(&mut self, bytes: &[u8]) {
273        self.layer.messages.send_local_infallible(
274            LocalMsg::PacketAtExcept {
275                pos: self.pos,
276                except: self.except,
277            },
278            |b| b.extend_from_slice(bytes),
279        );
280    }
281}
282
283pub struct RadiusWriter<'a> {
284    layer: &'a mut EntityLayer,
285    center: BlockPos,
286    radius_squared: u32,
287}
288
289impl WritePacket for RadiusWriter<'_> {
290    fn write_packet_fallible<P>(&mut self, packet: &P) -> anyhow::Result<()>
291    where
292        P: Packet + Encode,
293    {
294        self.layer.messages.send_local(
295            LocalMsg::RadiusAt {
296                center: self.center,
297                radius_squared: self.radius_squared,
298            },
299            |b| PacketWriter::new(b, self.layer.threshold).write_packet_fallible(packet),
300        )
301    }
302
303    fn write_packet_bytes(&mut self, bytes: &[u8]) {
304        self.layer.messages.send_local_infallible(
305            LocalMsg::RadiusAt {
306                center: self.center,
307                radius_squared: self.radius_squared,
308            },
309            |b| b.extend_from_slice(bytes),
310        );
311    }
312}
313
314pub struct RadiusExceptWriter<'a> {
315    layer: &'a mut EntityLayer,
316    center: BlockPos,
317    radius_squared: u32,
318    except: Entity,
319}
320
321impl WritePacket for RadiusExceptWriter<'_> {
322    fn write_packet_fallible<P>(&mut self, packet: &P) -> anyhow::Result<()>
323    where
324        P: Packet + Encode,
325    {
326        self.layer.messages.send_local(
327            LocalMsg::RadiusAtExcept {
328                center: self.center,
329                radius_squared: self.radius_squared,
330                except: self.except,
331            },
332            |b| PacketWriter::new(b, self.layer.threshold).write_packet_fallible(packet),
333        )
334    }
335
336    fn write_packet_bytes(&mut self, bytes: &[u8]) {
337        self.layer.messages.send_local_infallible(
338            LocalMsg::RadiusAtExcept {
339                center: self.center,
340                radius_squared: self.radius_squared,
341                except: self.except,
342            },
343            |b| b.extend_from_slice(bytes),
344        );
345    }
346}
347
348pub(super) fn build(app: &mut App) {
349    app.add_systems(
350        PostUpdate,
351        (
352            (
353                change_entity_positions,
354                send_entity_update_messages,
355                send_layer_despawn_messages,
356                ready_entity_layers,
357            )
358                .chain()
359                .in_set(UpdateLayersPreClientSet),
360            unready_entity_layers.in_set(UpdateLayersPostClientSet),
361        ),
362    );
363}
364
365fn change_entity_positions(
366    entities: Query<
367        (
368            Entity,
369            &EntityId,
370            &Position,
371            &OldPosition,
372            &EntityLayerId,
373            &OldEntityLayerId,
374            Has<Despawned>,
375        ),
376        Or<(Changed<Position>, Changed<EntityLayerId>, With<Despawned>)>,
377    >,
378    mut layers: Query<&mut EntityLayer>,
379) {
380    for (entity, entity_id, pos, old_pos, layer_id, old_layer_id, despawned) in &entities {
381        let chunk_pos = ChunkPos::from(pos.0);
382        let old_chunk_pos = ChunkPos::from(old_pos.get());
383
384        if despawned {
385            // Entity was deleted. Remove it from the layer.
386
387            if let Ok(old_layer) = layers.get_mut(layer_id.0) {
388                let old_layer = old_layer.into_inner();
389
390                if let Entry::Occupied(mut old_cell) = old_layer.entities.entry(old_chunk_pos) {
391                    if old_cell.get_mut().remove(&entity) {
392                        old_layer.messages.send_local_infallible(
393                            LocalMsg::DespawnEntity {
394                                pos: old_chunk_pos,
395                                dest_layer: Entity::PLACEHOLDER,
396                            },
397                            |b| b.extend_from_slice(&entity_id.get().to_ne_bytes()),
398                        );
399
400                        if old_cell.get().is_empty() {
401                            old_cell.remove();
402                        }
403                    }
404                }
405            }
406        } else if old_layer_id != layer_id {
407            // Entity changed their layer. Remove it from old layer and insert it in the new
408            // layer.
409
410            if let Ok(old_layer) = layers.get_mut(old_layer_id.get()) {
411                let old_layer = old_layer.into_inner();
412
413                if let Entry::Occupied(mut old_cell) = old_layer.entities.entry(old_chunk_pos) {
414                    if old_cell.get_mut().remove(&entity) {
415                        old_layer.messages.send_local_infallible(
416                            LocalMsg::DespawnEntity {
417                                pos: old_chunk_pos,
418                                dest_layer: layer_id.0,
419                            },
420                            |b| b.extend_from_slice(&entity_id.get().to_ne_bytes()),
421                        );
422
423                        if old_cell.get().is_empty() {
424                            old_cell.remove();
425                        }
426                    }
427                }
428            }
429
430            if let Ok(mut layer) = layers.get_mut(layer_id.0) {
431                if layer.entities.entry(chunk_pos).or_default().insert(entity) {
432                    layer.messages.send_local_infallible(
433                        LocalMsg::SpawnEntity {
434                            pos: chunk_pos,
435                            src_layer: old_layer_id.get(),
436                        },
437                        |b| b.extend_from_slice(&entity.to_bits().to_ne_bytes()),
438                    );
439                }
440            }
441        } else if chunk_pos != old_chunk_pos {
442            // Entity changed their chunk position without changing layers. Remove it from
443            // old cell and insert it in the new cell.
444
445            if let Ok(mut layer) = layers.get_mut(layer_id.0) {
446                if let Entry::Occupied(mut old_cell) = layer.entities.entry(old_chunk_pos) {
447                    if old_cell.get_mut().remove(&entity) {
448                        layer.messages.send_local_infallible(
449                            LocalMsg::DespawnEntityTransition {
450                                pos: old_chunk_pos,
451                                dest_pos: chunk_pos,
452                            },
453                            |b| b.extend_from_slice(&entity_id.get().to_ne_bytes()),
454                        );
455                    }
456                }
457
458                if layer.entities.entry(chunk_pos).or_default().insert(entity) {
459                    layer.messages.send_local_infallible(
460                        LocalMsg::SpawnEntityTransition {
461                            pos: chunk_pos,
462                            src_pos: old_chunk_pos,
463                        },
464                        |b| b.extend_from_slice(&entity.to_bits().to_ne_bytes()),
465                    );
466                }
467            }
468        }
469    }
470}
471
472fn send_entity_update_messages(
473    entities: Query<(Entity, UpdateEntityQuery, Has<Client>), Without<Despawned>>,
474    mut layers: Query<&mut EntityLayer>,
475) {
476    for layer in &mut layers {
477        let layer = layer.into_inner();
478
479        for cell in layer.entities.values_mut() {
480            for &entity in cell.iter() {
481                if let Ok((entity, update, is_client)) = entities.get(entity) {
482                    let chunk_pos = ChunkPos::from(update.pos.0);
483
484                    // Send the update packets to all viewers. If the entity being updated is a
485                    // client, then we need to be careful to exclude the client itself from
486                    // receiving the update packets.
487                    let msg = if is_client {
488                        LocalMsg::PacketAtExcept {
489                            pos: chunk_pos,
490                            except: entity,
491                        }
492                    } else {
493                        LocalMsg::PacketAt { pos: chunk_pos }
494                    };
495
496                    layer.messages.send_local_infallible(msg, |b| {
497                        update.write_update_packets(PacketWriter::new(b, layer.threshold))
498                    });
499                } else {
500                    panic!(
501                        "Entity {entity:?} was not properly removed from entity layer. Did you \
502                         forget to use the `Despawned` component?"
503                    );
504                }
505            }
506        }
507    }
508}
509
510fn send_layer_despawn_messages(mut layers: Query<&mut EntityLayer, With<Despawned>>) {
511    for mut layer in &mut layers {
512        layer
513            .messages
514            .send_global_infallible(GlobalMsg::DespawnLayer, |_| {});
515    }
516}
517
518fn ready_entity_layers(mut layers: Query<&mut EntityLayer>) {
519    for mut layer in &mut layers {
520        layer.messages.ready();
521    }
522}
523
524fn unready_entity_layers(mut layers: Query<&mut EntityLayer>) {
525    for mut layer in &mut layers {
526        layer.messages.unready();
527    }
528}