azalea_core/
direction.rs

1use azalea_buf::AzBuf;
2
3use crate::position::{BlockPos, Vec3};
4
5#[derive(Clone, Copy, Debug, AzBuf, Default, Eq, PartialEq)]
6#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
7pub enum Direction {
8    #[default]
9    Down = 0,
10    Up,
11    North,
12    South,
13    West,
14    East,
15}
16
17impl Direction {
18    pub const HORIZONTAL: [Direction; 4] = [
19        Direction::North,
20        Direction::South,
21        Direction::West,
22        Direction::East,
23    ];
24    pub const VERTICAL: [Direction; 2] = [Direction::Down, Direction::Up];
25
26    pub fn nearest(vec: Vec3) -> Direction {
27        let mut best_direction = Direction::North;
28        let mut best_direction_amount = 0.0;
29
30        for dir in [
31            Direction::Down,
32            Direction::Up,
33            Direction::North,
34            Direction::South,
35            Direction::West,
36            Direction::East,
37        ]
38        .iter()
39        {
40            let amount = dir.normal_vec3().dot(vec);
41            if amount > best_direction_amount {
42                best_direction = *dir;
43                best_direction_amount = amount;
44            }
45        }
46
47        best_direction
48    }
49
50    #[inline]
51    pub fn normal(self) -> BlockPos {
52        match self {
53            Direction::Down => BlockPos::new(0, -1, 0),
54            Direction::Up => BlockPos::new(0, 1, 0),
55            Direction::North => BlockPos::new(0, 0, -1),
56            Direction::South => BlockPos::new(0, 0, 1),
57            Direction::West => BlockPos::new(-1, 0, 0),
58            Direction::East => BlockPos::new(1, 0, 0),
59        }
60    }
61
62    #[inline]
63    pub fn normal_vec3(self) -> Vec3 {
64        self.normal().to_vec3_floored()
65    }
66
67    pub fn opposite(self) -> Direction {
68        match self {
69            Direction::Down => Direction::Up,
70            Direction::Up => Direction::Down,
71            Direction::North => Direction::South,
72            Direction::South => Direction::North,
73            Direction::West => Direction::East,
74            Direction::East => Direction::West,
75        }
76    }
77
78    pub fn x(self) -> i32 {
79        self.normal().x
80    }
81    pub fn y(self) -> i32 {
82        self.normal().y
83    }
84    pub fn z(self) -> i32 {
85        self.normal().z
86    }
87}
88
89/// The four cardinal directions.
90///
91/// Note that azalea_block has a similar enum named `FacingCardinal` that is
92/// used for block states.
93#[derive(Clone, Copy, Debug, AzBuf, PartialEq, Eq, Hash)]
94#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
95pub enum CardinalDirection {
96    North,
97    South,
98    West,
99    East,
100}
101
102/// A 3D axis like x, y, z.
103#[derive(Clone, Copy, Debug)]
104pub enum Axis {
105    X = 0,
106    Y = 1,
107    Z = 2,
108}
109
110#[derive(Clone, Copy, Debug)]
111pub enum AxisCycle {
112    None = 0,
113    Forward = 1,
114    Backward = 2,
115}
116
117impl CardinalDirection {
118    #[inline]
119    pub fn x(self) -> i16 {
120        match self {
121            CardinalDirection::East => 1,
122            CardinalDirection::West => -1,
123            _ => 0,
124        }
125    }
126    #[inline]
127    pub fn z(self) -> i16 {
128        match self {
129            CardinalDirection::South => 1,
130            CardinalDirection::North => -1,
131            _ => 0,
132        }
133    }
134
135    pub fn iter() -> impl Iterator<Item = CardinalDirection> {
136        [
137            CardinalDirection::North,
138            CardinalDirection::South,
139            CardinalDirection::West,
140            CardinalDirection::East,
141        ]
142        .iter()
143        .copied()
144    }
145
146    #[inline]
147    pub fn right(self) -> CardinalDirection {
148        match self {
149            CardinalDirection::North => CardinalDirection::East,
150            CardinalDirection::South => CardinalDirection::West,
151            CardinalDirection::West => CardinalDirection::North,
152            CardinalDirection::East => CardinalDirection::South,
153        }
154    }
155    #[inline]
156    pub fn left(self) -> CardinalDirection {
157        match self {
158            CardinalDirection::North => CardinalDirection::West,
159            CardinalDirection::South => CardinalDirection::East,
160            CardinalDirection::West => CardinalDirection::South,
161            CardinalDirection::East => CardinalDirection::North,
162        }
163    }
164}
165
166impl Axis {
167    /// Pick x, y, or z from the arguments depending on the axis.
168    #[inline]
169    pub fn choose<T>(&self, x: T, y: T, z: T) -> T {
170        match self {
171            Axis::X => x,
172            Axis::Y => y,
173            Axis::Z => z,
174        }
175    }
176
177    pub fn from_ordinal(ordinal: u32) -> Self {
178        match ordinal {
179            0 => Axis::X,
180            1 => Axis::Y,
181            2 => Axis::Z,
182            _ => panic!("Invalid ordinal {ordinal}"),
183        }
184    }
185}
186
187impl AxisCycle {
188    pub fn from_ordinal(ordinal: u32) -> Self {
189        match ordinal {
190            0 => Self::None,
191            1 => Self::Forward,
192            2 => Self::Backward,
193            _ => panic!("invalid ordinal"),
194        }
195    }
196    pub fn between(axis0: Axis, axis1: Axis) -> Self {
197        Self::from_ordinal(i32::rem_euclid(axis1 as i32 - axis0 as i32, 3) as u32)
198    }
199    pub fn inverse(self) -> Self {
200        match self {
201            Self::None => Self::None,
202            Self::Forward => Self::Backward,
203            Self::Backward => Self::Forward,
204        }
205    }
206    pub fn cycle(self, axis: Axis) -> Axis {
207        match self {
208            Self::None => axis,
209            Self::Forward => Axis::from_ordinal(i32::rem_euclid(axis as i32 + 1, 3) as u32),
210            Self::Backward => Axis::from_ordinal(i32::rem_euclid(axis as i32 - 1, 3) as u32),
211        }
212    }
213    pub fn cycle_xyz(self, x: i32, y: i32, z: i32, axis: Axis) -> i32 {
214        match self {
215            Self::None => axis.choose(x, y, z),
216            Self::Forward => axis.choose(z, x, y),
217            Self::Backward => axis.choose(y, z, x),
218        }
219    }
220}