use yog_data::{Atom, Schema};
use crate::{BlockPos, Point};
#[derive(Debug, Clone, PartialEq, Schema)]
#[data(view)]
pub struct LocalState {
pub pos: Point,
pub yaw: f32,
pub pitch: f32,
pub velocity: Point,
pub on_ground: bool,
pub in_water: bool,
pub eye_height: f64,
pub health: f32,
pub food: i32,
pub dimension: Atom,
pub slot: u32,
pub attack_strength: f32,
}
impl LocalState {
pub fn eye_pos(&self) -> Point {
Point {
y: self.pos.y + self.eye_height,
..self.pos
}
}
}
#[derive(Debug, Clone, PartialEq, Schema)]
#[data(view)]
pub struct BlockKind {
pub id: Atom,
pub solid: bool,
pub liquid: bool,
pub climbable: bool,
pub harmful: bool,
}
#[derive(Debug, Clone, PartialEq, Schema)]
#[data(view)]
pub struct BlockArea {
pub min: BlockPos,
pub max: BlockPos,
pub palette: Vec<BlockKind>,
pub blocks: Vec<u16>,
}
impl BlockArea {
pub fn at(&self, pos: impl Into<BlockPos>) -> Option<&BlockKind> {
let index = self.blocks.get(self.index(pos.into())?)?;
self.palette.get(usize::from(*index))
}
pub fn set(&mut self, pos: impl Into<BlockPos>, kind: u16) -> bool {
match self.index(pos.into()).and_then(|i| self.blocks.get_mut(i)) {
Some(block) if usize::from(kind) < self.palette.len() => {
*block = kind;
true
}
_ => false,
}
}
fn index(&self, pos: BlockPos) -> Option<usize> {
let (w, d) = (self.max.x - self.min.x + 1, self.max.z - self.min.z + 1);
let (x, y, z) = (pos.x - self.min.x, pos.y - self.min.y, pos.z - self.min.z);
let inside = (0..w).contains(&x)
&& (0..d).contains(&z)
&& (0..=self.max.y - self.min.y).contains(&y);
inside
.then(|| usize::try_from((y * d + z) * w + x).ok())
.flatten()
}
}
#[derive(Debug, Clone, PartialEq, Schema)]
#[data(view)]
pub struct NearbyEntity {
pub uuid: String,
pub entity_type: Atom,
pub pos: Point,
pub eye_height: f64,
pub velocity: Point,
pub health: Option<f32>,
pub name: Option<String>,
pub hostile: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Schema)]
pub enum ClickMode {
Pickup,
QuickMove,
Swap,
Clone,
Throw,
QuickCraft,
PickupAll,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn an_area_finds_its_blocks() {
let kind = |id: &str| BlockKind {
id: id.into(),
solid: true,
liquid: false,
climbable: false,
harmful: false,
};
let mut area = BlockArea {
min: BlockPos::new(0, 0, 0),
max: BlockPos::new(1, 1, 0),
palette: vec![kind("a"), kind("b")],
blocks: vec![0, 1, 1, 0],
};
assert_eq!(
area.at(BlockPos::new(1, 0, 0)).map(|k| k.id.as_str()),
Some("b")
);
assert_eq!(
area.at(BlockPos::new(0, 1, 0)).map(|k| k.id.as_str()),
Some("b")
);
assert_eq!(area.at(BlockPos::new(2, 0, 0)), None);
assert!(area.set(BlockPos::new(1, 0, 0), 0));
assert_eq!(
area.at(BlockPos::new(1, 0, 0)).map(|k| k.id.as_str()),
Some("a")
);
assert!(!area.set(BlockPos::new(2, 0, 0), 0));
assert!(!area.set(BlockPos::new(0, 0, 0), 2));
}
}