valence_server/
chunk_view.rs
1use valence_generated::chunk_view::{CHUNK_VIEW_LUT, EXTRA_VIEW_RADIUS, MAX_VIEW_DIST};
2use valence_protocol::ChunkPos;
3
4#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
7pub struct ChunkView {
8 pub pos: ChunkPos,
10 dist: u8,
11}
12
13impl ChunkView {
14 pub const fn new(pos: ChunkPos, dist: u8) -> Self {
17 Self {
18 pos,
19 dist: if dist > MAX_VIEW_DIST {
20 MAX_VIEW_DIST
21 } else {
22 dist
23 },
24 }
25 }
26
27 pub const fn with_dist(self, dist: u8) -> Self {
28 Self::new(self.pos, dist)
29 }
30
31 pub const fn dist(self) -> u8 {
32 self.dist
33 }
34
35 pub const fn contains(self, pos: ChunkPos) -> bool {
36 let true_dist = self.dist as u64 + EXTRA_VIEW_RADIUS as u64;
37 self.pos.distance_squared(pos) <= true_dist * true_dist
38 }
39
40 pub fn iter(self) -> impl DoubleEndedIterator<Item = ChunkPos> + ExactSizeIterator + Clone {
43 CHUNK_VIEW_LUT[self.dist as usize]
44 .iter()
45 .map(move |&(x, z)| ChunkPos {
46 x: self.pos.x + i32::from(x),
47 z: self.pos.z + i32::from(z),
48 })
49 }
50
51 pub fn diff(self, other: Self) -> impl DoubleEndedIterator<Item = ChunkPos> + Clone {
55 self.iter().filter(move |&p| !other.contains(p))
56 }
57
58 pub fn bounding_box(self) -> (ChunkPos, ChunkPos) {
75 let r = i32::from(self.dist) + EXTRA_VIEW_RADIUS;
76
77 (
78 ChunkPos::new(self.pos.x - r, self.pos.z - r),
79 ChunkPos::new(self.pos.x + r, self.pos.z + r),
80 )
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use std::collections::BTreeSet;
87
88 use super::*;
89
90 #[test]
91 fn chunk_view_contains() {
92 let view = ChunkView::new(ChunkPos::new(0, 0), 32);
93 let positions = view.iter().collect::<BTreeSet<_>>();
94
95 for z in -64..64 {
96 for x in -64..64 {
97 let p = ChunkPos::new(x, z);
98 assert_eq!(view.contains(p), positions.contains(&p), "{p:?}");
99 }
100 }
101 }
102}