1use yog_data::{Atom, Schema};
5
6use crate::{BlockPos, Point};
7
8#[derive(Debug, Clone, PartialEq, Schema)]
10#[data(view)]
11pub struct LocalState {
12 pub pos: Point,
13 pub yaw: f32,
15 pub pitch: f32,
16 pub velocity: Point,
18 pub on_ground: bool,
19 pub in_water: bool,
20 pub eye_height: f64,
21 pub health: f32,
22 pub food: i32,
23 pub dimension: Atom,
24 pub slot: u32,
26 pub attack_strength: f32,
28 pub sneaking: bool,
30}
31
32impl LocalState {
33 pub fn eye_pos(&self) -> Point {
35 Point {
36 y: self.pos.y + self.eye_height,
37 ..self.pos
38 }
39 }
40}
41
42#[derive(Debug, Clone, PartialEq, Schema)]
44#[data(view)]
45pub struct BlockKind {
46 pub id: Atom,
47 pub solid: bool,
49 pub liquid: bool,
50 pub climbable: bool,
52 pub harmful: bool,
54}
55
56#[derive(Debug, Clone, PartialEq, Schema)]
60#[data(view)]
61pub struct BlockArea {
62 pub min: BlockPos,
63 pub max: BlockPos,
64 pub palette: Vec<BlockKind>,
65 pub blocks: Vec<u16>,
66}
67
68impl BlockArea {
69 pub fn at(&self, pos: impl Into<BlockPos>) -> Option<&BlockKind> {
71 let index = self.blocks.get(self.index(pos.into())?)?;
72 self.palette.get(usize::from(*index))
73 }
74
75 pub fn set(&mut self, pos: impl Into<BlockPos>, kind: u16) -> bool {
78 match self.index(pos.into()).and_then(|i| self.blocks.get_mut(i)) {
79 Some(block) if usize::from(kind) < self.palette.len() => {
80 *block = kind;
81 true
82 }
83 _ => false,
84 }
85 }
86
87 fn index(&self, pos: BlockPos) -> Option<usize> {
89 let (w, d) = (self.max.x - self.min.x + 1, self.max.z - self.min.z + 1);
90 let (x, y, z) = (pos.x - self.min.x, pos.y - self.min.y, pos.z - self.min.z);
91 let inside = (0..w).contains(&x)
92 && (0..d).contains(&z)
93 && (0..=self.max.y - self.min.y).contains(&y);
94 inside
95 .then(|| usize::try_from((y * d + z) * w + x).ok())
96 .flatten()
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Schema)]
102#[data(view)]
103pub struct NearbyEntity {
104 pub uuid: String,
105 pub entity_type: Atom,
106 pub pos: Point,
107 pub eye_height: f64,
108 pub velocity: Point,
110 pub health: Option<f32>,
111 pub name: Option<String>,
113 pub hostile: bool,
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Schema)]
119pub enum ClickMode {
120 Pickup,
121 QuickMove,
122 Swap,
123 Clone,
124 Throw,
125 QuickCraft,
126 PickupAll,
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn an_area_finds_its_blocks() {
135 let kind = |id: &str| BlockKind {
136 id: id.into(),
137 solid: true,
138 liquid: false,
139 climbable: false,
140 harmful: false,
141 };
142 let mut area = BlockArea {
143 min: BlockPos::new(0, 0, 0),
144 max: BlockPos::new(1, 1, 0),
145 palette: vec![kind("a"), kind("b")],
146 blocks: vec![0, 1, 1, 0],
147 };
148 assert_eq!(
149 area.at(BlockPos::new(1, 0, 0)).map(|k| k.id.as_str()),
150 Some("b")
151 );
152 assert_eq!(
153 area.at(BlockPos::new(0, 1, 0)).map(|k| k.id.as_str()),
154 Some("b")
155 );
156 assert_eq!(area.at(BlockPos::new(2, 0, 0)), None);
157 assert!(area.set(BlockPos::new(1, 0, 0), 0));
158 assert_eq!(
159 area.at(BlockPos::new(1, 0, 0)).map(|k| k.id.as_str()),
160 Some("a")
161 );
162 assert!(!area.set(BlockPos::new(2, 0, 0), 0));
163 assert!(!area.set(BlockPos::new(0, 0, 0), 2));
164 }
165}