aboutsummaryrefslogtreecommitdiff
path: root/azalea-core/src
diff options
context:
space:
mode:
Diffstat (limited to 'azalea-core/src')
-rwxr-xr-xazalea-core/src/aabb.rs87
-rwxr-xr-xazalea-core/src/block_hit_result.rs21
-rwxr-xr-xazalea-core/src/direction.rs52
-rw-r--r--azalea-core/src/game_type.rs73
-rwxr-xr-xazalea-core/src/lib.rs9
-rwxr-xr-xazalea-core/src/particle/mod.rs5
-rwxr-xr-xazalea-core/src/position.rs19
7 files changed, 194 insertions, 72 deletions
diff --git a/azalea-core/src/aabb.rs b/azalea-core/src/aabb.rs
index 58f079e7..7ad4a657 100755
--- a/azalea-core/src/aabb.rs
+++ b/azalea-core/src/aabb.rs
@@ -164,15 +164,15 @@ impl AABB {
}
}
- pub fn move_relative(&self, x: f64, y: f64, z: f64) -> AABB {
+ pub fn move_relative(&self, delta: &Vec3) -> AABB {
AABB {
- min_x: self.min_x + x,
- min_y: self.min_y + y,
- min_z: self.min_z + z,
+ min_x: self.min_x + delta.x,
+ min_y: self.min_y + delta.y,
+ min_z: self.min_z + delta.z,
- max_x: self.max_x + x,
- max_y: self.max_y + y,
- max_z: self.max_z + z,
+ max_x: self.max_x + delta.x,
+ max_y: self.max_y + delta.y,
+ max_z: self.max_z + delta.z,
}
}
@@ -227,12 +227,11 @@ impl AABB {
pub fn clip(&self, min: &Vec3, max: &Vec3) -> Option<Vec3> {
let mut t = 1.0;
let delta = max - min;
- let _dir = self.get_direction(self, min, &mut t, None, &delta)?;
+ let _dir = Self::get_direction(self, min, &mut t, None, &delta)?;
Some(min + &(delta * t))
}
pub fn clip_iterable(
- &self,
boxes: &Vec<AABB>,
from: &Vec3,
to: &Vec3,
@@ -243,7 +242,13 @@ impl AABB {
let delta = to - from;
for aabb in boxes {
- dir = self.get_direction(aabb, from, &mut t, dir, &delta);
+ dir = Self::get_direction(
+ &aabb.move_relative(&pos.to_vec3_floored()),
+ from,
+ &mut t,
+ dir,
+ &delta,
+ );
}
let dir = dir?;
Some(BlockHitResult {
@@ -256,15 +261,14 @@ impl AABB {
}
fn get_direction(
- &self,
aabb: &AABB,
from: &Vec3,
t: &mut f64,
- dir: Option<Direction>,
+ mut dir: Option<Direction>,
delta: &Vec3,
) -> Option<Direction> {
if delta.x > EPSILON {
- return self.clip_point(ClipPointOpts {
+ dir = Self::clip_point(ClipPointOpts {
t,
approach_dir: dir,
delta,
@@ -277,7 +281,7 @@ impl AABB {
start: from,
});
} else if delta.x < -EPSILON {
- return self.clip_point(ClipPointOpts {
+ dir = Self::clip_point(ClipPointOpts {
t,
approach_dir: dir,
delta,
@@ -292,7 +296,7 @@ impl AABB {
}
if delta.y > EPSILON {
- return self.clip_point(ClipPointOpts {
+ dir = Self::clip_point(ClipPointOpts {
t,
approach_dir: dir,
delta: &Vec3 {
@@ -313,7 +317,7 @@ impl AABB {
},
});
} else if delta.y < -EPSILON {
- return self.clip_point(ClipPointOpts {
+ dir = Self::clip_point(ClipPointOpts {
t,
approach_dir: dir,
delta: &Vec3 {
@@ -336,7 +340,7 @@ impl AABB {
}
if delta.z > EPSILON {
- return self.clip_point(ClipPointOpts {
+ dir = Self::clip_point(ClipPointOpts {
t,
approach_dir: dir,
delta: &Vec3 {
@@ -357,7 +361,7 @@ impl AABB {
},
});
} else if delta.z < -EPSILON {
- return self.clip_point(ClipPointOpts {
+ dir = Self::clip_point(ClipPointOpts {
t,
approach_dir: dir,
delta: &Vec3 {
@@ -382,18 +386,18 @@ impl AABB {
dir
}
- fn clip_point(&self, opts: ClipPointOpts) -> Option<Direction> {
- let t_x = (opts.begin - opts.start.x) / opts.delta.x;
- let t_y = (opts.start.y + t_x) / opts.delta.y;
- let t_z = (opts.start.z + t_x) / opts.delta.z;
- if 0.0 < t_x
- && t_x < *opts.t
- && opts.min_x - EPSILON < t_y
- && t_y < opts.max_x + EPSILON
- && opts.min_z - EPSILON < t_z
- && t_z < opts.max_z + EPSILON
+ fn clip_point(opts: ClipPointOpts) -> Option<Direction> {
+ let d = (opts.begin - opts.start.x) / opts.delta.x;
+ let e = opts.start.y + d * opts.delta.y;
+ let f = opts.start.z + d * opts.delta.z;
+ if 0.0 < d
+ && d < *opts.t
+ && opts.min_x - EPSILON < e
+ && e < opts.max_x + EPSILON
+ && opts.min_z - EPSILON < f
+ && f < opts.max_z + EPSILON
{
- *opts.t = t_x;
+ *opts.t = d;
Some(opts.result_dir)
} else {
opts.approach_dir
@@ -435,3 +439,28 @@ impl AABB {
axis.choose(self.min_x, self.min_y, self.min_z)
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_aabb_clip_iterable() {
+ assert_ne!(
+ AABB::clip_iterable(
+ &vec![AABB {
+ min_x: 0.,
+ min_y: 0.,
+ min_z: 0.,
+ max_x: 1.,
+ max_y: 1.,
+ max_z: 1.,
+ }],
+ &Vec3::new(-1., -1., -1.),
+ &Vec3::new(1., 1., 1.),
+ &BlockPos::new(0, 0, 0),
+ ),
+ None
+ );
+ }
+}
diff --git a/azalea-core/src/block_hit_result.rs b/azalea-core/src/block_hit_result.rs
index 420d4408..3b4f7257 100755
--- a/azalea-core/src/block_hit_result.rs
+++ b/azalea-core/src/block_hit_result.rs
@@ -1,6 +1,6 @@
use crate::{BlockPos, Direction, Vec3};
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BlockHitResult {
pub location: Vec3,
pub direction: Direction,
@@ -8,3 +8,22 @@ pub struct BlockHitResult {
pub miss: bool,
pub inside: bool,
}
+
+impl BlockHitResult {
+ pub fn miss(location: Vec3, direction: Direction, block_pos: BlockPos) -> Self {
+ Self {
+ location,
+ direction,
+ block_pos,
+ miss: true,
+ inside: false,
+ }
+ }
+
+ pub fn with_direction(&self, direction: Direction) -> Self {
+ Self { direction, ..*self }
+ }
+ pub fn with_position(&self, block_pos: BlockPos) -> Self {
+ Self { block_pos, ..*self }
+ }
+}
diff --git a/azalea-core/src/direction.rs b/azalea-core/src/direction.rs
index 95dacc69..c872f26c 100755
--- a/azalea-core/src/direction.rs
+++ b/azalea-core/src/direction.rs
@@ -1,6 +1,8 @@
use azalea_buf::McBuf;
-#[derive(Clone, Copy, Debug, McBuf, Default)]
+use crate::Vec3;
+
+#[derive(Clone, Copy, Debug, McBuf, Default, Eq, PartialEq)]
pub enum Direction {
#[default]
Down = 0,
@@ -11,6 +13,54 @@ pub enum Direction {
East,
}
+impl Direction {
+ pub fn nearest(vec: Vec3) -> Direction {
+ let mut best_direction = Direction::North;
+ let mut best_direction_amount = 0.0;
+
+ for dir in [
+ Direction::Down,
+ Direction::Up,
+ Direction::North,
+ Direction::South,
+ Direction::West,
+ Direction::East,
+ ]
+ .iter()
+ {
+ let amount = dir.normal().dot(vec);
+ if amount > best_direction_amount {
+ best_direction = *dir;
+ best_direction_amount = amount;
+ }
+ }
+
+ best_direction
+ }
+
+ pub fn normal(self) -> Vec3 {
+ match self {
+ Direction::Down => Vec3::new(0.0, -1.0, 0.0),
+ Direction::Up => Vec3::new(0.0, 1.0, 0.0),
+ Direction::North => Vec3::new(0.0, 0.0, -1.0),
+ Direction::South => Vec3::new(0.0, 0.0, 1.0),
+ Direction::West => Vec3::new(-1.0, 0.0, 0.0),
+ Direction::East => Vec3::new(1.0, 0.0, 0.0),
+ }
+ }
+
+ pub fn opposite(self) -> Direction {
+ match self {
+ Direction::Down => Direction::Up,
+ Direction::Up => Direction::Down,
+ Direction::North => Direction::South,
+ Direction::South => Direction::North,
+ Direction::West => Direction::East,
+ Direction::East => Direction::West,
+ }
+ }
+}
+
// TODO: make azalea_block use this instead of FacingCardinal
#[derive(Clone, Copy, Debug, McBuf)]
pub enum CardinalDirection {
diff --git a/azalea-core/src/game_type.rs b/azalea-core/src/game_type.rs
index f99a5805..e1a3e19b 100644
--- a/azalea-core/src/game_type.rs
+++ b/azalea-core/src/game_type.rs
@@ -1,8 +1,9 @@
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
use std::io::{Cursor, Write};
-#[derive(Hash, Copy, Clone, Debug, Default)]
-pub enum GameType {
+/// A Minecraft gamemode, like survival or creative.
+#[derive(Hash, Copy, Clone, Debug, Default, Eq, PartialEq)]
+pub enum GameMode {
#[default]
Survival,
Creative,
@@ -10,30 +11,30 @@ pub enum GameType {
Spectator,
}
-impl GameType {
+impl GameMode {
pub fn to_id(&self) -> u8 {
match self {
- GameType::Survival => 0,
- GameType::Creative => 1,
- GameType::Adventure => 2,
- GameType::Spectator => 3,
+ GameMode::Survival => 0,
+ GameMode::Creative => 1,
+ GameMode::Adventure => 2,
+ GameMode::Spectator => 3,
}
}
/// Get the id of the game type, but return -1 if the game type is invalid.
- pub fn to_optional_id<T: Into<Option<GameType>>>(game_type: T) -> i8 {
+ pub fn to_optional_id<T: Into<Option<GameMode>>>(game_type: T) -> i8 {
match game_type.into() {
Some(game_type) => game_type.to_id() as i8,
None => -1,
}
}
- pub fn from_id(id: u8) -> Option<GameType> {
+ pub fn from_id(id: u8) -> Option<GameMode> {
Some(match id {
- 0 => GameType::Survival,
- 1 => GameType::Creative,
- 2 => GameType::Adventure,
- 3 => GameType::Spectator,
+ 0 => GameMode::Survival,
+ 1 => GameMode::Creative,
+ 2 => GameMode::Adventure,
+ 3 => GameMode::Spectator,
_ => return None,
})
}
@@ -42,7 +43,7 @@ impl GameType {
Some(
match id {
-1 => None,
- id => Some(GameType::from_id(id as u8)?),
+ id => Some(GameMode::from_id(id as u8)?),
}
.into(),
)
@@ -52,10 +53,10 @@ impl GameType {
// TODO: these should be translated
// TranslatableComponent("selectWorld.gameMode." + string2)
match self {
- GameType::Survival => "Survival",
- GameType::Creative => "Creative",
- GameType::Adventure => "Adventure",
- GameType::Spectator => "Spectator",
+ GameMode::Survival => "Survival",
+ GameMode::Creative => "Creative",
+ GameMode::Adventure => "Adventure",
+ GameMode::Spectator => "Spectator",
}
}
@@ -63,32 +64,32 @@ impl GameType {
// TODO: These should be translated TranslatableComponent("gameMode." +
// string2);
match self {
- GameType::Survival => "Survival Mode",
- GameType::Creative => "Creative Mode",
- GameType::Adventure => "Adventure Mode",
- GameType::Spectator => "Spectator Mode",
+ GameMode::Survival => "Survival Mode",
+ GameMode::Creative => "Creative Mode",
+ GameMode::Adventure => "Adventure Mode",
+ GameMode::Spectator => "Spectator Mode",
}
}
- pub fn from_name(name: &str) -> GameType {
+ pub fn from_name(name: &str) -> GameMode {
match name {
- "survival" => GameType::Survival,
- "creative" => GameType::Creative,
- "adventure" => GameType::Adventure,
- "spectator" => GameType::Spectator,
+ "survival" => GameMode::Survival,
+ "creative" => GameMode::Creative,
+ "adventure" => GameMode::Adventure,
+ "spectator" => GameMode::Spectator,
_ => panic!("Unknown game type name: {name}"),
}
}
}
-impl McBufReadable for GameType {
+impl McBufReadable for GameMode {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let id = u8::read_from(buf)?;
- GameType::from_id(id).ok_or(BufReadError::UnexpectedEnumVariant { id: id as i32 })
+ GameMode::from_id(id).ok_or(BufReadError::UnexpectedEnumVariant { id: id as i32 })
}
}
-impl McBufWritable for GameType {
+impl McBufWritable for GameMode {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
u8::write_into(&self.to_id(), buf)
}
@@ -97,15 +98,15 @@ impl McBufWritable for GameType {
/// Rust doesn't let us `impl McBufReadable for Option<GameType>` so we have to
/// make a new type :(
#[derive(Hash, Copy, Clone, Debug)]
-pub struct OptionalGameType(pub Option<GameType>);
+pub struct OptionalGameType(pub Option<GameMode>);
-impl From<Option<GameType>> for OptionalGameType {
- fn from(game_type: Option<GameType>) -> Self {
+impl From<Option<GameMode>> for OptionalGameType {
+ fn from(game_type: Option<GameMode>) -> Self {
OptionalGameType(game_type)
}
}
-impl From<OptionalGameType> for Option<GameType> {
+impl From<OptionalGameType> for Option<GameMode> {
fn from(optional_game_type: OptionalGameType) -> Self {
optional_game_type.0
}
@@ -114,12 +115,12 @@ impl From<OptionalGameType> for Option<GameType> {
impl McBufReadable for OptionalGameType {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let id = i8::read_from(buf)?;
- GameType::from_optional_id(id).ok_or(BufReadError::UnexpectedEnumVariant { id: id as i32 })
+ GameMode::from_optional_id(id).ok_or(BufReadError::UnexpectedEnumVariant { id: id as i32 })
}
}
impl McBufWritable for OptionalGameType {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- GameType::to_optional_id(*self).write_into(buf)
+ GameMode::to_optional_id(*self).write_into(buf)
}
}
diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs
index ce502fe5..7bf4a12c 100755
--- a/azalea-core/src/lib.rs
+++ b/azalea-core/src/lib.rs
@@ -13,9 +13,6 @@ pub use resource_location::*;
mod game_type;
pub use game_type::*;
-mod slot;
-pub use slot::*;
-
mod position;
pub use position::*;
@@ -40,6 +37,8 @@ pub use aabb::*;
mod block_hit_result;
pub use block_hit_result::*;
+// some random math things used in minecraft are defined down here
+
// TODO: make this generic
pub fn binary_search(mut min: i32, max: i32, predicate: &dyn Fn(i32) -> bool) -> i32 {
let mut diff = max - min;
@@ -70,6 +69,10 @@ pub fn gcd(mut a: u32, mut b: u32) -> u32 {
a
}
+pub fn lerp<T: num_traits::Float>(amount: T, a: T, b: T) -> T {
+ a + amount * (b - a)
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/azalea-core/src/particle/mod.rs b/azalea-core/src/particle/mod.rs
index 8dc9f8c6..60128f3f 100755
--- a/azalea-core/src/particle/mod.rs
+++ b/azalea-core/src/particle/mod.rs
@@ -1,5 +1,6 @@
-use crate::{BlockPos, Slot};
+use crate::BlockPos;
use azalea_buf::McBuf;
+use azalea_inventory::ItemSlot;
#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
#[derive(Debug, Clone, McBuf, Default)]
@@ -139,7 +140,7 @@ pub struct DustColorTransitionParticle {
#[derive(Debug, Clone, McBuf)]
pub struct ItemParticle {
- pub item: Slot,
+ pub item: ItemSlot,
}
#[derive(Debug, Clone, McBuf)]
diff --git a/azalea-core/src/position.rs b/azalea-core/src/position.rs
index c09c9966..766c38d6 100755
--- a/azalea-core/src/position.rs
+++ b/azalea-core/src/position.rs
@@ -18,6 +18,12 @@ macro_rules! vec3_impl {
self.x * self.x + self.y * self.y + self.z * self.z
}
+ /// Get the squared distance from this position to another position.
+ /// Equivalent to `(self - other).length_sqr()`.
+ pub fn distance_to_sqr(&self, other: &Self) -> $type {
+ (self - other).length_sqr()
+ }
+
/// Return a new instance of this position with the y coordinate
/// decreased by the given number.
pub fn down(&self, y: $type) -> Self {
@@ -36,6 +42,10 @@ macro_rules! vec3_impl {
z: self.z,
}
}
+
+ pub fn dot(&self, other: Self) -> $type {
+ self.x * other.x + self.y * other.y + self.z * other.z
+ }
}
impl Add for &$name {
@@ -142,6 +152,15 @@ impl BlockPos {
}
}
+ /// Convert the block position into a Vec3 without centering it.
+ pub fn to_vec3_floored(&self) -> Vec3 {
+ Vec3 {
+ x: self.x as f64,
+ y: self.y as f64,
+ z: self.z as f64,
+ }
+ }
+
/// Get the distance of this vector from the origin by doing `x + y + z`.
pub fn length_manhattan(&self) -> u32 {
(self.x.abs() + self.y.abs() + self.z.abs()) as u32