Skip to content

Commit

Permalink
Merge branch 'release/0.10.10' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
caewok committed Sep 9, 2024
2 parents bc45ebb + 20aac11 commit 83b3a6a
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 42 deletions.
5 changes: 5 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 0.10.10
Improve how the pathfinding path is cleaned when snapping to grids to avoid weird backstepping issues. Should be a bit more aggressive in finding a viable grid-center path.
Don't pathfind around hidden tokens. Closes #200.
Fix for error re clone function not found when tracking combat move history. Closes #201.

# 0.10.9
Additional fix for 5-10-5 using 10-5-10 (the offset distance was not fixed previously). Closes #195, #196.
If the movement cost is rounded to 0, don't display the label. Closes #196.
Expand Down
5 changes: 3 additions & 2 deletions scripts/Ruler.js
Original file line number Diff line number Diff line change
Expand Up @@ -437,10 +437,11 @@ function _computeDistance() {
// - 3d path.
// - Add the offsetDistance property for determining changes due to terrain.
// - Calculate distance properties from nearest waypoint, for labeling.
const Point3d = CONFIG.GeometryLib.threeD.Point3d;
let path = [];
if ( this.segments.length ) path.push(this.segments[0].ray.A.clone());
if ( this.segments.length ) path.push(Point3d.fromObject(this.segments[0].ray.A));
for ( const segment of this.segments ) {
const B = segment.ray.B.clone();
const B = Point3d.fromObject(segment.ray.B);
B.teleport = segment.teleport;
path.push(B);
}
Expand Down
6 changes: 6 additions & 0 deletions scripts/pathfinding/WallTracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,13 @@ export class WallTracerEdge extends GraphEdge {
* @returns {boolean}
*/
static tokenEdgeBlocks(token, moveToken, tokenBlockType, elevation = 0) {
// Don't block hidden tokens.
if ( token.document.hidden ) return false;

// Don't block oneself.
if ( !moveToken || moveToken === token ) return false;

// Must be within the elevation bounds.
if ( !elevation.between(token.topZ, token.bottomZ) ) return false;

// Don't block dead tokens (HP <= 0).
Expand Down
102 changes: 62 additions & 40 deletions scripts/pathfinding/pathfinding.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { cdt2dConstrainedGraph, cdt2dToBorderTriangles } from "../delaunator/cdt
import { Settings } from "../settings.js";
import { MODULE_ID } from "../const.js";
import { MovePenalty } from "../measurement/MovePenalty.js";
import { GridCoordinates3d } from "../geometry/3d/GridCoordinates3d.js";


/* Testing
Expand Down Expand Up @@ -304,7 +304,7 @@ export class Pathfinder {
* @param {PathNode} current
*/
_heuristic(goal, current) {
const distance = GridCoordinates3d.gridDistanceBetween(goal.entryPoint, current.entryPoint);
const distance = CONFIG.GeometryLib.threeD.GridCoordinates3d.gridDistanceBetween(goal.entryPoint, current.entryPoint);
return CONFIG.GeometryLib.utils.gridUnitsToPixels(distance);
}

Expand Down Expand Up @@ -578,7 +578,7 @@ function alignPathToGrid(pathPoints, token) {
}

// Check dropping the connections between segments.
gridPoints = cleanSegmentConnections(gridPoints, token);
cleanSegmentGridConnections(gridPoints, token);

// Deduplicate the remaining points, combining into single array.
const deDupedPoints = new NoDupePointsArray();
Expand All @@ -589,40 +589,48 @@ function alignPathToGrid(pathPoints, token) {

/**
* Shorten connections between segments.
* Grid points are [a, gridPt0,... gridPt1, b].
* Next grid points are [b, gridPt0, ... gridPt1, c]
* If gridPt1 equals gridPt0, then can connect the two segments.
* Grid points are [gridPt0,... gridPt1, a].
* Next grid points are [a, gridPt0, ... gridPt1]
* Connect the b's, dropping all duplicates and converting to grid centers unles.
* @param {PIXI.Point[][]} gridPoints
* @returns {PIXI.Point[][]}
*/
function cleanSegmentConnections(gridPoints, token) {
function cleanSegmentGridConnections(gridPoints, token) {
// Drop empty arrays.
gridPoints = gridPoints.filter(arr => arr.length);

// Compare two of the point arrays and attempt to combine.
let prevPts = gridPoints[0];
for ( let i = 1, n = gridPoints.length; i < n; i += 1 ) {
const nextPts = gridPoints[i];
const a = prevPts.at(-2);
const b = prevPts.at(-1);
const c = nextPts.at(0);
const d = nextPts.at(1);
if ( !(b && c) ) {

// Examine 3 points into the segment at the linked ends.
const a0 = prevPts.at(-1);
const b0 = prevPts.at(-2); // 1, -2 may be undefined.
const a1 = nextPts.at(0);
const b1 = nextPts.at(1);

// If a0 and a1 are equal, can remove a0.
if ( !a0.x.almostEqual(a1.x) || !a0.y.almostEqual(a1.y) ) {
prevPts = nextPts;
continue;
}
prevPts.pop(); // Remove a0.

// If no collision between the next two points, can remove a1.
if ( !b0 || !b1 || hasCollision(b0, b1, token) ) {
prevPts = nextPts;
continue;
}
nextPts.shift(); // Remove a1.

// previous: [...a, b]
// next: [c, d, ...]
// Implicitly all below must have b && c.
if ( a && d && b.isEndpoint && c.isEndpoint && !hasCollision(a, d, token) ) {
// If b and c are endpoints, can drop both if there is no collision between a and d.
prevPts.pop();
nextPts.shift();
} else if ((b.x === c.x && b.y === c.y) // Either b or c is not an endpoint; drop b as both are equal.
|| (a && b.isEndpoint && !hasCollision(a, c, token)) ) prevPts.pop(); // Drop endpoint b.
else if ( d && c.isEndpoint && !hasCollision(b, d, token) ) nextPts.shift(); // Drop endpoint c.
if ( !b0.x.almostEqual(b1.x) || !b0.y.almostEqual(b1.y) ) {
prevPts = nextPts;
continue;
}
prevPts.pop(); // Remove b1.
prevPts = nextPts;

}
return gridPoints;
}
Expand All @@ -634,28 +642,42 @@ function cleanSegmentConnections(gridPoints, token) {
*/
function alignSegmentToGrid(a, b, token) {
if ( hasCollision(a, b, token) ) return [a, b];
const gridPoints = canvas.grid.getDirectPath([a, b]);
const allPoints = [a, ...gridPoints.map(pt => canvas.grid.getCenterPoint(pt)), b];

// Test if a --> b has collision. If so, change b to the line.
const testedSet = new Set();
let currA = allPoints[0];
for ( let i = 1, n = allPoints.length - 1; i < n; i += 1 ) {
const currB = allPoints[i];
if ( hasCollision(currA, currB, token) ) allPoints[i] = foundry.utils.closestPointToSegment(currB, a, b);
else testedSet.add(`${key(currA)}|${key(currB)}`);
}
const GridCoordinates = CONFIG.GeometryLib.GridCoordinates;
const gridPoints = canvas.grid.getDirectPath([a, b]);
const allPoints = [GridCoordinates.fromObject(a), ...gridPoints.map(offset => GridCoordinates.fromOffset(offset)), GridCoordinates.fromObject(b)];
const nPts = allPoints.length;
if ( nPts < 3 ) return allPoints;

// To maximize grid spaces, move from outside in at both ends of the segment.
// Adjust points at either end, and walk to middle.
// Test if a --> b has collision. If so, change a to the line.
currA = allPoints[1];
for ( let i = 2, n = allPoints.length; i < n; i += 1 ) {
const currB = allPoints[i];
const keyAB = `${key(currA)}|${key(currB)}`
if ( testedSet.has(keyAB) ) continue;
if ( hasCollision(currA, currB, token) ) allPoints[i - 1] = foundry.utils.closestPointToSegment(currA, a, b);
// else testedSet.add(`${key(currA)}|${key(currB)}`);
for ( let i = 1, j = nPts - 2; i <= j; i += 1, j -= 1 ) {
const a0 = allPoints[i - 1];
const a1 = allPoints[i];
const a2 = allPoints[i + 1];
if ( hasCollision(a0, a1, token)
|| hasCollision(a1, a2, token) ) allPoints[i] = GridCoordinates.fromObject(foundry.utils.closestPointToSegment(a1, a, b));

if ( i === j ) break;
const b0 = allPoints[j + 1];
const b1 = allPoints[j];
const b2 = allPoints[j - 1];
if ( hasCollision(b0, b1, token)
|| hasCollision(b1, b2, token) ) allPoints[j] = GridCoordinates.fromObject(foundry.utils.closestPointToSegment(b1, a, b));
}

// For any non-centered points, check if we can move to an adjacent grid square. (Skip start and end.)
for ( let i = 1, n = nPts - 2; i < n; i += 1 ) {
const a1 = allPoints[i];
const center = a1.center;
if ( a1.almostEqual(center) ) continue;

const a0 = allPoints[i - 1];
const a2 = allPoints[i + 1];
if ( hasCollision(a0, center, token) || hasCollision(a2, center, token) ) continue;
allPoints[i] = center;
}

return allPoints;
}

Expand Down

0 comments on commit 83b3a6a

Please sign in to comment.