diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 1a3fef08..fcaea289 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -158,6 +158,31 @@ public class Settings { */ public Setting backtrackCostFavoringCoefficient = new Setting<>(0.5); + /** + * Toggle the following 4 settings + *

+ * They have a noticable performance impact, so they default off + */ + public Setting avoidance = new Setting<>(false); + /** + * Set to 1.0 to effectively disable this feature + *

+ * Set below 1.0 to go out of your way to walk near mob spawners + */ + public Setting mobSpawnerAvoidanceCoefficient = new Setting<>(2.0); + + public Setting mobSpawnerAvoidanceRadius = new Setting<>(16); + + /** + * Set to 1.0 to effectively disable this feature + *

+ * Set below 1.0 to go out of your way to walk near mobs + */ + public Setting mobAvoidanceCoefficient = new Setting<>(1.5); + + public Setting mobAvoidanceRadius = new Setting<>(8); + + /** * Don't repropagate cost improvements below 0.01 ticks. They're all just floating point inaccuracies, * and there's no point. diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index bd2146b8..ec83a268 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -37,7 +37,8 @@ import baritone.pathing.path.CutoffPath; import baritone.pathing.path.PathExecutor; import baritone.utils.Helper; import baritone.utils.PathRenderer; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import baritone.utils.pathing.AvoidanceHelper; +import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap; import net.minecraft.util.math.BlockPos; import net.minecraft.world.chunk.EmptyChunk; @@ -503,12 +504,12 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, transformed = new GoalXZ(pos.getX(), pos.getZ()); } } - LongOpenHashSet favoredPositions = null; - if (Baritone.settings().backtrackCostFavoringCoefficient.get() != 1D && previous != null) { - LongOpenHashSet tmp = new LongOpenHashSet(); - previous.positions().forEach(pos -> tmp.add(BetterBlockPos.longHash(pos))); - favoredPositions = tmp; + Long2DoubleOpenHashMap favoredPositions = new Long2DoubleOpenHashMap(); + double coeff = Baritone.settings().backtrackCostFavoringCoefficient.get(); + if (coeff != 1D && previous != null) { + previous.positions().forEach(pos -> favoredPositions.put(BetterBlockPos.longHash(pos), coeff)); } + AvoidanceHelper.INSTANCE.apply(favoredPositions, context.getBaritone().getPlayerContext()); return new AStarPathFinder(start.getX(), start.getY(), start.getZ(), transformed, favoredPositions, context); } diff --git a/src/main/java/baritone/pathing/calc/AStarPathFinder.java b/src/main/java/baritone/pathing/calc/AStarPathFinder.java index d7292da7..14b17b80 100644 --- a/src/main/java/baritone/pathing/calc/AStarPathFinder.java +++ b/src/main/java/baritone/pathing/calc/AStarPathFinder.java @@ -28,9 +28,8 @@ import baritone.pathing.movement.Moves; import baritone.utils.Helper; import baritone.utils.pathing.BetterWorldBorder; import baritone.utils.pathing.MutableMoveResult; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap; -import java.util.HashSet; import java.util.Optional; /** @@ -40,10 +39,10 @@ import java.util.Optional; */ public final class AStarPathFinder extends AbstractNodeCostSearch implements Helper { - private final LongOpenHashSet favoredPositions; + private final Long2DoubleOpenHashMap favoredPositions; private final CalculationContext calcContext; - public AStarPathFinder(int startX, int startY, int startZ, Goal goal, LongOpenHashSet favoredPositions, CalculationContext context) { + public AStarPathFinder(int startX, int startY, int startZ, Goal goal, Long2DoubleOpenHashMap favoredPositions, CalculationContext context) { super(startX, startY, startZ, goal, context); this.favoredPositions = favoredPositions; this.calcContext = context; @@ -64,7 +63,8 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel bestSoFar[i] = startNode; } MutableMoveResult res = new MutableMoveResult(); - LongOpenHashSet favored = favoredPositions; + Long2DoubleOpenHashMap favored = favoredPositions; + favored.defaultReturnValue(1.0D); BetterWorldBorder worldBorder = new BetterWorldBorder(calcContext.world().getWorldBorder()); long startTime = System.nanoTime() / 1000000L; boolean slowPath = Baritone.settings().slowPath.get(); @@ -77,7 +77,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel int numNodes = 0; int numMovementsConsidered = 0; int numEmptyChunk = 0; - boolean favoring = favored != null; + boolean favoring = favored != null && !favored.isEmpty(); int pathingMaxChunkBorderFetch = Baritone.settings().pathingMaxChunkBorderFetch.get(); // grab all settings beforehand so that changing settings during pathing doesn't cause a crash or unpredictable behavior double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get(); boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get(); @@ -137,9 +137,10 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel throw new IllegalStateException(moves + " " + res.y + " " + (currentNode.y + moves.yOffset)); } long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z); - if (favoring && favored.contains(hashCode)) { + favored.get(hashCode); + if (favoring) { // see issue #18 - actionCost *= favorCoeff; + actionCost *= favored.get(hashCode); } PathNode neighbor = getNodeAtPosition(res.x, res.y, res.z, hashCode); double tentativeCost = currentNode.cost + actionCost; diff --git a/src/main/java/baritone/utils/pathing/AvoidanceHelper.java b/src/main/java/baritone/utils/pathing/AvoidanceHelper.java new file mode 100644 index 00000000..0201eef2 --- /dev/null +++ b/src/main/java/baritone/utils/pathing/AvoidanceHelper.java @@ -0,0 +1,58 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.utils.pathing; + +import baritone.Baritone; +import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.IPlayerContext; +import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap; +import net.minecraft.entity.monster.EntityMob; +import net.minecraft.util.math.BlockPos; + +public enum AvoidanceHelper { + INSTANCE; + + public void apply(Long2DoubleOpenHashMap map, IPlayerContext ctx) { + if (!Baritone.settings().avoidance.get()) { + return; + } + long start = System.currentTimeMillis(); + double mobSpawnerCoeff = Baritone.settings().mobSpawnerAvoidanceCoefficient.get(); + double mobCoeff = Baritone.settings().mobAvoidanceCoefficient.get(); + if (mobSpawnerCoeff != 1.0D) { + ctx.worldData().getCachedWorld().getLocationsOf("mob_spawner", 1, ctx.playerFeet().x, ctx.playerFeet().z, 2).forEach(mobspawner -> sphere(mobspawner, Baritone.settings().mobSpawnerAvoidanceRadius.get(), map, mobSpawnerCoeff)); + } + if (mobCoeff != 1.0D) { + ctx.world().loadedEntityList.stream().filter(entity -> entity instanceof EntityMob).forEach(entity -> sphere(new BlockPos(entity), Baritone.settings().mobAvoidanceRadius.get(), map, mobCoeff)); + } + long end = System.currentTimeMillis(); + System.out.println("Took " + (end - start) + "ms to generate avoidance of " + map.size() + " blocks"); + } + + private void sphere(BlockPos center, int radius, Long2DoubleOpenHashMap map, double coeff) { + for (int x = -radius; x <= radius; x++) { + for (int y = -radius; y <= radius; y++) { + for (int z = -radius; z <= radius; z++) { + if (x * x + y * y + z * z <= radius * radius) { + map.put(BetterBlockPos.longHash(center.getX() + x, center.getY() + y, center.getZ() + z), coeff); + } + } + } + } + } +}