From c50a8662afeadfce50f64600efa497b07e9bce86 Mon Sep 17 00:00:00 2001 From: mat Date: Sun, 4 Jan 2026 22:06:06 -0300 Subject: better order for RelBlockPos and slightly cleanup calculate_cached_mining_costs_index --- azalea/src/pathfinder/rel_block_pos.rs | 6 ++++-- azalea/src/pathfinder/world.rs | 38 ++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 15 deletions(-) (limited to 'azalea/src') diff --git a/azalea/src/pathfinder/rel_block_pos.rs b/azalea/src/pathfinder/rel_block_pos.rs index b8e96041..65b61ffa 100644 --- a/azalea/src/pathfinder/rel_block_pos.rs +++ b/azalea/src/pathfinder/rel_block_pos.rs @@ -14,10 +14,12 @@ use azalea_core::position::BlockPos; #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(C)] pub struct RelBlockPos { - pub x: i16, - pub z: i16, /// The actual non-relative Y coordinate of the block. pub y: i32, + /// The X coordinate of the block, relative to some origin. + pub x: i16, + /// The Y coordinate of the block, relative to some origin. + pub z: i16, } impl RelBlockPos { diff --git a/azalea/src/pathfinder/world.rs b/azalea/src/pathfinder/world.rs index 819e4254..a44af6b5 100644 --- a/azalea/src/pathfinder/world.rs +++ b/azalea/src/pathfinder/world.rs @@ -108,8 +108,11 @@ impl CachedWorld { cached_blocks: Default::default(), // this uses about 12mb of memory. it *really* helps though. cached_mining_costs: UnsafeCell::new( - vec![(RelBlockPos::new(i16::MAX, i32::MAX, i16::MAX), 0.); 2usize.pow(20)] - .into_boxed_slice(), + vec![ + (RelBlockPos::new(i16::MAX, i32::MAX, i16::MAX), 0.); + CACHED_MINING_COSTS_SIZE + ] + .into_boxed_slice(), ), } } @@ -314,7 +317,7 @@ impl CachedWorld { let cached_mining_costs = unsafe { &mut *self.cached_mining_costs.get() }; // 20 bits total: // 8 bits for x, 4 bits for y, 8 bits for z - let hash_index = Self::calculate_cached_mining_costs_index(pos); + let hash_index = calculate_cached_mining_costs_index(pos); let &(cached_pos, potential_cost) = unsafe { cached_mining_costs.get_unchecked(hash_index) }; if cached_pos == pos { @@ -329,16 +332,6 @@ impl CachedWorld { cost } - fn calculate_cached_mining_costs_index(pos: RelBlockPos) -> usize { - // 20 bits total: - // 8 bits for x, 8 bits for z, 4 bits for y - let hash_index = ((pos.x as usize & 0xff) << 12) - | ((pos.z as usize & 0xff) << 4) - | (pos.y as usize & 0xf); - debug_assert!(hash_index < 1048576); - hash_index - } - fn uncached_cost_for_breaking_block( &self, pos: RelBlockPos, @@ -526,6 +519,25 @@ impl CachedWorld { } } +const CACHED_MINING_COSTS_SIZE: usize = 2usize.pow(20); +fn calculate_cached_mining_costs_index(pos: RelBlockPos) -> usize { + // create a 20-bit index by taking the bottom bits from each axis + + const X_BITS: usize = 8; + const Y_BITS: usize = 3; + const Z_BITS: usize = 8; + + const X_MASK: usize = (1 << X_BITS) - 1; + const Y_MASK: usize = (1 << Y_BITS) - 1; + const Z_MASK: usize = (1 << Z_BITS) - 1; + + let hash_index = ((pos.x as usize & X_MASK) << (Y_BITS + Z_BITS)) + | ((pos.z as usize & Z_MASK) << Y_BITS) + | (pos.y as usize & Y_MASK); + debug_assert!(hash_index < CACHED_MINING_COSTS_SIZE); + hash_index +} + /// Whether our client could pass through this block. pub fn is_block_state_passable(block_state: BlockState) -> bool { // i already tried optimizing this by having it cache in an IntMap/FxHashMap but -- cgit v1.2.3