Skip to content

Commit

Permalink
BLAZINGLY FAST 🚀🚀🚀 pathfinding
Browse files Browse the repository at this point in the history
  • Loading branch information
mat-1 committed Oct 5, 2023
1 parent a060fff commit c2fb991
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 58 deletions.
93 changes: 81 additions & 12 deletions azalea-core/src/position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ impl ChunkSectionPos {
}
/// The coordinates of a block inside a chunk.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[repr(align(8))]
pub struct ChunkBlockPos {
pub x: u8,
pub y: i32,
Expand All @@ -273,9 +274,33 @@ impl ChunkBlockPos {
}
}

impl Hash for ChunkBlockPos {
// optimized hash that only calls hash once
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
u64::from(*self).hash(state);
}
}
impl From<ChunkBlockPos> for u64 {
#[inline]
fn from(pos: ChunkBlockPos) -> Self {
// convert to u64
let mut val: u64 = 0;
// first 32 bits are y
val |= pos.y as u64;
// next 8 bits are z
val |= (pos.z as u64) << 32;
// last 8 bits are x
val |= (pos.x as u64) << 40;
val
}
}
impl nohash_hasher::IsEnabled for ChunkBlockPos {}

/// The coordinates of a block inside a chunk section. Each coordinate must be
/// in the range [0, 15].
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[repr(align(4))]
pub struct ChunkSectionBlockPos {
pub x: u8,
pub y: u8,
Expand All @@ -294,6 +319,28 @@ impl Add<ChunkSectionBlockPos> for ChunkSectionPos {
)
}
}
impl Hash for ChunkSectionBlockPos {
// optimized hash that only calls hash once
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
u16::from(*self).hash(state);
}
}

impl From<ChunkSectionBlockPos> for u16 {
#[inline]
fn from(pos: ChunkSectionBlockPos) -> Self {
let mut val: u16 = 0;
// first 4 bits are z
val |= pos.z as u16;
// next 4 bits are y
val |= (pos.y as u16) << 4;
// last 4 bits are x
val |= (pos.x as u16) << 8;
val
}
}
impl nohash_hasher::IsEnabled for ChunkSectionBlockPos {}

/// A block pos with an attached world
#[derive(Debug, Clone)]
Expand All @@ -312,22 +359,33 @@ impl From<&BlockPos> for ChunkPos {
}
}
}
impl From<BlockPos> for ChunkPos {
#[inline]
fn from(pos: BlockPos) -> Self {
ChunkPos {
x: pos.x.div_floor(16),
z: pos.z.div_floor(16),
}
}
}

impl From<BlockPos> for ChunkSectionPos {
#[inline]
fn from(pos: BlockPos) -> Self {
ChunkSectionPos {
x: pos.x.div_floor(16),
y: pos.y.div_floor(16),
z: pos.z.div_floor(16),
x: pos.x >> 4,
y: pos.y >> 4,
z: pos.z >> 4,
}
}
}
impl From<&BlockPos> for ChunkSectionPos {
#[inline]
fn from(pos: &BlockPos) -> Self {
ChunkSectionPos {
x: pos.x.div_floor(16),
y: pos.y.div_floor(16),
z: pos.z.div_floor(16),
x: pos.x >> 4,
y: pos.y >> 4,
z: pos.z >> 4,
}
}
}
Expand All @@ -348,17 +406,28 @@ impl From<&BlockPos> for ChunkBlockPos {
}
}
}

