suggestion for zephreo to make multi destination parkour

This commit is contained in:
Leijurv 2020-11-25 01:14:23 -08:00
parent 6bec994a57
commit 4a489d29de
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
3 changed files with 70 additions and 40 deletions

View File

@ -114,50 +114,53 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
}
res.reset();
moves.apply(calcContext, currentNode.x, currentNode.y, currentNode.z, res);
numMovementsConsidered++;
double actionCost = res.cost;
if (actionCost >= ActionCosts.COST_INF) {
continue;
}
if (actionCost <= 0 || Double.isNaN(actionCost)) {
throw new IllegalStateException(moves + " calculated implausible cost " + actionCost);
}
// check destination after verifying it's not COST_INF -- some movements return a static IMPOSSIBLE object with COST_INF and destination being 0,0,0 to avoid allocating a new result for every failed calculation
if (moves.dynamicXZ && !worldBorder.entirelyContains(res.x, res.z)) { // see issue #218
continue;
}
if (!moves.dynamicXZ && (res.x != newX || res.z != newZ)) {
throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ);
}
if (!moves.dynamicY && res.y != currentNode.y + moves.yOffset) {
throw new IllegalStateException(moves + " " + res.y + " " + (currentNode.y + moves.yOffset));
}
long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z);
if (isFavoring) {
// see issue #18
actionCost *= favoring.calculate(hashCode);
}
PathNode neighbor = getNodeAtPosition(res.x, res.y, res.z, hashCode);
double tentativeCost = currentNode.cost + actionCost;
if (neighbor.cost - tentativeCost > minimumImprovement) {
neighbor.previous = currentNode;
neighbor.cost = tentativeCost;
neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal;
if (neighbor.isOpen()) {
openSet.update(neighbor);
} else {
openSet.insert(neighbor);//dont double count, dont insert into open set if it's already there
while (res != null) {
numMovementsConsidered++;
double actionCost = res.cost;
if (actionCost >= ActionCosts.COST_INF) {
continue;
}
for (int i = 0; i < COEFFICIENTS.length; i++) {
double heuristic = neighbor.estimatedCostToGoal + neighbor.cost / COEFFICIENTS[i];
if (bestHeuristicSoFar[i] - heuristic > minimumImprovement) {
bestHeuristicSoFar[i] = heuristic;
bestSoFar[i] = neighbor;
if (failing && getDistFromStartSq(neighbor) > MIN_DIST_PATH * MIN_DIST_PATH) {
failing = false;
if (actionCost <= 0 || Double.isNaN(actionCost)) {
throw new IllegalStateException(moves + " calculated implausible cost " + actionCost);
}
// check destination after verifying it's not COST_INF -- some movements return a static IMPOSSIBLE object with COST_INF and destination being 0,0,0 to avoid allocating a new result for every failed calculation
if (moves.dynamicXZ && !worldBorder.entirelyContains(res.x, res.z)) { // see issue #218
continue;
}
if (!moves.dynamicXZ && (res.x != newX || res.z != newZ)) {
throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ);
}
if (!moves.dynamicY && res.y != currentNode.y + moves.yOffset) {
throw new IllegalStateException(moves + " " + res.y + " " + (currentNode.y + moves.yOffset));
}
long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z);
if (isFavoring) {
// see issue #18
actionCost *= favoring.calculate(hashCode);
}
PathNode neighbor = getNodeAtPosition(res.x, res.y, res.z, hashCode);
double tentativeCost = currentNode.cost + actionCost;
if (neighbor.cost - tentativeCost > minimumImprovement) {
neighbor.previous = currentNode;
neighbor.cost = tentativeCost;
neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal;
if (neighbor.isOpen()) {
openSet.update(neighbor);
} else {
openSet.insert(neighbor);//dont double count, dont insert into open set if it's already there
}
for (int i = 0; i < COEFFICIENTS.length; i++) {
double heuristic = neighbor.estimatedCostToGoal + neighbor.cost / COEFFICIENTS[i];
if (bestHeuristicSoFar[i] - heuristic > minimumImprovement) {
bestHeuristicSoFar[i] = heuristic;
bestSoFar[i] = neighbor;
if (failing && getDistFromStartSq(neighbor) > MIN_DIST_PATH * MIN_DIST_PATH) {
failing = false;
}
}
}
}
res = res.getNext();
}
}
}

View File

@ -131,8 +131,14 @@ public class MovementParkour extends Movement {
res.y = y;
res.z = destZ;
res.cost = costFromJumpDistance(i) + context.jumpPenalty;
// for example, right here, we might just do:
res = res.nextPotentialDestination();
// that like, marks this `res` as "done" and we've put in this movement option's data
}
// and instead of this return
return;
// we would just continue onto the rest of the loop, and if we find an alternate landing, we would just update `res` as normal, and everything would Just Work
// we could return ANY number of potential movement destinations like this, and as soon as we get each new one, we just pop it into the stack by writing to `res` then doing `res = res.nextPotentialDestination();`
}
if (!MovementHelper.fullyPassable(context, destX, y + 3, destZ)) {
return;

View File

@ -30,6 +30,8 @@ public final class MutableMoveResult {
public int y;
public int z;
public double cost;
private MutableMoveResult next;
private boolean hasNext;
public MutableMoveResult() {
reset();
@ -40,5 +42,24 @@ public final class MutableMoveResult {
y = 0;
z = 0;
cost = ActionCosts.COST_INF;
hasNext = false;
if (next != null) {
next.reset();
}
}
public MutableMoveResult nextPotentialDestination() {
if (next == null) {
next = new MutableMoveResult(); // this is okay because it's one-time at the beginning (or near the beginning) of the calculation, instead of per-movement
}
hasNext = true;
return next;
}
public MutableMoveResult getNext() {
if (!hasNext) {
return null;
}
return next;
}
}