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#[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 Packet,
34 PacketExcept { except: Entity },
37 DespawnLayer,
40}
41
42#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
43pub(crate) enum LocalMsg {
45 DespawnEntity { pos: ChunkPos, dest_layer: Entity },
48 DespawnEntityTransition { pos: ChunkPos, dest_pos: ChunkPos },
51 SpawnEntity { pos: ChunkPos, src_layer: Entity },
54 SpawnEntityTransition { pos: ChunkPos, src_pos: ChunkPos },
57 PacketAt { pos: ChunkPos },
60 PacketAtExcept { pos: ChunkPos, except: Entity },
64 RadiusAt {
66 center: BlockPos,
67 radius_squared: u32,
68 },
69 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 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 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 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 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 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 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}