chunkedge_server/layer/
entity.rs

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