use std::ops::{self, Index, IndexMut}; use bevy::{ ecs::component::Component, math::{Dir3, IVec3, InvalidDirectionError}, }; use overload::overload; use super::BlockRegion; #[derive(Component, Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct BlockPos { pub x: i32, pub y: i32, pub z: i32, } impl BlockPos { pub const ORIGIN: BlockPos = Self::new(0, 0, 0); pub const fn new(x: i32, y: i32, z: i32) -> Self { Self { x, y, z } } pub fn region(self) -> BlockRegion { BlockRegion::new_unchecked(self, self) } pub fn distance_to(self, other: Self) -> f32 { (self.distance_to_squared(other) as f32).sqrt() } pub fn distance_to_squared(self, other: Self) -> i32 { IVec3::distance_squared(self.into(), other.into()) } pub fn direction_to(self, other: Self) -> Result { Dir3::new((other - self).as_vec3()) } pub fn min(self, rhs: Self) -> Self { Self::new(self.x.min(rhs.x), self.y.min(rhs.y), self.z.min(rhs.z)) } pub fn max(self, rhs: Self) -> Self { Self::new(self.x.max(rhs.x), self.y.max(rhs.y), self.z.max(rhs.z)) } pub fn offset(self, x: i32, y: i32, z: i32) -> Self { Self::new(self.x + x, self.y + y, self.z + z) } } impl std::fmt::Display for BlockPos { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "[{}, {}, {}]", self.x, self.y, self.z) } } // Offsetting overload!((l: BlockPos) + (r: IVec3) -> BlockPos { BlockPos::new(l.x + r.x, l.y + r.y, l.z + r.z) }); overload!((l: BlockPos) - (r: IVec3) -> BlockPos { BlockPos::new(l.x - r.x, l.y - r.y, l.z - r.z) }); overload!((s: &mut BlockPos) += (v: IVec3) { s.x += v.x; s.y += v.y; s.z += v.z; }); overload!((s: &mut BlockPos) -= (v: IVec3) { s.x -= v.x; s.y -= v.y; s.z -= v.z; }); // Difference overload!((l: BlockPos) - (r: BlockPos) -> IVec3 { IVec3::new(l.x - r.x, l.y - r.y, l.z - r.z) }); // Indexing impl Index for BlockPos { type Output = i32; fn index(&self, index: usize) -> &Self::Output { match index { 0 => &self.x, 1 => &self.y, 2 => &self.z, _ => panic!("index out of bounds"), } } } impl IndexMut for BlockPos { fn index_mut(&mut self, index: usize) -> &mut Self::Output { match index { 0 => &mut self.x, 1 => &mut self.y, 2 => &mut self.z, _ => panic!("index out of bounds"), } } } // Conversion impl From<(i32, i32, i32)> for BlockPos { fn from((x, y, z): (i32, i32, i32)) -> Self { Self::new(x, y, z) } } impl From for (i32, i32, i32) { fn from(BlockPos { x, y, z }: BlockPos) -> Self { (x, y, z) } } impl From<[i32; 3]> for BlockPos { fn from([x, y, z]: [i32; 3]) -> Self { Self::new(x, y, z) } } impl From for [i32; 3] { fn from(BlockPos { x, y, z }: BlockPos) -> Self { [x, y, z] } } impl From for BlockPos { fn from(IVec3 { x, y, z }: IVec3) -> Self { Self::new(x, y, z) } } impl From for IVec3 { fn from(BlockPos { x, y, z }: BlockPos) -> Self { Self::new(x, y, z) } }