mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
reduce allocations for collision detection
This commit is contained in:
parent
018ab55bdb
commit
e47dee388e
7 changed files with 90 additions and 92 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -460,6 +460,7 @@ dependencies = [
|
|||
"nohash-hasher",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
"uuid",
|
||||
]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue