1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! Defines chunk layers and entity layers. Chunk layers contain the chunks and
//! dimension data of a world, while entity layers contain all the Minecraft
//! entities.
//!
//! These two together are analogous to Minecraft "levels" or "worlds".

pub mod bvh;
pub mod chunk;
pub mod entity;
pub mod message;

use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
pub use chunk::ChunkLayer;
pub use entity::EntityLayer;
use valence_entity::{InitEntitiesSet, UpdateTrackedDataSet};
use valence_protocol::encode::WritePacket;
use valence_protocol::{BlockPos, ChunkPos, Ident};
use valence_registry::{BiomeRegistry, DimensionTypeRegistry};
use valence_server_common::Server;

pub struct LayerPlugin;

/// When entity and chunk changes are written to layers. Systems that modify
/// chunks and entities should run _before_ this. Systems that need to read
/// layer messages should run _after_ this.
#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct UpdateLayersPreClientSet;

/// When layers are cleared and messages from this tick are lost. Systems that
/// read layer messages should run _before_ this.
#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct UpdateLayersPostClientSet;

impl Plugin for LayerPlugin {
    fn build(&self, app: &mut App) {
        app.configure_sets(
            PostUpdate,
            (
                UpdateLayersPreClientSet
                    .after(InitEntitiesSet)
                    .after(UpdateTrackedDataSet),
                UpdateLayersPostClientSet.after(UpdateLayersPreClientSet),
            ),
        );

        chunk::build(app);
        entity::build(app);
    }
}

/// Common functionality for layers. Notable implementors are [`ChunkLayer`] and
/// [`EntityLayer`].
///
/// Layers support sending packets to viewers of the layer under various
/// conditions. These are the "packet writers" exposed by this trait.
///
/// Layers themselves implement the [`WritePacket`] trait. Writing directly to a
/// layer will send packets to all viewers unconditionally.
pub trait Layer: WritePacket {
    /// Packet writer returned by [`except_writer`](Self::except_writer).
    type ExceptWriter<'a>: WritePacket
    where
        Self: 'a;

    /// Packet writer returned by [`view_writer`](Self::ViewWriter).
    type ViewWriter<'a>: WritePacket
    where
        Self: 'a;

    /// Packet writer returned by
    /// [`view_except_writer`](Self::ViewExceptWriter).
    type ViewExceptWriter<'a>: WritePacket
    where
        Self: 'a;

    /// Packet writer returned by [`radius_writer`](Self::radius_writer).
    type RadiusWriter<'a>: WritePacket
    where
        Self: 'a;

    /// Packet writer returned by
    /// [`radius_except_writer`](Self::radius_except_writer).
    type RadiusExceptWriter<'a>: WritePacket
    where
        Self: 'a;

    /// Returns a packet writer which sends packets to all viewers not
    /// identified by `except`.
    fn except_writer(&mut self, except: Entity) -> Self::ExceptWriter<'_>;

    /// Returns a packet writer which sends packets to viewers in view of
    /// the chunk position `pos`.
    fn view_writer(&mut self, pos: impl Into<ChunkPos>) -> Self::ViewWriter<'_>;

    /// Returns a packet writer which sends packets to viewers in
    /// view of the chunk position `pos` and not identified by `except`.
    fn view_except_writer(
        &mut self,
        pos: impl Into<ChunkPos>,
        except: Entity,
    ) -> Self::ViewExceptWriter<'_>;

    /// Returns a packet writer which sends packets to viewers within `radius`
    /// blocks of the block position `pos`.
    fn radius_writer(&mut self, pos: impl Into<BlockPos>, radius: u32) -> Self::RadiusWriter<'_>;

    /// Returns a packet writer which sends packets to viewers within `radius`
    /// blocks of the block position `pos` and not identified by `except`.
    fn radius_except_writer(
        &mut self,
        pos: impl Into<BlockPos>,
        radius: u32,
        except: Entity,
    ) -> Self::RadiusExceptWriter<'_>;
}

/// Convenience [`Bundle`] for spawning a layer entity with both [`ChunkLayer`]
/// and [`EntityLayer`] components.
#[derive(Bundle)]
pub struct LayerBundle {
    pub chunk: ChunkLayer,
    pub entity: EntityLayer,
}

impl LayerBundle {
    /// Returns a new layer bundle.
    pub fn new<N: Into<Ident<String>>>(
        dimension_type_name: N,
        dimensions: &DimensionTypeRegistry,
        biomes: &BiomeRegistry,
        server: &Server,
    ) -> Self {
        Self {
            chunk: ChunkLayer::new(dimension_type_name, dimensions, biomes, server),
            entity: EntityLayer::new(server),
        }
    }
}