From a0aa51df78b7f7362395ac687a6f83386025440f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20V=C3=B6gele?= Date: Thu, 3 Mar 2022 22:08:51 +0100 Subject: [PATCH] Use the correct token shape --- js/pathfinding.js | 32 +++++++++++++++++--------------- js/util.js | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/js/pathfinding.js b/js/pathfinding.js index 1c36b79..325d806 100644 --- a/js/pathfinding.js +++ b/js/pathfinding.js @@ -2,14 +2,15 @@ import {getCenterFromGridPositionObj, getGridPositionFromPixelsObj, getPixelsFro import {moveWithoutAnimation, togglePathfinding} from "./keybindings.js"; import {debugGraphics} from "./main.js"; import {settingsKey} from "./settings.js"; -import {getSnapPointForTokenObj, iterPairs} from "./util.js"; +import {getSnapPointForTokenObj, getTokenShape, getTokenShapeId, iterPairs} from "./util.js"; import * as GridlessPathfinding from "../wasm/gridless_pathfinding.js"; import {PriorityQueueSet} from "./data_structures.js"; import { buildCostFunction } from "./api.js"; import { measure } from "./foundry_imports.js"; -let cachedNodes = undefined; +// TODO Account for changing terrain per token in the caches +let caches = new Map(); let cacheElevation; let use5105 = false; let gridlessPathfinders = new Map(); @@ -53,8 +54,7 @@ export function findPath(from, to, token, previousWaypoints) { let endNode = getCenterFromGridPositionObj(currentNode.node); let oldPath = [{ray: new Ray(startNode, middleNode)}, {ray: new Ray(middleNode, endNode)}]; let newPath = [{ray: new Ray(startNode, endNode)}]; - // TODO Use correct token shape - let costFunction = buildCostFunction(token, [{x: 0, y: 0}]); + let costFunction = buildCostFunction(token, getTokenShape(token)); // TODO Cache the used measurement for use in the next loop to improve performance let oldDistance = terrainRuler.measureDistances(oldPath, {costFunction}).reduce((a, b) => a + b); let newDistance = terrainRuler.measureDistances(newPath, {costFunction})[0]; @@ -84,15 +84,19 @@ export function findPath(from, to, token, previousWaypoints) { } function getNode(pos, token, initialize=true) { - if (!cachedNodes) - cachedNodes = new Array(gridHeight); - if (!cachedNodes[pos.y]) - cachedNodes[pos.y] = new Array(gridWidth); - if (!cachedNodes[pos.y][pos.x]) { - cachedNodes[pos.y][pos.x] = pos; + let shapeId = getTokenShapeId(token); + let cache = caches.get(shapeId); + if (!cache) { + cache = new Array(gridHeight); + caches.set(shapeId, cache); + } + if (!cache[pos.y]) + cache[pos.y] = new Array(gridWidth); + if (!cache[pos.y][pos.x]) { + cache[pos.y][pos.x] = pos; } - const node = cachedNodes[pos.y][pos.x]; + const node = cache[pos.y][pos.x]; if (initialize && !node.edges) { node.edges = []; for (const neighborPos of canvas.grid.grid.getNeighbors(pos.y, pos.x).map(([y, x]) => {return {x, y};})) { @@ -105,10 +109,8 @@ function getNode(pos, token, initialize=true) { const isDiagonal = node.x !== neighborPos.x && node.y !== neighborPos.y && canvas.grid.type === CONST.GRID_TYPES.SQUARE; let edgeCost; if (window.terrainRuler) { - // TODO Additional cache for each token shape - // TODO Use the correct token shape let ray = new Ray(getCenterFromGridPositionObj(neighborPos), getCenterFromGridPositionObj(pos)); - let measuredDistance = terrainRuler.measureDistances([{ray}], {costFunction: buildCostFunction(token, [{x: 0, y: 0}])})[0]; + let measuredDistance = terrainRuler.measureDistances([{ray}], {costFunction: buildCostFunction(token, getTokenShape(token))})[0]; edgeCost = Math.round(measuredDistance / canvas.dimensions.distance); if (ray.terrainRulerFinalState?.noDiagonals === 1) { edgeCost = 1.5; @@ -200,7 +202,7 @@ function stepCollidesWithWall(from, to, token) { } export function wipePathfindingCache() { - cachedNodes = undefined; + caches.clear(); for (const pathfinder of gridlessPathfinders.values()) { GridlessPathfinding.free(pathfinder); } diff --git a/js/util.js b/js/util.js index ebcb2a0..3937442 100644 --- a/js/util.js +++ b/js/util.js @@ -157,6 +157,31 @@ export function getAreaFromPositionAndShape(position, shape) { }); } + +export function getTokenShapeId(token) { + if (token.scene.data.gridType === CONST.GRID_TYPES.GRIDLESS) { + return "1"; + } + else if (token.scene.data.gridType === CONST.GRID_TYPES.SQUARE) { + return `${token.data.width}x${token.data.height}`; + } + else { + // Hex grids + if (game.modules.get("hex-size-support")?.active && CONFIG.hexSizeSupport.getAltSnappingFlag(token)) { + const borderSize = token.data.flags["hex-size-support"].borderSize; + + let inversionFlag = ""; + if (Boolean(CONFIG.hexSizeSupport.getAltOrientationFlag(token)) !== canvas.grid.grid.options.columns) + inversionFlag = "i"; + + return `${borderSize}${inversionFlag}`; + } + else { + return "1"; + } + } +} + export function getTokenShape(token) { if (token.scene.data.gridType === CONST.GRID_TYPES.GRIDLESS) { return [{x: 0, y: 0}]