impl From<&BlockPos> for ChunkSectionBlockPos {
fn from(pos: &BlockPos) -> Self {
ChunkSectionBlockPos {
impl From<BlockPos> for ChunkBlockPos {
#[inline]
fn from(pos: BlockPos) -> Self {
ChunkBlockPos {
x: pos.x.rem_euclid(16) as u8,
y: pos.y.rem_euclid(16) as u8,
y: pos.y,
z: pos.z.rem_euclid(16) as u8,
}
}
}

impl From<BlockPos> for ChunkSectionBlockPos {
#[inline]
fn from(pos: BlockPos) -> Self {
ChunkSectionBlockPos {
x: pos.x as u8 & 0xF,
y: pos.y as u8 & 0xF,
z: pos.z as u8 & 0xF,
}
}
}

impl From<&ChunkBlockPos> for ChunkSectionBlockPos {
#[inline]
fn from(pos: &ChunkBlockPos) -> Self {
Expand Down Expand Up @@ -529,7 +598,7 @@ mod tests {
fn test_into_chunk_section_block_pos() {
let block_pos = BlockPos::new(0, -60, 0);
assert_eq!(
ChunkSectionBlockPos::from(&block_pos),
ChunkSectionBlockPos::from(block_pos),
ChunkSectionBlockPos::new(0, 4, 0)
);
}
Expand Down
20 changes: 10 additions & 10 deletions azalea/src/pathfinder/moves/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
use super::{default_is_reached, Edge, ExecuteCtx, IsReachedCtx, MoveData, PathfinderCtx};

pub fn basic_move(ctx: &PathfinderCtx, node: BlockPos) -> Vec<Edge> {
let mut edges = Vec::new();
let mut edges = Vec::with_capacity(8);
edges.extend(forward_move(ctx, node));
edges.extend(ascend_move(ctx, node));
edges.extend(descend_move(ctx, node));
Expand All @@ -27,7 +27,7 @@ fn forward_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<Edge> {
for dir in CardinalDirection::iter() {
let offset = BlockPos::new(dir.x(), 0, dir.z());

if !ctx.is_standable(&(pos + offset)) {
if !ctx.is_standable(pos + offset) {
continue;
}

Expand Down Expand Up @@ -73,10 +73,10 @@ fn ascend_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<Edge> {
for dir in CardinalDirection::iter() {
let offset = BlockPos::new(dir.x(), 1, dir.z());

if !ctx.is_block_passable(&pos.up(2)) {
if !ctx.is_block_passable(pos.up(2)) {
continue;
}
if !ctx.is_standable(&(pos + offset)) {
if !ctx.is_standable(pos + offset) {
continue;
}

Expand Down Expand Up @@ -157,18 +157,18 @@ fn descend_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<Edge> {
for dir in CardinalDirection::iter() {
let dir_delta = BlockPos::new(dir.x(), 0, dir.z());
let new_horizontal_position = pos + dir_delta;
let fall_distance = ctx.fall_distance(&new_horizontal_position);
let fall_distance = ctx.fall_distance(new_horizontal_position);
if fall_distance == 0 || fall_distance > 3 {
continue;
}
let new_position = new_horizontal_position.down(fall_distance as i32);

// check whether 3 blocks vertically forward are passable
if !ctx.is_passable(&new_horizontal_position) {
if !ctx.is_passable(new_horizontal_position) {
continue;
}
// check whether we can stand on the target position
if !ctx.is_standable(&new_position) {
if !ctx.is_standable(new_position) {
continue;
}

Expand Down Expand Up @@ -266,16 +266,16 @@ fn diagonal_move(ctx: &PathfinderCtx, pos: BlockPos) -> Vec<Edge> {
let right = dir.right();
let offset = BlockPos::new(dir.x() + right.x(), 0, dir.z() + right.z());

if !ctx.is_passable(&BlockPos::new(pos.x + dir.x(), pos.y, pos.z + dir.z()))
&& !ctx.is_passable(&BlockPos::new(
if !ctx.is_passable(BlockPos::new(pos.x + dir.x(), pos.y, pos.z + dir.z()))
&& !ctx.is_passable(BlockPos::new(
pos.x + dir.right().x(),
pos.y,
pos.z + dir.right().z(),
))
{
continue;
}
if !ctx.is_standable(&(pos + offset)) {
if !ctx.is_standable(pos + offset) {
continue;
}
// +0.001 so it doesn't unnecessarily go diagonal sometimes
Expand Down
Loading

0 comments on commit c2fb991

Please sign in to comment.