diff --git a/js/pathfinding.js b/js/pathfinding.js index 35e533f..271a905 100644 --- a/js/pathfinding.js +++ b/js/pathfinding.js @@ -4,34 +4,45 @@ import {debugGraphics} from "./main.js"; import {settingsKey} from "./settings.js"; import {getSnapPointForTokenObj, iterPairs} from "./util.js"; +import * as GridlessPathfinding from "../wasm/gridless_pathfinding.js" + let cachedNodes = undefined; let use5105 = false; +let gridlessPathfinder = undefined; export function isPathfindingEnabled() { - if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) - return false; if (!game.settings.get(settingsKey, "allowPathfinding")) return false; return game.settings.get(settingsKey, "autoPathfinding") != togglePathfinding; } export function findPath(from, to, token, previousWaypoints) { - const lastNode = calculatePath(from, to, token, previousWaypoints); - if (!lastNode) - return null; - paintPathfindingDebug(lastNode, token); - const path = []; - let currentNode = lastNode; - while (currentNode) { - // TODO Check if the distance doesn't change - if (path.length >= 2 && !stepCollidesWithWall(currentNode.node, path[path.length - 2], token)) - // Replace last waypoint if the current waypoint leads to a valid path - path[path.length - 1] = {x: currentNode.node.x, y: currentNode.node.y}; - else - path.push({x: currentNode.node.x, y: currentNode.node.y}); - currentNode = currentNode.previous; + if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) { + if (!gridlessPathfinder) + gridlessPathfinder = GridlessPathfinding.initialize(canvas.walls.placeables); + paintGridlessPathfindingDebug(gridlessPathfinder); + const path = GridlessPathfinding.findPath(gridlessPathfinder, from, to); + console.warn(path); + return path; + } + else { + const lastNode = calculatePath(from, to, token, previousWaypoints); + if (!lastNode) + return null; + paintGriddedPathfindingDebug(lastNode, token); + const path = []; + let currentNode = lastNode; + while (currentNode) { + // TODO Check if the distance doesn't change + if (path.length >= 2 && !stepCollidesWithWall(currentNode.node, path[path.length - 2], token)) + // Replace last waypoint if the current waypoint leads to a valid path + path[path.length - 1] = {x: currentNode.node.x, y: currentNode.node.y}; + else + path.push({x: currentNode.node.x, y: currentNode.node.y}); + currentNode = currentNode.previous; + } + return path; } - return path; } export function wipePathfindingCache() { @@ -135,7 +146,7 @@ function stepCollidesWithWall(from, to, token) { return canvas.walls.checkCollision(new Ray(stepStart, stepEnd)); } -function paintPathfindingDebug(lastNode, token) { +function paintGriddedPathfindingDebug(lastNode, token) { if (!CONFIG.debug.dragRuler) return; @@ -151,3 +162,16 @@ function paintPathfindingDebug(lastNode, token) { currentNode = currentNode.previous; } } + +function paintGridlessPathfindingDebug(pathfinder) { + if (!CONFIG.debug.dragRuler) + return; + + debugGraphics.removeChildren(); + let graphic = new PIXI.Graphics(); + graphic.lineStyle(2, 0x440000); + for (const point of GridlessPathfinding.debugGetPathfindingPoints(pathfinder)) { + graphic.drawCircle(point.x, point.y, 5); + } + debugGraphics.addChild(graphic); +} diff --git a/rust/src/js_api.rs b/rust/src/js_api.rs index d65037e..68704fc 100644 --- a/rust/src/js_api.rs +++ b/rust/src/js_api.rs @@ -20,7 +20,7 @@ extern "C" { } #[wasm_bindgen( - inline_js = "export function collidesWithWall(p1, p2) { return canvas.walls.checkCollision(new Ray(p1, p2)); }" + inline_js = "export function collidesWithWall(p1, p2) { return canvas.walls.checkCollision(new Ray(p1, p2));}" )] extern "C" { #[wasm_bindgen(js_name=collidesWithWall)] @@ -39,6 +39,26 @@ extern "C" { fn c(this: &JsWallData) -> Vec; } +#[wasm_bindgen] +extern "C" { + pub type JsPoint; + + #[wasm_bindgen(method, getter)] + fn x(this: &JsPoint) -> f64; + + #[wasm_bindgen(method, getter)] + fn y(this: &JsPoint) -> f64; +} + +impl From for Point { + fn from(point: JsPoint) -> Self { + Point { + x: point.x(), + y: point.y(), + } + } +} + #[derive(Debug, Clone, Copy)] pub struct Wall { pub p1: Point, @@ -61,7 +81,7 @@ impl Wall { } #[allow(dead_code)] -#[wasm_bindgen(js_name=buildCache)] +#[wasm_bindgen] pub fn initialize(js_walls: Vec) -> Pathfinder { let mut walls = Vec::with_capacity(js_walls.len()); for wall in js_walls { @@ -79,14 +99,25 @@ pub fn free(pathfinder: Pathfinder) { #[allow(dead_code)] #[wasm_bindgen(js_name=findPath)] -pub fn find_path(pathfinder: &mut Pathfinder, from: Point, to: Point) -> Option { - if let Some(first_node) = pathfinder.find_path(from, to) { +pub fn find_path(pathfinder: &mut Pathfinder, from: JsPoint, to: JsPoint) -> Option { + if let Some(first_node) = pathfinder.find_path(from.into(), to.into()) { Some(first_node.iter_path().map(JsValue::from).collect()) } else { None } } +#[allow(dead_code)] +#[wasm_bindgen(js_name=debugGetPathfindingPoints)] +pub fn debug_get_pathfinding_points(pathfinder: &Pathfinder) -> Array { + pathfinder + .nodes + .iter() + .map(|node| node.borrow().point) + .map(JsValue::from) + .collect() +} + trait IteratePath { fn iter_path(&self) -> PathIterator; } diff --git a/rust/src/pathfinder.rs b/rust/src/pathfinder.rs index 8a26efb..e1f0948 100644 --- a/rust/src/pathfinder.rs +++ b/rust/src/pathfinder.rs @@ -83,6 +83,10 @@ impl NodeStorage { node.borrow_mut().edges = Some(edges); } + + pub fn iter(&self) -> std::slice::Iter<'_, NodePtr> { + self.0.iter() + } } #[wasm_bindgen]