mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
start optimizing pathfinder
This commit is contained in:
parent
994bac2c13
commit
c3d27487ca
6 changed files with 89 additions and 102 deletions
|
@ -15,7 +15,7 @@ pub trait BlockWithShape {
|
|||
fn shape(&self) -> &'static VoxelShape;
|
||||
}
|
||||
|
||||
static SHAPE0: Lazy<VoxelShape> = Lazy::new(|| collision::empty_shape());
|
||||
static SHAPE0: Lazy<VoxelShape> = Lazy::new(|| collision::EMPTY_SHAPE.clone());
|
||||
static SHAPE1: Lazy<VoxelShape> = Lazy::new(|| collision::box_shape(0., 0., 0., 1., 1., 1.));
|
||||
static SHAPE2: Lazy<VoxelShape> =
|
||||
Lazy::new(|| collision::box_shape(0.4375, 0., 0.4375, 0.5625, 1., 0.5625));
|
||||
|
|
|
@ -6,15 +6,15 @@ use azalea_core::{
|
|||
math::{binary_search, EPSILON},
|
||||
position::{BlockPos, Vec3},
|
||||
};
|
||||
use std::{cmp, num::NonZeroU32};
|
||||
use std::{cmp, num::NonZeroU32, sync::LazyLock};
|
||||
|
||||
pub struct Shapes;
|
||||
|
||||
pub fn block_shape() -> VoxelShape {
|
||||
pub static BLOCK_SHAPE: LazyLock<VoxelShape> = LazyLock::new(|| {
|
||||
let mut shape = BitSetDiscreteVoxelShape::new(1, 1, 1);
|
||||
shape.fill(0, 0, 0);
|
||||
VoxelShape::Cube(CubeVoxelShape::new(DiscreteVoxelShape::BitSet(shape)))
|
||||
}
|
||||
});
|
||||
|
||||
pub fn box_shape(
|
||||
min_x: f64,
|
||||
|
@ -43,7 +43,7 @@ pub fn box_shape_unchecked(
|
|||
max_z: f64,
|
||||
) -> VoxelShape {
|
||||
if max_x - min_x < EPSILON && max_y - min_y < EPSILON && max_z - min_z < EPSILON {
|
||||
return empty_shape();
|
||||
return EMPTY_SHAPE.clone();
|
||||
}
|
||||
|
||||
let x_bits = find_bits(min_x, max_x);
|
||||
|
@ -52,14 +52,14 @@ pub fn box_shape_unchecked(
|
|||
|
||||
if x_bits < 0 || y_bits < 0 || z_bits < 0 {
|
||||
return VoxelShape::Array(ArrayVoxelShape::new(
|
||||
block_shape().shape(),
|
||||
BLOCK_SHAPE.shape(),
|
||||
vec![min_x, max_x],
|
||||
vec![min_y, max_y],
|
||||
vec![min_z, max_z],
|
||||
));
|
||||
}
|
||||
if x_bits == 0 && y_bits == 0 && z_bits == 0 {
|
||||
return block_shape();
|
||||
return BLOCK_SHAPE.clone();
|
||||
}
|
||||
|
||||
let x_bits = 1 << x_bits;
|
||||
|
@ -79,14 +79,14 @@ pub fn box_shape_unchecked(
|
|||
VoxelShape::Cube(CubeVoxelShape::new(DiscreteVoxelShape::BitSet(shape)))
|
||||
}
|
||||
|
||||
pub fn empty_shape() -> VoxelShape {
|
||||
pub static EMPTY_SHAPE: LazyLock<VoxelShape> = LazyLock::new(|| {
|
||||
VoxelShape::Array(ArrayVoxelShape::new(
|
||||
DiscreteVoxelShape::BitSet(BitSetDiscreteVoxelShape::new(0, 0, 0)),
|
||||
vec![0.],
|
||||
vec![0.],
|
||||
vec![0.],
|
||||
))
|
||||
}
|
||||
});
|
||||
|
||||
fn find_bits(min: f64, max: f64) -> i32 {
|
||||
if min < -EPSILON || max > 1. + EPSILON {
|
||||
|
@ -143,10 +143,18 @@ impl Shapes {
|
|||
let op_true_false = op(true, false);
|
||||
let op_false_true = op(false, true);
|
||||
if a.is_empty() {
|
||||
return if op_false_true { b } else { empty_shape() };
|
||||
return if op_false_true {
|
||||
b
|
||||
} else {
|
||||
EMPTY_SHAPE.clone()
|
||||
};
|
||||
}
|
||||
if b.is_empty() {
|
||||
return if op_true_false { a } else { empty_shape() };
|
||||
return if op_true_false {
|
||||
a
|
||||
} else {
|
||||
EMPTY_SHAPE.clone()
|
||||
};
|
||||
}
|
||||
// IndexMerger var5 = createIndexMerger(1, a.getCoords(Direction.Axis.X),
|
||||
// b.getCoords(Direction.Axis.X), var3, var4); IndexMerger var6 =
|
||||
|
@ -360,7 +368,7 @@ impl VoxelShape {
|
|||
#[must_use]
|
||||
pub fn move_relative(&self, x: f64, y: f64, z: f64) -> VoxelShape {
|
||||
if self.shape().is_empty() {
|
||||
return empty_shape();
|
||||
return EMPTY_SHAPE.clone();
|
||||
}
|
||||
|
||||
VoxelShape::Array(ArrayVoxelShape::new(
|
||||
|
@ -510,24 +518,15 @@ impl VoxelShape {
|
|||
// return var1[0];
|
||||
// }
|
||||
fn optimize(&self) -> VoxelShape {
|
||||
// let mut var1 = empty_shape();
|
||||
// self.for_all_boxes(|var1x, var3, var5, var7, var9, var11| {
|
||||
// var1 = Shapes::join_unoptimized(
|
||||
// var1,
|
||||
// box_shape(var1x, var3, var5, var7, var9, var11),
|
||||
// |a, b| a || b,
|
||||
// );
|
||||
// });
|
||||
// var1
|
||||
let mut var1 = empty_shape();
|
||||
let mut shape = EMPTY_SHAPE.clone();
|
||||
self.for_all_boxes(|var1x, var3, var5, var7, var9, var11| {
|
||||
var1 = Shapes::join_unoptimized(
|
||||
var1.clone(),
|
||||
shape = Shapes::join_unoptimized(
|
||||
shape.clone(),
|
||||
box_shape(var1x, var3, var5, var7, var9, var11),
|
||||
|a, b| a || b,
|
||||
);
|
||||
});
|
||||
var1
|
||||
shape
|
||||
}
|
||||
|
||||
// public void forAllBoxes(Shapes.DoubleLineConsumer var1) {
|
||||
|
@ -703,7 +702,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_block_shape() {
|
||||
let shape = block_shape();
|
||||
let shape = &*BLOCK_SHAPE;
|
||||
assert_eq!(shape.shape().size(Axis::X), 1);
|
||||
assert_eq!(shape.shape().size(Axis::Y), 1);
|
||||
assert_eq!(shape.shape().size(Axis::Z), 1);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::Shapes;
|
||||
use super::{Shapes, BLOCK_SHAPE};
|
||||
use crate::collision::{BlockWithShape, VoxelShape, AABB};
|
||||
use azalea_block::BlockState;
|
||||
use azalea_core::{
|
||||
|
@ -8,7 +8,7 @@ use azalea_core::{
|
|||
};
|
||||
use azalea_world::{Chunk, Instance};
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
pub fn get_block_collisions(world: &Instance, aabb: AABB) -> BlockCollisions<'_> {
|
||||
BlockCollisions::new(world, aabb)
|
||||
|
@ -91,7 +91,7 @@ impl<'a> Iterator for BlockCollisions<'a> {
|
|||
let block_shape = block_state.shape();
|
||||
|
||||
// if it's a full block do a faster collision check
|
||||
if block_shape == &crate::collision::block_shape() {
|
||||
if block_shape == BLOCK_SHAPE.deref() {
|
||||
if !self.aabb.intersects_aabb(&AABB {
|
||||
min_x: item.pos.x as f64,
|
||||
min_y: item.pos.y as f64,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(lazy_cell)]
|
||||
|
||||
pub mod clip;
|
||||
pub mod collision;
|
||||
|
|
|
@ -35,35 +35,41 @@ impl Debug for MoveData {
|
|||
|
||||
/// whether this block is passable
|
||||
fn is_block_passable(pos: &BlockPos, world: &ChunkStorage) -> bool {
|
||||
if let Some(block) = world.get_block_state(pos) {
|
||||
if block.shape() != &collision::empty_shape() {
|
||||
return false;
|
||||
}
|
||||
if block == azalea_registry::Block::Water.into() {
|
||||
return false;
|
||||
}
|
||||
if block.waterlogged() {
|
||||
return false;
|
||||
}
|
||||
// block.waterlogged currently doesn't account for seagrass and some other water
|
||||
// blocks
|
||||
if block == azalea_registry::Block::Seagrass.into() {
|
||||
return false;
|
||||
}
|
||||
|
||||
block.shape() == &collision::empty_shape()
|
||||
} else {
|
||||
false
|
||||
let Some(block) = world.get_block_state(pos) else {
|
||||
return false;
|
||||
};
|
||||
if block.is_air() {
|
||||
// fast path
|
||||
return true;
|
||||
}
|
||||
if block.shape() != &*collision::EMPTY_SHAPE {
|
||||
return false;
|
||||
}
|
||||
if block == azalea_registry::Block::Water.into() {
|
||||
return false;
|
||||
}
|
||||
if block.waterlogged() {
|
||||
return false;
|
||||
}
|
||||
// block.waterlogged currently doesn't account for seagrass and some other water
|
||||
// blocks
|
||||
if block == azalea_registry::Block::Seagrass.into() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// whether this block has a solid hitbox (i.e. we can stand on it)
|
||||
fn is_block_solid(pos: &BlockPos, world: &ChunkStorage) -> bool {
|
||||
if let Some(block) = world.get_block_state(pos) {
|
||||
block.shape() == &collision::block_shape()
|
||||
} else {
|
||||
false
|
||||
let Some(block) = world.get_block_state(pos) else {
|
||||
return false;
|
||||
};
|
||||
if block.is_air() {
|
||||
// fast path
|
||||
return false;
|
||||
}
|
||||
block.shape() == &*collision::BLOCK_SHAPE
|
||||
}
|
||||
|
||||
/// Whether this block and the block above are passable
|
||||
|
@ -143,25 +149,20 @@ mod tests {
|
|||
#[test]
|
||||
fn test_is_passable() {
|
||||
let mut partial_world = PartialInstance::default();
|
||||
let mut chunk_storage = ChunkStorage::default();
|
||||
let mut world = ChunkStorage::default();
|
||||
|
||||
partial_world.chunks.set(
|
||||
&ChunkPos { x: 0, z: 0 },
|
||||
Some(Chunk::default()),
|
||||
&mut chunk_storage,
|
||||
);
|
||||
partial_world
|
||||
.chunks
|
||||
.set(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()), &mut world);
|
||||
partial_world.chunks.set_block_state(
|
||||
&BlockPos::new(0, 0, 0),
|
||||
azalea_registry::Block::Stone.into(),
|
||||
&chunk_storage,
|
||||
);
|
||||
partial_world.chunks.set_block_state(
|
||||
&BlockPos::new(0, 1, 0),
|
||||
BlockState::AIR,
|
||||
&chunk_storage,
|
||||
&world,
|
||||
);
|
||||
partial_world
|
||||
.chunks
|
||||
.set_block_state(&BlockPos::new(0, 1, 0), BlockState::AIR, &world);
|
||||
|
||||
let world = chunk_storage.into();
|
||||
assert!(!is_block_passable(&BlockPos::new(0, 0, 0), &world));
|
||||
assert!(is_block_passable(&BlockPos::new(0, 1, 0), &world));
|
||||
}
|
||||
|
@ -169,24 +170,19 @@ mod tests {
|
|||
#[test]
|
||||
fn test_is_solid() {
|
||||
let mut partial_world = PartialInstance::default();
|
||||
let mut chunk_storage = ChunkStorage::default();
|
||||
partial_world.chunks.set(
|
||||
&ChunkPos { x: 0, z: 0 },
|
||||
Some(Chunk::default()),
|
||||
&mut chunk_storage,
|
||||
);
|
||||
let mut world = ChunkStorage::default();
|
||||
partial_world
|
||||
.chunks
|
||||
.set(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()), &mut world);
|
||||
partial_world.chunks.set_block_state(
|
||||
&BlockPos::new(0, 0, 0),
|
||||
azalea_registry::Block::Stone.into(),
|
||||
&chunk_storage,
|
||||
);
|
||||
partial_world.chunks.set_block_state(
|
||||
&BlockPos::new(0, 1, 0),
|
||||
BlockState::AIR,
|
||||
&chunk_storage,
|
||||
&world,
|
||||
);
|
||||
partial_world
|
||||
.chunks
|
||||
.set_block_state(&BlockPos::new(0, 1, 0), BlockState::AIR, &world);
|
||||
|
||||
let world = chunk_storage.into();
|
||||
assert!(is_block_solid(&BlockPos::new(0, 0, 0), &world));
|
||||
assert!(!is_block_solid(&BlockPos::new(0, 1, 0), &world));
|
||||
}
|
||||
|
@ -194,34 +190,25 @@ mod tests {
|
|||
#[test]
|
||||
fn test_is_standable() {
|
||||
let mut partial_world = PartialInstance::default();
|
||||
let mut chunk_storage = ChunkStorage::default();
|
||||
partial_world.chunks.set(
|
||||
&ChunkPos { x: 0, z: 0 },
|
||||
Some(Chunk::default()),
|
||||
&mut chunk_storage,
|
||||
);
|
||||
let mut world = ChunkStorage::default();
|
||||
partial_world
|
||||
.chunks
|
||||
.set(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()), &mut world);
|
||||
partial_world.chunks.set_block_state(
|
||||
&BlockPos::new(0, 0, 0),
|
||||
azalea_registry::Block::Stone.into(),
|
||||
&chunk_storage,
|
||||
);
|
||||
partial_world.chunks.set_block_state(
|
||||
&BlockPos::new(0, 1, 0),
|
||||
BlockState::AIR,
|
||||
&chunk_storage,
|
||||
);
|
||||
partial_world.chunks.set_block_state(
|
||||
&BlockPos::new(0, 2, 0),
|
||||
BlockState::AIR,
|
||||
&chunk_storage,
|
||||
);
|
||||
partial_world.chunks.set_block_state(
|
||||
&BlockPos::new(0, 3, 0),
|
||||
BlockState::AIR,
|
||||
&chunk_storage,
|
||||
&world,
|
||||
);
|
||||
partial_world
|
||||
.chunks
|
||||
.set_block_state(&BlockPos::new(0, 1, 0), BlockState::AIR, &world);
|
||||
partial_world
|
||||
.chunks
|
||||
.set_block_state(&BlockPos::new(0, 2, 0), BlockState::AIR, &world);
|
||||
partial_world
|
||||
.chunks
|
||||
.set_block_state(&BlockPos::new(0, 3, 0), BlockState::AIR, &world);
|
||||
|
||||
let world = chunk_storage.into();
|
||||
assert!(is_standable(&BlockPos::new(0, 1, 0), &world));
|
||||
assert!(!is_standable(&BlockPos::new(0, 0, 0), &world));
|
||||
assert!(!is_standable(&BlockPos::new(0, 2, 0), &world));
|
||||
|
|
|
@ -148,7 +148,7 @@ def generate_code_for_shape(shape_id: str, parts: list[list[float]]):
|
|||
code += f'static SHAPE{shape_id}: Lazy<VoxelShape> = Lazy::new(|| {{'
|
||||
steps = []
|
||||
if parts == ():
|
||||
steps.append('collision::empty_shape()')
|
||||
steps.append('collision::EMPTY_SHAPE.clone()')
|
||||
else:
|
||||
steps.append(f'collision::box_shape({make_arguments(parts[0])})')
|
||||
for part in parts[1:]:
|
||||
|
|
Loading…
Add table
Reference in a new issue