refactor: simplify to time-sliced synchronous path queue
The async pathfinding with StandableBitGrid caused massive lag due to synchronous bounding box calculation in the main thread (millions of hashmap lookups for long paths). Additionally, the splicing logic had a catastrophic bug where it applied a single finished path to ALL entities unconditionally. Solution: - Revert to thread-local synchronous A* - Implement PathRequestQueue to process max 8 paths per frame - Keep provisional paths for immediate movement - Since entity walks provisional path, full path calculates from current position, eliminating the need for complex splicing logic.
This commit is contained in:
@@ -195,98 +195,3 @@ impl TileMap {
|
||||
self.floor_tiles.get_mut(pos)
|
||||
}
|
||||
}
|
||||
|
||||
/// Bit-packed bounding-box snapshot for async pathfinding.
|
||||
/// 1 bit per tile = ~6KB for 50,000 tiles vs HashMap overhead.
|
||||
/// Must be Send+Sync — no RefCell, no Arc.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StandableBitGrid {
|
||||
pub origin: IVec3,
|
||||
pub size: UVec3,
|
||||
pub bits: Vec<u64>,
|
||||
}
|
||||
|
||||
impl StandableBitGrid {
|
||||
/// Create a bit-grid snapshot of all standable tiles within bounding box.
|
||||
/// origin: min corner (inclusive), snapped to ITILE_SIZE
|
||||
/// size: dimensions in tiles (not pixels)
|
||||
pub fn new(origin: IVec3, size: UVec3, tilemap: &TileMap) -> Self {
|
||||
let total_bits = (size.x * size.y * size.z) as usize;
|
||||
let words = (total_bits + 63) / 64;
|
||||
let mut bits = vec![0u64; words];
|
||||
|
||||
for bz in 0..size.z {
|
||||
for by in 0..size.y {
|
||||
for bx in 0..size.x {
|
||||
let pos = IVec3::new(
|
||||
origin.x + (bx as i32) * ITILE_SIZE,
|
||||
origin.y + (by as i32) * ITILE_SIZE,
|
||||
origin.z + (bz as i32) * ITILE_SIZE,
|
||||
);
|
||||
if Self::tile_is_standable(tilemap, pos) {
|
||||
let idx = ((bz * size.y * size.x) + (by * size.x) + bx) as usize;
|
||||
bits[idx / 64] |= 1u64 << (idx % 64);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self { origin, size, bits }
|
||||
}
|
||||
|
||||
/// Standable check using TileMap (mirrors pathfinding.rs::is_standable_tile)
|
||||
#[inline]
|
||||
fn tile_is_standable(tilemap: &TileMap, pos: IVec3) -> bool {
|
||||
let can_stand_in_tile = tilemap
|
||||
.floor_tiles
|
||||
.get(&pos)
|
||||
.map(|t| t.can_stand_in())
|
||||
.unwrap_or(false);
|
||||
let can_stand_in_fixture = tilemap
|
||||
.fixture_tiles
|
||||
.get(&pos)
|
||||
.map(|t| t.can_stand_in())
|
||||
.unwrap_or(false);
|
||||
let pos_below = pos - IVec3::new(0, 0, ITILE_SIZE);
|
||||
let can_stand_on_tile_below = tilemap
|
||||
.floor_tiles
|
||||
.get(&pos_below)
|
||||
.map(|t| t.can_stand_on())
|
||||
.unwrap_or(false);
|
||||
let can_stand_on_fixture_below = tilemap
|
||||
.fixture_tiles
|
||||
.get(&pos_below)
|
||||
.map(|t| t.can_stand_on())
|
||||
.unwrap_or(false);
|
||||
|
||||
(can_stand_in_tile || can_stand_in_fixture)
|
||||
&& (can_stand_on_tile_below || can_stand_on_fixture_below)
|
||||
}
|
||||
|
||||
/// O(1) standable check using bit-grid coordinates.
|
||||
#[inline]
|
||||
pub fn is_standable_at(&self, bx: u32, by: u32, bz: u32) -> bool {
|
||||
if bx >= self.size.x || by >= self.size.y || bz >= self.size.z {
|
||||
return false;
|
||||
}
|
||||
let idx = ((bz * self.size.y * self.size.x) + (by * self.size.x) + bx) as usize;
|
||||
self.bits[idx / 64] & (1u64 << (idx % 64)) != 0
|
||||
}
|
||||
|
||||
/// Convert IVec3 world position to bit-grid coordinates.
|
||||
/// Returns None if position is outside the grid bounds.
|
||||
#[inline]
|
||||
pub fn to_bit_coords(&self, pos: IVec3) -> Option<(u32, u32, u32)> {
|
||||
let local = pos - self.origin;
|
||||
if local.x < 0 || local.y < 0 || local.z < 0 {
|
||||
return None;
|
||||
}
|
||||
let bx = (local.x / ITILE_SIZE) as u32;
|
||||
let by = (local.y / ITILE_SIZE) as u32;
|
||||
let bz = (local.z / ITILE_SIZE) as u32;
|
||||
if bx >= self.size.x || by >= self.size.y || bz >= self.size.z {
|
||||
return None;
|
||||
}
|
||||
Some((bx, by, bz))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user