From 59bfc5bc941e2a9937b82b2373408b6ede97c8e7 Mon Sep 17 00:00:00 2001 From: mat Date: Tue, 28 Jun 2022 22:54:52 -0500 Subject: [PATCH] more shape stuff --- azalea-physics/src/dimension_collisions.rs | 13 ++- azalea-physics/src/discrete_voxel_shape.rs | 26 +++++ azalea-physics/src/lib.rs | 8 +- azalea-physics/src/shape.rs | 111 ++++++++++++++++----- 4 files changed, 127 insertions(+), 31 deletions(-) diff --git a/azalea-physics/src/dimension_collisions.rs b/azalea-physics/src/dimension_collisions.rs index df51ff9d..37cbfabd 100644 --- a/azalea-physics/src/dimension_collisions.rs +++ b/azalea-physics/src/dimension_collisions.rs @@ -1,4 +1,4 @@ -use crate::{aabb::EPSILON, VoxelShape, AABB}; +use crate::{aabb::EPSILON, ArrayVoxelShape, VoxelShape, AABB}; use azalea_block::{Block, BlockState}; use azalea_core::{ChunkPos, ChunkSectionPos, Cursor3d, CursorIterationType}; use azalea_entity::Entity; @@ -76,7 +76,7 @@ impl<'a> BlockCollisions<'a> { } impl<'a> Iterator for BlockCollisions<'a> { - type Item = VoxelShape; + type Item = ArrayVoxelShape; fn next(&mut self) -> Option { while let Some(item) = self.cursor.next() { @@ -93,7 +93,7 @@ impl<'a> Iterator for BlockCollisions<'a> { let pos = item.pos; let block_state: BlockState = chunk_lock.get(&(&pos).into(), self.dimension.min_y()); - let block: &dyn Block = &block_state.into(); + let block: Box = block_state.into(); // TODO: continue if self.only_suffocating_blocks and the block is not suffocating @@ -101,6 +101,7 @@ impl<'a> Iterator for BlockCollisions<'a> { // let block_shape = block.get_collision_shape(); // if block_shape == Shapes::block() { if true { + // TODO: this can be optimized if !self.aabb.intersects_aabb(&AABB { min_x: item.pos.x as f64, min_y: item.pos.y as f64, @@ -112,7 +113,11 @@ impl<'a> Iterator for BlockCollisions<'a> { continue; } - return block_shape.move_relative(item.pos.x, item.pos.y, item.pos.z); + return Some(block_shape.move_relative( + item.pos.x as f64, + item.pos.y as f64, + item.pos.z as f64, + )); } // let block_shape = block_shape.move_relative(item.pos.x, item.pos.y, item.pos.z); diff --git a/azalea-physics/src/discrete_voxel_shape.rs b/azalea-physics/src/discrete_voxel_shape.rs index ae530970..d3f9932d 100644 --- a/azalea-physics/src/discrete_voxel_shape.rs +++ b/azalea-physics/src/discrete_voxel_shape.rs @@ -1,5 +1,7 @@ use azalea_core::BitSet; +// TODO: every impl of DiscreteVoxelShape could be turned into a single enum as an optimization + pub trait DiscreteVoxelShape { // public boolean isFullWide(int var1, int var2, int var3) { // if (var1 >= 0 && var2 >= 0 && var3 >= 0) { @@ -17,6 +19,30 @@ pub trait DiscreteVoxelShape { // } // return false; // } + fn x_size(&self) -> usize; + fn y_size(&self) -> usize; + fn z_size(&self) -> usize; + + fn first_full_x(&self) -> usize; + fn first_full_y(&self) -> usize; + fn first_full_z(&self) -> usize; + + fn last_full_x(&self) -> usize; + fn last_full_y(&self) -> usize; + fn last_full_z(&self) -> usize; + + fn is_empty(&self) -> bool { + if self.first_full_x() >= self.last_full_x() { + return true; + } + if self.first_full_y() >= self.last_full_y() { + return true; + } + if self.first_full_x() >= self.last_full_x() { + return true; + } + false + } } #[derive(Default)] diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index f9826d61..c05b2662 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -28,12 +28,12 @@ trait HasPhysics { movement: &Vec3, entity_bounding_box: &AABB, dimension: &Dimension, - entity_collisions: Vec, + entity_collisions: Vec>, ) -> Vec3; fn collide_with_shapes( movement: &Vec3, entity_box: &AABB, - collision_boxes: &Vec, + collision_boxes: &Vec>, ) -> Vec3; } @@ -79,7 +79,7 @@ impl HasPhysics for Entity { movement: &Vec3, entity_bounding_box: &AABB, dimension: &Dimension, - entity_collisions: Vec, + entity_collisions: Vec>, ) -> Vec3 { let mut collision_boxes = Vec::with_capacity(1); // entity_collisions.len() + 1 @@ -98,7 +98,7 @@ impl HasPhysics for Entity { fn collide_with_shapes( movement: &Vec3, entity_box: &AABB, - collision_boxes: &Vec, + collision_boxes: &Vec>, ) -> Vec3 { // TODO *movement diff --git a/azalea-physics/src/shape.rs b/azalea-physics/src/shape.rs index 9251d60c..7ec057ec 100644 --- a/azalea-physics/src/shape.rs +++ b/azalea-physics/src/shape.rs @@ -1,40 +1,105 @@ +use std::ops::{Add, Index}; + use azalea_core::Direction; use crate::{BitSetDiscreteVoxelShape, DiscreteVoxelShape}; -pub struct VoxelShape { - shape: BitSetDiscreteVoxelShape, - faces: Vec, -} - pub struct Shapes {} -pub fn block_shape() -> VoxelShape { +pub fn block_shape() -> Box { let mut shape = BitSetDiscreteVoxelShape::new(1, 1, 1); shape.fill(0, 0, 0); - VoxelShape::new(shape) + VoxelShape::new(Box::new(shape)) } -impl VoxelShape { - pub fn new(shape: BitSetDiscreteVoxelShape) -> Self { - VoxelShape { - shape, - faces: Vec::new(), - } - } +pub trait VoxelShape { + fn shape(&self) -> Box; - // public VoxelShape move(double var1, double var3, double var5) { - // return (VoxelShape)(this.isEmpty() ? Shapes.empty() : new ArrayVoxelShape(this.shape, new OffsetDoubleList(this.getCoords(Direction.Axis.X), var1), new OffsetDoubleList(this.getCoords(Direction.Axis.Y), var3), new OffsetDoubleList(this.getCoords(Direction.Axis.Z), var5))); - // } - pub fn move_relative(&self, x: i32, y: i32, z: i32) -> Self { - if self.is_empty() { + fn get_x_coords(&self) -> Vec; + fn get_y_coords(&self) -> Vec; + fn get_z_coords(&self) -> Vec; + + fn move_relative(&self, x: f64, y: f64, z: f64) -> ArrayVoxelShape { + if self.shape().is_empty() { return Shapes::empty(); } + // TODO: just offset the vecs now instead of using an OffsetVec ArrayVoxelShape::new( - self.shape, - OffsetDoubleList::new(self.get_coords(Direction::Axis::X), x), - OffsetDoubleList::new(self.get_coords(Direction::Axis::Y), y), - OffsetDoubleList::new(self.get_coords(Direction::Axis::Z), z), + self.shape(), + self.get_x_coords().iter().map(|c| c + x).collect(), + self.get_y_coords().iter().map(|c| c + y).collect(), + self.get_z_coords().iter().map(|c| c + z).collect(), ) } } + +pub struct ArrayVoxelShape { + shape: Box, + faces: Option>>, + + pub xs: Vec, + pub ys: Vec, + pub zs: Vec, +} + +impl ArrayVoxelShape { + // ArrayVoxelShape(DiscreteVoxelShape var1, DoubleList var2, DoubleList var3, DoubleList var4) { + // super(var1); + // int var5 = var1.getXSize() + 1; + // int var6 = var1.getYSize() + 1; + // int var7 = var1.getZSize() + 1; + // if (var5 == var2.size() && var6 == var3.size() && var7 == var4.size()) { + // this.xs = var2; + // this.ys = var3; + // this.zs = var4; + // } else { + // throw (IllegalArgumentException)Util.pauseInIde(new IllegalArgumentException("Lengths of point arrays must be consistent with the size of the VoxelShape.")); + // } + // } + pub fn new( + shape: Box, + xs: Vec, + ys: Vec, + zs: Vec, + ) -> Self { + let x_size = shape.x_size() + 1; + let y_size = shape.y_size() + 1; + let z_size = shape.z_size() + 1; + + // Lengths of point arrays must be consistent with the size of the VoxelShape. + assert_eq!(x_size, xs.len()); + assert_eq!(y_size, ys.len()); + assert_eq!(z_size, zs.len()); + + Self { + faces: None, + shape, + xs, + ys, + zs, + } + } +} + +// mojang moment +// this is probably for an optimization and could probably be optimized more +/// A Vec that adds the given offset when indexing into it. +pub struct OffsetVec { + delegate: Vec, + offset: T, +} + +impl OffsetVec +where + T: Add, +{ + pub fn new(delegate: Vec, offset: T) -> Self { + Self { delegate, offset } + } + pub fn index(&self, index: usize) -> T { + self.delegate[index] + self.offset + } + pub fn len(&self) -> usize { + self.delegate.len() + } +}