aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2024-02-25 22:31:56 -0600
committermat <git@matdoes.dev>2024-02-25 22:31:56 -0600
commite47dee388e1e7f051417244ab1c054f8b9acd755 (patch)
tree41c369fdcd967dc795ea66cb3a6c982c3dfd2d2f
parent018ab55bdb02e7774044198c8a30e0d02a7c6e29 (diff)
downloadazalea-drasl-e47dee388e1e7f051417244ab1c054f8b9acd755.tar.xz
reduce allocations for collision detection
-rw-r--r--Cargo.lock1
-rwxr-xr-xazalea-block/src/lib.rs2
-rw-r--r--azalea-physics/Cargo.toml1
-rwxr-xr-xazalea-physics/src/collision/discrete_voxel_shape.rs2
-rwxr-xr-xazalea-physics/src/collision/shape.rs71
-rw-r--r--azalea-physics/src/collision/world_collisions.rs23
-rw-r--r--azalea/benches/physics.rs82
7 files changed, 90 insertions, 92 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 168ac60b..6f228d2d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -460,6 +460,7 @@ dependencies = [
"nohash-hasher",
"once_cell",
"parking_lot",
+ "smallvec",
"tracing",
"uuid",
]
diff --git a/azalea-block/src/lib.rs b/azalea-block/src/lib.rs
index dc41b405..2a46fd01 100755
--- a/azalea-block/src/lib.rs
+++ b/azalea-block/src/lib.rs
@@ -59,6 +59,8 @@ impl BlockState {
state_id <= Self::max_state()
}
+ /// Returns true if the block is air. This only checks for normal air, not
+ /// other types like cave air.
#[inline]
pub fn is_air(&self) -> bool {
self == &Self::AIR
diff --git a/azalea-physics/Cargo.toml b/azalea-physics/Cargo.toml
index 043c0548..7b762896 100644
--- a/azalea-physics/Cargo.toml
+++ b/azalea-physics/Cargo.toml
@@ -21,6 +21,7 @@ tracing = "0.1.40"
once_cell = "1.19.0"
parking_lot = "^0.12.1"
nohash-hasher = "0.2.0"
+smallvec = "1.13.1"
[dev-dependencies]
bevy_time = "0.13.0"
diff --git a/azalea-physics/src/collision/discrete_voxel_shape.rs b/azalea-physics/src/collision/discrete_voxel_shape.rs
index f63b7c2a..211e6303 100755
--- a/azalea-physics/src/collision/discrete_voxel_shape.rs
+++ b/azalea-physics/src/collision/discrete_voxel_shape.rs
@@ -13,6 +13,7 @@ pub enum DiscreteVoxelShape {
}
impl DiscreteVoxelShape {
+ #[inline]
pub fn size(&self, axis: Axis) -> u32 {
match self {
DiscreteVoxelShape::BitSet(shape) => shape.size(axis),
@@ -305,6 +306,7 @@ impl BitSetDiscreteVoxelShape {
}
impl BitSetDiscreteVoxelShape {
+ #[inline]
fn size(&self, axis: Axis) -> u32 {
axis.choose(self.x_size, self.y_size, self.z_size)
}
diff --git a/azalea-physics/src/collision/shape.rs b/azalea-physics/src/collision/shape.rs
index 41ade73c..56befa39 100755
--- a/azalea-physics/src/collision/shape.rs
+++ b/azalea-physics/src/collision/shape.rs
@@ -169,22 +169,22 @@ impl Shapes {
// var5.getList(), var6.getList(), var7.getList()));
let var5 = Self::create_index_merger(
1,
- a.get_coords(Axis::X),
- b.get_coords(Axis::X),
+ a.get_coords(Axis::X).to_vec(),
+ b.get_coords(Axis::X).to_vec(),
op_true_false,
op_false_true,
);
let var6 = Self::create_index_merger(
(var5.size() - 1).try_into().unwrap(),
- a.get_coords(Axis::Y),
- b.get_coords(Axis::Y),
+ a.get_coords(Axis::Y).to_vec(),
+ b.get_coords(Axis::Y).to_vec(),
op_true_false,
op_false_true,
);
let var7 = Self::create_index_merger(
((var5.size() - 1) * (var6.size() - 1)).try_into().unwrap(),
- a.get_coords(Axis::Z),
- b.get_coords(Axis::Z),
+ a.get_coords(Axis::Z).to_vec(),
+ b.get_coords(Axis::Z).to_vec(),
op_true_false,
op_false_true,
);
@@ -233,22 +233,22 @@ impl Shapes {
let x_merger = Self::create_index_merger(
1,
- a.get_coords(Axis::X),
- b.get_coords(Axis::X),
+ a.get_coords(Axis::X).to_vec(),
+ b.get_coords(Axis::X).to_vec(),
op_true_false,
op_false_true,
);
let y_merger = Self::create_index_merger(
(x_merger.size() - 1) as i32,
- a.get_coords(Axis::Y),
- b.get_coords(Axis::Y),
+ a.get_coords(Axis::Y).to_vec(),
+ b.get_coords(Axis::Y).to_vec(),
op_true_false,
op_false_true,
);
let z_merger = Self::create_index_merger(
((x_merger.size() - 1) * (y_merger.size() - 1)) as i32,
- a.get_coords(Axis::Z),
- b.get_coords(Axis::Z),
+ a.get_coords(Axis::Z).to_vec(),
+ b.get_coords(Axis::Z).to_vec(),
op_true_false,
op_false_true,
);
@@ -361,7 +361,7 @@ impl VoxelShape {
}
}
- pub fn get_coords(&self, axis: Axis) -> Vec<f64> {
+ pub fn get_coords(&self, axis: Axis) -> &[f64] {
match self {
VoxelShape::Array(s) => s.get_coords(axis),
VoxelShape::Cube(s) => s.get_coords(axis),
@@ -625,6 +625,10 @@ pub struct CubeVoxelShape {
// TODO: check where faces is used in minecraft
#[allow(dead_code)]
faces: Option<Vec<VoxelShape>>,
+
+ x_coords: Vec<f64>,
+ y_coords: Vec<f64>,
+ z_coords: Vec<f64>,
}
impl ArrayVoxelShape {
@@ -634,9 +638,9 @@ impl ArrayVoxelShape {
let z_size = shape.size(Axis::Z) + 1;
// Lengths of point arrays must be consistent with the size of the VoxelShape.
- assert_eq!(x_size, xs.len() as u32);
- assert_eq!(y_size, ys.len() as u32);
- assert_eq!(z_size, zs.len() as u32);
+ debug_assert_eq!(x_size, xs.len() as u32);
+ debug_assert_eq!(y_size, ys.len() as u32);
+ debug_assert_eq!(z_size, zs.len() as u32);
Self {
faces: None,
@@ -648,19 +652,30 @@ impl ArrayVoxelShape {
}
}
-impl CubeVoxelShape {
- pub fn new(shape: DiscreteVoxelShape) -> Self {
- Self { shape, faces: None }
- }
-}
-
impl ArrayVoxelShape {
fn shape(&self) -> &DiscreteVoxelShape {
&self.shape
}
- fn get_coords(&self, axis: Axis) -> Vec<f64> {
- axis.choose(self.xs.clone(), self.ys.clone(), self.zs.clone())
+ fn get_coords(&self, axis: Axis) -> &[f64] {
+ axis.choose(&self.xs, &self.ys, &self.zs)
+ }
+}
+
+impl CubeVoxelShape {
+ pub fn new(shape: DiscreteVoxelShape) -> Self {
+ // pre-calculate the coor
+ let x_coords = Self::calculate_coords(&shape, Axis::X);
+ let y_coords = Self::calculate_coords(&shape, Axis::Y);
+ let z_coords = Self::calculate_coords(&shape, Axis::Z);
+
+ Self {
+ shape,
+ faces: None,
+ x_coords,
+ y_coords,
+ z_coords,
+ }
}
}
@@ -669,8 +684,8 @@ impl CubeVoxelShape {
&self.shape
}
- fn get_coords(&self, axis: Axis) -> Vec<f64> {
- let size = self.shape.size(axis);
+ fn calculate_coords(shape: &DiscreteVoxelShape, axis: Axis) -> Vec<f64> {
+ let size = shape.size(axis);
let mut parts = Vec::with_capacity(size as usize);
for i in 0..=size {
parts.push(i as f64 / size as f64);
@@ -678,6 +693,10 @@ impl CubeVoxelShape {
parts
}
+ fn get_coords(&self, axis: Axis) -> &[f64] {
+ axis.choose(&self.x_coords, &self.y_coords, &self.z_coords)
+ }
+
fn find_index(&self, axis: Axis, coord: f64) -> i32 {
let n = self.shape().size(axis);
(f64::clamp(coord * (n as f64), -1f64, n as f64)) as i32
diff --git a/azalea-physics/src/collision/world_collisions.rs b/azalea-physics/src/collision/world_collisions.rs
index cb721f00..8493b847 100644
--- a/azalea-physics/src/collision/world_collisions.rs
+++ b/azalea-physics/src/collision/world_collisions.rs
@@ -22,6 +22,7 @@ pub struct BlockCollisions<'a> {
pub only_suffocating_blocks: bool,
cached_sections: Vec<(ChunkSectionPos, azalea_world::Section)>,
+ cached_block_shapes: Vec<(BlockState, &'static VoxelShape)>,
}
impl<'a> BlockCollisions<'a> {
@@ -44,6 +45,7 @@ impl<'a> BlockCollisions<'a> {
only_suffocating_blocks: false,
cached_sections: Vec::new(),
+ cached_block_shapes: Vec::new(),
}
}
@@ -95,8 +97,27 @@ impl<'a> BlockCollisions<'a> {
self.cached_sections.push((section_pos, section.clone()));
+ // println!(
+ // "chunk section length: {}",
+ // section.states.storage.data.len()
+ // );
+ // println!("biome length: {}", section.biomes.storage.data.len());
+
section.get(section_block_pos)
}
+
+ fn get_block_shape(&mut self, block_state: BlockState) -> &'static VoxelShape {
+ for (cached_block_state, cached_shape) in &self.cached_block_shapes {
+ if block_state == *cached_block_state {
+ return cached_shape;
+ }
+ }
+
+ let shape = block_state.shape();
+ self.cached_block_shapes.push((block_state, shape));
+
+ shape
+ }
}
impl<'a> Iterator for BlockCollisions<'a> {
@@ -138,7 +159,7 @@ impl<'a> Iterator for BlockCollisions<'a> {
));
}
- let block_shape = block_state.shape();
+ let block_shape = self.get_block_shape(block_state);
let block_shape =
block_shape.move_relative(item.pos.x as f64, item.pos.y as f64, item.pos.z as f64);
diff --git a/azalea/benches/physics.rs b/azalea/benches/physics.rs
index 6f8dc7bc..0d4a3f2f 100644
--- a/azalea/benches/physics.rs
+++ b/azalea/benches/physics.rs
@@ -28,29 +28,22 @@ fn generate_world(partial_chunks: &mut PartialChunkStorage, size: u32) -> ChunkS
}
}
- // for chunk_x in -size..size {
- // for chunk_z in -size..size {
- // let chunk_pos = ChunkPos::new(chunk_x, chunk_z);
- // let chunk = chunks.get(&chunk_pos).unwrap();
- // let mut chunk = chunk.write();
- // for x in 0..16_u8 {
- // for z in 0..16_u8 {
- // chunk.set(
- // &ChunkBlockPos::new(x, 1, z),
- // azalea_registry::Block::Bedrock.into(),
- // chunks.min_y,
- // );
- // if rng.gen_bool(0.5) {
- // chunk.set(
- // &ChunkBlockPos::new(x, 2, z),
- // azalea_registry::Block::Bedrock.into(),
- // chunks.min_y,
- // );
- // }
- // }
- // }
- // }
- // }
+ for chunk_x in -size..size {
+ for chunk_z in -size..size {
+ let chunk_pos = ChunkPos::new(chunk_x, chunk_z);
+ let chunk = chunks.get(&chunk_pos).unwrap();
+ let mut chunk = chunk.write();
+ for x in 0..16_u8 {
+ for z in 0..16_u8 {
+ chunk.set(
+ &ChunkBlockPos::new(x, 1, z),
+ azalea_registry::Block::OakFence.into(),
+ chunks.min_y,
+ );
+ }
+ }
+ }
+ }
// let mut start = BlockPos::new(-64, 4, -64);
// // move start down until it's on a solid block
@@ -69,47 +62,6 @@ fn generate_world(partial_chunks: &mut PartialChunkStorage, size: u32) -> ChunkS
chunks
}
-fn generate_mining_world(
- partial_chunks: &mut PartialChunkStorage,
- size: u32,
-) -> (ChunkStorage, BlockPos, BlockPos) {
- let size = size as i32;
-
- let mut chunks = ChunkStorage::default();
- for chunk_x in -size..size {
- for chunk_z in -size..size {
- let chunk_pos = ChunkPos::new(chunk_x, chunk_z);
- partial_chunks.set(&chunk_pos, Some(Chunk::default()), &mut chunks);
- }
- }
-
- // let mut rng = StdRng::seed_from_u64(0);
-
- for chunk_x in -size..size {
- for chunk_z in -size..size {
- let chunk_pos = ChunkPos::new(chunk_x, chunk_z);
- let chunk = chunks.get(&chunk_pos).unwrap();
- let mut chunk = chunk.write();
- for y in chunks.min_y..(chunks.min_y + chunks.height as i32) {
- for x in 0..16_u8 {
- for z in 0..16_u8 {
- chunk.set(
- &ChunkBlockPos::new(x, y, z),
- azalea_registry::Block::Stone.into(),
- chunks.min_y,
- );
- }
- }
- }
- }
- }
-
- let start = BlockPos::new(-64, 4, -64);
- let end = BlockPos::new(0, 4, 0);
-
- (chunks, start, end)
-}
-
fn run_physics_benchmark(b: &mut Bencher<'_>) {
let mut partial_chunks = PartialChunkStorage::new(32);
@@ -126,7 +78,7 @@ fn run_physics_benchmark(b: &mut Bencher<'_>) {
// std::process::exit(0);
b.iter(|| {
- let entity = simulation_set.spawn(SimulatedPlayerBundle::new(Vec3::new(0.0, 4.0, 0.0)));
+ let entity = simulation_set.spawn(SimulatedPlayerBundle::new(Vec3::new(0.5, 2.0, 0.5)));
for _ in 0..20 {
simulation_set.tick();
}