From 54cee52eb2aeb81429df698e4a9bb62e4a6fcd2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20V=C3=B6gele?= Date: Mon, 28 Feb 2022 22:48:15 +0100 Subject: [PATCH] Add support for the wall height module in the gridless pathfinder --- js/pathfinding.js | 6 ++-- rust/src/js_api.rs | 64 +++++++++++++++++++++++++++++++++++++++--- rust/src/pathfinder.rs | 5 +++- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/js/pathfinding.js b/js/pathfinding.js index d6db627..8754cdc 100644 --- a/js/pathfinding.js +++ b/js/pathfinding.js @@ -25,12 +25,12 @@ export function isPathfindingEnabled() { export function findPath(from, to, token, previousWaypoints) { checkCacheValid(token); - + if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) { let tokenSize = Math.max(token.data.width, token.data.height) * canvas.dimensions.size; let pathfinder = gridlessPathfinders.get(tokenSize); if (!pathfinder) { - pathfinder = GridlessPathfinding.initialize(canvas.walls.placeables, tokenSize); + pathfinder = GridlessPathfinding.initialize(canvas.walls.placeables, tokenSize, token.data.elevation, Boolean(game.modules.get("levels")?.active)); gridlessPathfinders.set(tokenSize, pathfinder); } paintGridlessPathfindingDebug(pathfinder); @@ -176,7 +176,7 @@ export function wipePathfindingCache() { * Check if the current cache is still suitable for the path we're about to find. If not, clear the cache */ function checkCacheValid(token) { - // If levels is enabled, the cache is invalid if it was made for a + // If levels is enabled, the cache is invalid if it was made for a if (game.modules.get("levels")?.active) { const tokenElevation = token.data.elevation; if (tokenElevation !== cacheElevation) { diff --git a/rust/src/js_api.rs b/rust/src/js_api.rs index 2d29d7c..c90a532 100644 --- a/rust/src/js_api.rs +++ b/rust/src/js_api.rs @@ -23,6 +23,8 @@ extern "C" { extern "C" { pub type JsWall; pub type JsWallData; + pub type JsWallFlags; + pub type JsWallHeight; #[wasm_bindgen(method, getter)] fn data(this: &JsWall) -> JsWallData; @@ -38,6 +40,18 @@ extern "C" { #[wasm_bindgen(method, getter, js_name = "move")] fn move_type(this: &JsWallData) -> WallSenseType; + + #[wasm_bindgen(method, getter)] + fn flags(this: &JsWallData) -> JsWallFlags; + + #[wasm_bindgen(method, getter, js_name = "wallHeight")] + fn wall_height(this: &JsWallFlags) -> Option; + + #[wasm_bindgen(method, getter, js_name = "wallHeightTop")] + fn top(this: &JsWallHeight) -> Option; + + #[wasm_bindgen(method, getter, js_name = "wallHeightBottom")] + fn bottom(this: &JsWallHeight) -> Option; } #[wasm_bindgen] @@ -120,6 +134,38 @@ impl TryFrom for WallSenseType { } } +#[derive(Debug, Copy, Clone)] +pub struct WallHeight { + pub top: f64, + pub bottom: f64, +} + +impl Default for WallHeight { + fn default() -> Self { + Self { + top: f64::INFINITY, + bottom: f64::NEG_INFINITY, + } + } +} + +impl From> for WallHeight { + fn from(height: Option) -> Self { + let height = height + .map(|height| (height.top(), height.bottom())) + .unwrap_or((None, None)); + let top = height.0.unwrap_or(WallHeight::default().top); + let bottom = height.1.unwrap_or(WallHeight::default().bottom); + Self { top, bottom } + } +} + +impl WallHeight { + pub fn contains(&self, height: f64) -> bool { + self.top >= height && self.bottom <= height + } +} + #[derive(Debug, Clone, Copy)] pub struct Wall { pub p1: Point, @@ -127,6 +173,7 @@ pub struct Wall { pub door_type: DoorType, pub door_state: DoorState, pub move_type: WallSenseType, + pub height: WallHeight, } impl Wall { @@ -136,6 +183,7 @@ impl Wall { door_type: DoorType, door_state: DoorState, move_type: WallSenseType, + height: WallHeight, ) -> Self { Self { p1, @@ -143,6 +191,7 @@ impl Wall { door_type, door_state, move_type, + height, } } @@ -156,29 +205,36 @@ impl Wall { } impl Wall { - fn from_js(wall: &JsWall) -> Self { + fn from_js(wall: &JsWall, enable_height: bool) -> Self { let data = wall.data(); let mut c = data.c(); c.iter_mut().for_each(|val| *val = val.round()); + let height = if enable_height { + data.flags().wall_height().into() + } + else { + WallHeight::default() + }; Self::new( Point::new(c[0], c[1]), Point::new(c[2], c[3]), data.door_type(), data.door_state(), data.move_type(), + height, ) } } #[allow(dead_code)] #[wasm_bindgen] -pub fn initialize(js_walls: Vec, token_size: f64) -> Pathfinder { +pub fn initialize(js_walls: Vec, token_size: f64, token_elevation: f64, enable_height: bool) -> Pathfinder { let mut walls = Vec::with_capacity(js_walls.len()); for wall in js_walls { let wall = JsWall::from(wall); - walls.push(Wall::from_js(&wall)); + walls.push(Wall::from_js(&wall, enable_height)); } - Pathfinder::initialize(walls, token_size) + Pathfinder::initialize(walls, token_size, token_elevation) } #[allow(dead_code)] diff --git a/rust/src/pathfinder.rs b/rust/src/pathfinder.rs index 1855b0a..89b37b8 100644 --- a/rust/src/pathfinder.rs +++ b/rust/src/pathfinder.rs @@ -148,7 +148,7 @@ pub struct Pathfinder { } impl Pathfinder { - pub fn initialize(walls: I, token_size: f64) -> Self + pub fn initialize(walls: I, token_size: f64, token_elevation: f64) -> Self where I: IntoIterator, { @@ -162,6 +162,9 @@ impl Pathfinder { if wall.is_door() && wall.is_open() { continue; } + if !wall.height.contains(token_elevation) { + continue; + } let x_diff = wall.p2.x - wall.p1.x; let y_diff = wall.p2.y - wall.p1.y; let p1_angle = y_diff.atan2(x_diff).rem_euclid(2.0 * PI);