diff options
Diffstat (limited to 'azalea-core')
| -rwxr-xr-x[-rw-r--r--] | azalea-core/Cargo.toml | 4 | ||||
| -rwxr-xr-x | azalea-core/src/aabb.rs | 87 | ||||
| -rwxr-xr-x | azalea-core/src/block_hit_result.rs | 21 | ||||
| -rwxr-xr-x | azalea-core/src/direction.rs | 52 | ||||
| -rw-r--r-- | azalea-core/src/game_type.rs | 73 | ||||
| -rwxr-xr-x | azalea-core/src/lib.rs | 9 | ||||
| -rwxr-xr-x | azalea-core/src/particle/mod.rs | 5 | ||||
| -rwxr-xr-x | azalea-core/src/position.rs | 19 |
8 files changed, 198 insertions, 72 deletions
diff --git a/azalea-core/Cargo.toml b/azalea-core/Cargo.toml index 6f49774c..76f4b456 100644..100755 --- a/azalea-core/Cargo.toml +++ b/azalea-core/Cargo.toml @@ -10,8 +10,12 @@ version = "0.6.0" [dependencies] azalea-buf = { path = "../azalea-buf", version = "^0.6.0" } +azalea-chat = { path = "../azalea-chat", version = "^0.6.0" } +azalea-inventory = { version = "0.1.0", path = "../azalea-inventory" } azalea-nbt = { path = "../azalea-nbt", version = "^0.6.0" } +azalea-registry = { path = "../azalea-registry", version = "^0.6.0" } bevy_ecs = { version = "0.10.0", default-features = false, optional = true } +num-traits = "0.2.15" serde = { version = "^1.0", optional = true } uuid = "^1.1.2" 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 |
