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}
29
30impl LocalState {
31 pub fn eye_pos(&self) -> Point {
33 Point {
34 y: self.pos.y + self.eye_height,
35 ..self.pos
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, Schema)]
42#[data(view)]
43pub struct BlockKind {
44 pub id: Atom,
45 pub solid: bool,
47 pub liquid: bool,
48 pub climbable: bool,
50 pub harmful: bool,
52}
53
54#[derive(Debug, Clone, PartialEq, Schema)]
58#[data(view)]
59pub struct BlockArea {
60 pub min: BlockPos,
61 pub max: BlockPos,
62 pub palette: Vec<BlockKind>,
63 pub blocks: Vec<u16>,
64}
65
66impl BlockArea {
67 pub fn at(&self, pos: impl Into<BlockPos>) -> Option<&BlockKind> {
69 let index = self.blocks.get(self.index(pos.into())?)?;
70 self.palette.get(usize::from(*index))
71 }
72
73 pub fn set(&mut self, pos: impl Into<BlockPos>, kind: u16) -> bool {
76 match self.index(pos.into()).and_then(|i| self.blocks.get_mut(i)) {
77 Some(block) if usize::from(kind) < self.palette.len() => {
78 *block = kind;
79 true
80 }
81 _ => false,
82 }
83 }
84
85 fn index(&self, pos: BlockPos) -> Option<usize> {
87 let (w, d) = (self.max.x - self.min.x + 1, self.max.z - self.min.z + 1);
88 let (x, y, z) = (pos.x - self.min.x, pos.y - self.min.y, pos.z - self.min.z);
89 let inside = (0..w).contains(&x)
90 && (0..d).contains(&z)
91 && (0..=self.max.y - self.min.y).contains(&y);
92 inside
93 .then(|| usize::try_from((y * d + z) * w + x).ok())
94 .flatten()
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Schema)]
100#[data(view)]
101pub struct NearbyEntity {
102 pub uuid: String,
103 pub entity_type: Atom,
104 pub pos: Point,
105 pub eye_height: f64,
106 pub velocity: Point,
108 pub health: Option<f32>,
109 pub name: Option<String>,
111 pub hostile: bool,
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Schema)]
117pub enum ClickMode {
118 Pickup,
119 QuickMove,
120 Swap,
121 Clone,
122 Throw,
123 QuickCraft,
124 PickupAll,
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn an_area_finds_its_blocks() {
133 let kind = |id: &str| BlockKind {
134 id: id.into(),
135 solid: true,
136 liquid: false,
137 climbable: false,
138 harmful: false,
139 };
140 let mut area = BlockArea {
141 min: BlockPos::new(0, 0, 0),
142 max: BlockPos::new(1, 1, 0),
143 palette: vec![kind("a"), kind("b")],
144 blocks: vec![0, 1, 1, 0],
145 };
146 assert_eq!(
147 area.at(BlockPos::new(1, 0, 0)).map(|k| k.id.as_str()),
148 Some("b")
149 );
150 assert_eq!(
151 area.at(BlockPos::new(0, 1, 0)).map(|k| k.id.as_str()),
152 Some("b")
153 );
154 assert_eq!(area.at(BlockPos::new(2, 0, 0)), None);
155 assert!(area.set(BlockPos::new(1, 0, 0), 0));
156 assert_eq!(
157 area.at(BlockPos::new(1, 0, 0)).map(|k| k.id.as_str()),
158 Some("a")
159 );
160 assert!(!area.set(BlockPos::new(2, 0, 0), 0));
161 assert!(!area.set(BlockPos::new(0, 0, 0), 2));
162 }
163}