Skip to content

Commit

Permalink
optimize pathfinder more
Browse files Browse the repository at this point in the history
  • Loading branch information
mat-1 committed Oct 2, 2023
1 parent d0505f7 commit 7b10e5c
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 35 deletions.
2 changes: 1 addition & 1 deletion azalea-brigadier/src/suggestion/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod suggestions;
mod suggestions_builder;
mod suggestions_builder;

use crate::context::StringRange;
#[cfg(feature = "azalea-buf")]
Expand Down
14 changes: 14 additions & 0 deletions azalea-core/src/position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,33 @@ use crate::resource_location::ResourceLocation;
macro_rules! vec3_impl {
($name:ident, $type:ty) => {
impl $name {
#[inline]
pub fn new(x: $type, y: $type, z: $type) -> Self {
Self { x, y, z }
}

/// Get the distance of this vector to the origin by doing `x^2 + y^2 +
/// z^2`.
#[inline]
pub fn length_sqr(&self) -> $type {
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()`.
#[inline]
pub fn distance_to_sqr(&self, other: &Self) -> $type {
(self - other).length_sqr()
}

#[inline]
pub fn horizontal_distance_sqr(&self) -> $type {
self.x * self.x + self.z * self.z
}

/// Return a new instance of this position with the y coordinate
/// decreased by the given number.
#[inline]
pub fn down(&self, y: $type) -> Self {
Self {
x: self.x,
Expand All @@ -46,6 +51,7 @@ macro_rules! vec3_impl {
}
/// Return a new instance of this position with the y coordinate
/// increased by the given number.
#[inline]
pub fn up(&self, y: $type) -> Self {
Self {
x: self.x,
Expand All @@ -54,6 +60,7 @@ macro_rules! vec3_impl {
}
}

#[inline]
pub fn dot(&self, other: Self) -> $type {
self.x * other.x + self.y * other.y + self.z * other.z
}
Expand All @@ -62,6 +69,7 @@ macro_rules! vec3_impl {
impl Add for &$name {
type Output = $name;

#[inline]
fn add(self, rhs: Self) -> Self::Output {
$name {
x: self.x + rhs.x,
Expand All @@ -74,12 +82,14 @@ macro_rules! vec3_impl {
impl Add for $name {
type Output = $name;

#[inline]
fn add(self, rhs: Self) -> Self::Output {
(&self).add(&rhs)
}
}

impl AddAssign for $name {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.x += rhs.x;
self.y += rhs.y;
Expand All @@ -89,6 +99,7 @@ macro_rules! vec3_impl {
impl Rem<$type> for $name {
type Output = Self;

#[inline]
fn rem(self, rhs: $type) -> Self::Output {
Self {
x: self.x % rhs,
Expand All @@ -102,6 +113,7 @@ macro_rules! vec3_impl {
type Output = $name;

/// Find the difference between two positions.
#[inline]
fn sub(self, other: Self) -> Self::Output {
Self::Output {
x: self.x - other.x,
Expand All @@ -113,6 +125,7 @@ macro_rules! vec3_impl {
impl Sub for $name {
type Output = Self;

#[inline]
fn sub(self, other: Self) -> Self::Output {
(&self).sub(&other)
}
Expand All @@ -121,6 +134,7 @@ macro_rules! vec3_impl {
impl Mul<$type> for $name {
type Output = Self;

#[inline]
fn mul(self, multiplier: $type) -> Self::Output {
Self {
x: self.x * multiplier,
Expand Down
14 changes: 14 additions & 0 deletions azalea-physics/src/collision/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ use once_cell::sync::Lazy;

pub trait BlockWithShape {
fn shape(&self) -> &'static VoxelShape;
/// Tells you whether the block has an empty shape.
///
/// This is slightly more efficient than calling `shape()` and comparing
/// against `EMPTY_SHAPE`.
fn is_shape_empty(&self) -> bool;
fn is_shape_full(&self) -> bool;
}

static SHAPE0: Lazy<VoxelShape> = Lazy::new(|| collision::EMPTY_SHAPE.clone());
Expand Down Expand Up @@ -8028,4 +8034,12 @@ impl BlockWithShape for BlockState {
_ => &SHAPE1,
}
}

fn is_shape_empty(&self) -> bool {
matches!(self.id, 0|25..=78|80..=111|1944..=1991|2004..=2010|2063..=2090|2355..=2872|2978..=4273|4278..=4285|4302..=4589|4662..=4681|4762..=5537|5626..=5651|5716..=5733|5738..=5772|5799..=5814|5859..=5863|5865..=5866|6813..=6998|7001..=7002|7005..=7006|7009..=7010|7013..=7014|7017..=7018|7021..=7022|7025..=7026|7385..=7388|7406|7521..=7664|7925|7928|8249|8252|8595..=8826|9143..=9174|9320..=9343|10367..=10398|10747..=11078|11310..=11311|11314..=11315|11318..=11319|11322..=11323|11326..=11327|11330..=11331|11334..=11335|11338..=11339|11342..=11343|11346..=11347|11350..=11351|11354..=11355|11358..=11359|11362..=11363|11366..=11367|11370..=11371|11374..=11375|11378..=11379|11382..=11383|11386..=11387|11390..=11391|11394..=11395|11398..=11399|11402..=11403|11406..=11407|11410..=11411|11414..=11415|11418..=11419|11422..=11423|11426..=11427|11430..=11431|11434..=11435|11438..=11439|11442..=11443|11446..=11447|11450..=11451|11454..=11455|11458..=11459|11462..=11463|11466..=11467|11470..=11471|11474..=11475|11478..=11479|11482..=11483|11486..=11487|11490..=11491|11494..=11495|11498..=11499|11502..=11503|11506..=11507|11510..=11511|11514..=11515|11518..=11519|11522..=11523|11526..=11527|11530..=11531|11534..=11535|11538..=11539|11542..=11543|11546..=11547|11550..=11551|11554..=11555|11558..=11559|11562..=11563|12495..=12496|12499|12501|12503|12505|12507..=12512|12514|12549|12760..=12786|12813..=12932|12944|12958..=12961|14166|14169|14490|14493|14814|14817|15138|15141|15462|15465|15786|15789|16110|16113|16434|16437|16758|16761|17082|17085|17406|17409|17730|17733|18054|18057|18575..=18578|18592|18594..=18595|18609|18611..=18665|18680..=18683|18876..=18877|18880..=18881|18884..=18885|18888..=18889|18892..=18893|18896..=18897|18900..=18901|18904..=18905|18908..=18909|18912..=18913|18916..=18917|18920..=18921|18924..=18925|18928..=18929|18932..=18933|18936..=18937|19100..=19147|19276..=19355|19547|19550|19967|19970|20372..=20397|20404|20407|21084|21566..=21693|22455..=22509|22513..=22528|22536..=22537|22544..=22545|22552..=22553|22560..=22587|22686|22689|23097|23100|23508|23511|23919|23922|24258)
}

fn is_shape_full(&self) -> bool {
matches!(self.id, 1..=24|79|112..=1687|1998..=2003|2017..=2022|2047..=2062|2091..=2354|2873|4274..=4277|4294..=4301|5734..=5737|5780..=5781|5798|5815..=5816|5849..=5850|5852..=5858|5864|5867..=5874|5946..=5961|6538..=6741|6812|7269..=7270|7272|7415|7417..=7418|7511..=7512|7665|7906..=7918|9223..=9224|9235..=9239|9344..=9371|10364..=10366|10463..=10465|10710..=10711|10716..=10717|10722..=10727|10744..=10746|11079..=11081|11166..=11167|11172..=11173|11178..=11179|11184..=11185|11190..=11191|11196..=11197|11202..=11203|11208..=11209|11214..=11215|11220..=11221|11226..=11227|11232..=11233|11238..=11239|11244..=11245|11250..=11251|11256..=11257|11262..=11263|11268..=11269|11274..=11275|11280..=11281|11286..=11287|11292..=11293|11298..=11299|11304..=11309|12404..=12413|12494|12515..=12548|12550..=12759|12787|12803..=12812|12941|14086..=14087|14092..=14093|14098..=14099|14104..=14105|14110..=14111|14116..=14117|14122..=14123|14128..=14129|14134..=14135|14140..=14141|14146..=14147|14152..=14153|14158..=14159|18404..=18437|18466|18579..=18591|18593|18596..=18608|18610|18666..=18667|18672..=18673|18678..=18679|19356..=19371|19381..=19444|19446..=19454|19459..=19460|19869..=19874|19879..=19880|20285|20370..=20371|20722..=20724|21031..=21032|21081..=21083|21565|21694..=21695|21704..=21713|22038..=22039|22044..=22045|22050..=22051|22056..=22065|22390..=22391|22396..=22397|22402..=22403|22408..=22409|22454|22529|22588|22590..=22593|22678..=22679|23004|23089..=23090|23415|23500..=23501|23826|23911..=23912|24237..=24246|24249..=24257|24259)
}
}
4 changes: 2 additions & 2 deletions azalea/src/pathfinder/moves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl<'a> PathfinderCtx<'a> {
// fast path
return true;
}
if block.shape() != &*collision::EMPTY_SHAPE {
if !block.is_shape_empty() {
return false;
}
if block == azalea_registry::Block::Water.into() {
Expand All @@ -107,7 +107,7 @@ impl<'a> PathfinderCtx<'a> {
// fast path
return false;
}
block.shape() == &*collision::BLOCK_SHAPE
block.is_shape_full()
}

/// Whether this block and the block above are passable
Expand Down
27 changes: 15 additions & 12 deletions azalea/src/pathfinder/moves/parkour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ fn parkour_forward_1_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<Edge> {
let gap_offset = BlockPos::new(dir.x(), 0, dir.z());
let offset = BlockPos::new(dir.x() * 2, 0, dir.z() * 2);

// make sure we actually have to jump
if ctx.is_block_solid(&(pos + gap_offset).down(1)) {
continue;
}
if !ctx.is_standable(&(pos + offset)) {
continue;
}
Expand All @@ -31,10 +35,6 @@ fn parkour_forward_1_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<Edge> {
if !ctx.is_block_passable(&(pos + gap_offset).up(2)) {
continue;
}
// make sure we actually have to jump
if ctx.is_block_solid(&(pos + gap_offset).down(1)) {
continue;
}
// make sure it's not a headhitter
if !ctx.is_block_passable(&pos.up(2)) {
continue;
Expand Down Expand Up @@ -64,6 +64,13 @@ fn parkour_forward_2_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<Edge> {
let gap_2_offset = BlockPos::new(dir.x() * 2, 0, dir.z() * 2);
let offset = BlockPos::new(dir.x() * 3, 0, dir.z() * 3);

// make sure we actually have to jump
if ctx.is_block_solid(&(pos + gap_1_offset).down(1))
|| ctx.is_block_solid(&(pos + gap_2_offset).down(1))
{
continue;
}

if !ctx.is_standable(&(pos + offset)) {
continue;
}
Expand All @@ -79,10 +86,6 @@ fn parkour_forward_2_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<Edge> {
if !ctx.is_block_passable(&(pos + gap_2_offset).up(2)) {
continue;
}
// make sure we actually have to jump
if ctx.is_block_solid(&(pos + gap_1_offset).down(1)) {
continue;
}
// make sure it's not a headhitter
if !ctx.is_block_passable(&pos.up(2)) {
continue;
Expand Down Expand Up @@ -114,6 +117,10 @@ fn parkour_headhitter_forward_1_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<
let gap_offset = BlockPos::new(dir.x(), 0, dir.z());
let offset = BlockPos::new(dir.x() * 2, 0, dir.z() * 2);

// make sure we actually have to jump
if ctx.is_block_solid(&(pos + gap_offset).down(1)) {
continue;
}
if !ctx.is_standable(&(pos + offset)) {
continue;
}
Expand All @@ -123,10 +130,6 @@ fn parkour_headhitter_forward_1_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<
if !ctx.is_block_passable(&(pos + gap_offset).up(2)) {
continue;
}
// make sure we actually have to jump
if ctx.is_block_solid(&(pos + gap_offset).down(1)) {
continue;
}
// make sure it is a headhitter
if !ctx.is_block_solid(&pos.up(2)) {
continue;
Expand Down
63 changes: 43 additions & 20 deletions codegen/lib/code/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,45 +72,35 @@ def generate_block_shapes_code(blocks: dict, shapes: dict, block_states_report,
for (shape_id, shape) in sorted(shapes.items(), key=lambda shape: int(shape[0])):
generated_shape_code += generate_code_for_shape(shape_id, shape)


# 1..100 | 200..300 => &SHAPE1,
generated_match_inner_code = ''
shape_ids_to_block_state_ids = {}
for block_id, shape_ids in blocks.items():
if isinstance(shape_ids, int):
shape_ids = [shape_ids]
block_report_data = block_states_report['minecraft:' + block_id]
block_data_burger = block_datas_burger[block_id]

for possible_state, shape_id in zip(block_report_data['states'], shape_ids):
block_state_id = possible_state['id']

if shape_id not in shape_ids_to_block_state_ids:
shape_ids_to_block_state_ids[shape_id] = []
shape_ids_to_block_state_ids[shape_id].append(block_state_id)

empty_shape_match_code = convert_ints_to_rust_ranges(shape_ids_to_block_state_ids[0])
block_shape_match_code = convert_ints_to_rust_ranges(shape_ids_to_block_state_ids[1])

# shape 1 is the most common so we have a _ => &SHAPE1 at the end
del shape_ids_to_block_state_ids[1]
for shape_id, block_state_ids in shape_ids_to_block_state_ids.items():

# convert them into ranges (so like 1|2|3 is 1..=3 instead)
block_state_ids_ranges = []
range_start_block_state_id = None
last_block_state_id = None
for block_state_id in sorted(block_state_ids):
if range_start_block_state_id is None:
range_start_block_state_id = block_state_id

if last_block_state_id is not None:
# check if the range is done
if block_state_id - 1 != last_block_state_id:
block_state_ids_ranges.append(f'{range_start_block_state_id}..={last_block_state_id}' if range_start_block_state_id != last_block_state_id else str(range_start_block_state_id))
range_start_block_state_id = block_state_id

last_block_state_id = block_state_id

block_state_ids_ranges.append(f'{range_start_block_state_id}..={last_block_state_id}' if range_start_block_state_id != last_block_state_id else str(range_start_block_state_id))
generated_match_inner_code += f'{"|".join(block_state_ids_ranges)} => &SHAPE{shape_id},\n'
for shape_id, block_state_ids in shape_ids_to_block_state_ids.items():
generated_match_inner_code += f'{convert_ints_to_rust_ranges(block_state_ids)} => &SHAPE{shape_id},\n'
generated_match_inner_code += '_ => &SHAPE1'

if empty_shape_match_code == '':
print('Error: shape 0 was not found')

return f'''
//! Autogenerated block collisions for every block
Expand All @@ -127,6 +117,11 @@ def generate_block_shapes_code(blocks: dict, shapes: dict, block_states_report,
pub trait BlockWithShape {{
fn shape(&self) -> &'static VoxelShape;
/// Tells you whether the block has an empty shape.
///
/// This is slightly more efficient than calling `shape()` and comparing against `EMPTY_SHAPE`.
fn is_shape_empty(&self) -> bool;
fn is_shape_full(&self) -> bool;
}}
{generated_shape_code}
Expand All @@ -137,6 +132,14 @@ def generate_block_shapes_code(blocks: dict, shapes: dict, block_states_report,
{generated_match_inner_code}
}}
}}
fn is_shape_empty(&self) -> bool {{
matches!(self.id, {empty_shape_match_code})
}}
fn is_shape_full(&self) -> bool {{
matches!(self.id, {block_shape_match_code})
}}
}}
'''

Expand Down Expand Up @@ -165,3 +168,23 @@ def make_arguments(part: list[float]):
code += '}\n'
code += '});\n'
return code

def convert_ints_to_rust_ranges(block_state_ids: list[int]) -> str:
# convert them into ranges (so like 1|2|3 is 1..=3 instead)
block_state_ids_ranges = []
range_start_block_state_id = None
last_block_state_id = None
for block_state_id in sorted(block_state_ids):
if range_start_block_state_id is None:
range_start_block_state_id = block_state_id

if last_block_state_id is not None:
# check if the range is done
if block_state_id - 1 != last_block_state_id:
block_state_ids_ranges.append(f'{range_start_block_state_id}..={last_block_state_id}' if range_start_block_state_id != last_block_state_id else str(range_start_block_state_id))
range_start_block_state_id = block_state_id

last_block_state_id = block_state_id

block_state_ids_ranges.append(f'{range_start_block_state_id}..={last_block_state_id}' if range_start_block_state_id != last_block_state_id else str(range_start_block_state_id))
return '|'.join(block_state_ids_ranges)

0 comments on commit 7b10e5c

Please sign in to comment.