use of baritone.api.pathing.goals.Goal in project baritone by cabaletta.
the class OpenSetsTest method testSize.
@Test
public void testSize() {
System.out.println("Testing size " + size);
// Include LinkedListOpenSet even though it's not performant because I absolutely trust that it behaves properly
// I'm really testing the heap implementations against it as the ground truth
IOpenSet[] test = new IOpenSet[] { new BinaryHeapOpenSet(), new LinkedListOpenSet() };
for (IOpenSet set : test) {
assertTrue(set.isEmpty());
}
// generate the pathnodes that we'll be testing the sets on
PathNode[] toInsert = new PathNode[size];
for (int i = 0; i < size; i++) {
// can't use an existing goal
// because they use Baritone.settings()
// and we can't do that because Minecraft itself isn't initted
PathNode pn = new PathNode(0, 0, 0, new Goal() {
@Override
public boolean isInGoal(int x, int y, int z) {
return false;
}
@Override
public double heuristic(int x, int y, int z) {
return 0;
}
});
pn.combinedCost = Math.random();
toInsert[i] = pn;
}
// create a list of what the first removals should be
ArrayList<PathNode> copy = new ArrayList<>(Arrays.asList(toInsert));
copy.sort(Comparator.comparingDouble(pn -> pn.combinedCost));
Set<PathNode> lowestQuarter = new HashSet<>(copy.subList(0, size / 4));
// all opensets should be empty; nothing has been inserted yet
for (IOpenSet set : test) {
assertTrue(set.isEmpty());
}
System.out.println("Insertion");
for (IOpenSet set : test) {
long before = System.nanoTime() / 1000000L;
for (int i = 0; i < size; i++) set.insert(toInsert[i]);
System.out.println(set.getClass() + " " + (System.nanoTime() / 1000000L - before));
// all three take either 0 or 1ms to insert up to 10,000 nodes
// linkedlist takes 0ms most often (because there's no array resizing or allocation there, just pointer shuffling)
}
// all opensets should now be full
for (IOpenSet set : test) {
assertFalse(set.isEmpty());
}
System.out.println("Removal round 1");
// remove a quarter of the nodes and verify that they are indeed the size/4 lowest ones
removeAndTest(size / 4, test, lowestQuarter);
// none of them should be empty (sanity check)
for (IOpenSet set : test) {
assertFalse(set.isEmpty());
}
int cnt = 0;
for (int i = 0; cnt < size / 2 && i < size; i++) {
if (lowestQuarter.contains(toInsert[i])) {
// these were already removed and can't be updated to test
continue;
}
toInsert[i].combinedCost *= Math.random();
// multiplying it by a random number between 0 and 1 is guaranteed to decrease it
for (IOpenSet set : test) {
// it's difficult to benchmark these individually because if you modify all at once then update then
// it breaks the internal consistency of the heaps.
// you have to call update every time you modify a node.
set.update(toInsert[i]);
}
cnt++;
}
// still shouldn't be empty
for (IOpenSet set : test) {
assertFalse(set.isEmpty());
}
System.out.println("Removal round 2");
// remove the remaining 3/4
removeAndTest(size - size / 4, test, null);
// every set should now be empty
for (IOpenSet set : test) {
assertTrue(set.isEmpty());
}
}
use of baritone.api.pathing.goals.Goal in project baritone by cabaletta.
the class PathingBehavior method findPathInNewThread.
/**
* In a new thread, pathfind to target blockpos
*
* @param start
* @param talkAboutIt
*/
private void findPathInNewThread(final BlockPos start, final boolean talkAboutIt, CalculationContext context) {
// actually, we can check this, muahaha
if (!Thread.holdsLock(pathCalcLock)) {
throw new IllegalStateException("Must be called with synchronization on pathCalcLock");
// why do it this way? it's already indented so much that putting the whole thing in a synchronized(pathCalcLock) was just too much lol
}
if (inProgress != null) {
// should have been checked by caller
throw new IllegalStateException("Already doing it");
}
if (!context.safeForThreadedUse) {
throw new IllegalStateException("Improper context thread safety level");
}
Goal goal = this.goal;
if (goal == null) {
// TODO should this be an exception too? definitely should be checked by caller
logDebug("no goal");
return;
}
long primaryTimeout;
long failureTimeout;
if (current == null) {
primaryTimeout = Baritone.settings().primaryTimeoutMS.value;
failureTimeout = Baritone.settings().failureTimeoutMS.value;
} else {
primaryTimeout = Baritone.settings().planAheadPrimaryTimeoutMS.value;
failureTimeout = Baritone.settings().planAheadFailureTimeoutMS.value;
}
AbstractNodeCostSearch pathfinder = createPathfinder(start, goal, current == null ? null : current.getPath(), context);
if (!Objects.equals(pathfinder.getGoal(), goal)) {
// will return the exact same object if simplification didn't happen
logDebug("Simplifying " + goal.getClass() + " to GoalXZ due to distance");
}
inProgress = pathfinder;
Baritone.getExecutor().execute(() -> {
if (talkAboutIt) {
logDebug("Starting to search for path from " + start + " to " + goal);
}
PathCalculationResult calcResult = pathfinder.calculate(primaryTimeout, failureTimeout);
synchronized (pathPlanLock) {
Optional<PathExecutor> executor = calcResult.getPath().map(p -> new PathExecutor(PathingBehavior.this, p));
if (current == null) {
if (executor.isPresent()) {
if (executor.get().getPath().positions().contains(expectedSegmentStart)) {
queuePathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING);
current = executor.get();
resetEstimatedTicksToGoal(start);
} else {
logDebug("Warning: discarding orphan path segment with incorrect start");
}
} else {
if (calcResult.getType() != PathCalculationResult.Type.CANCELLATION && calcResult.getType() != PathCalculationResult.Type.EXCEPTION) {
// don't dispatch CALC_FAILED on cancellation
queuePathEvent(PathEvent.CALC_FAILED);
}
}
} else {
if (next == null) {
if (executor.isPresent()) {
if (executor.get().getPath().getSrc().equals(current.getPath().getDest())) {
queuePathEvent(PathEvent.NEXT_SEGMENT_CALC_FINISHED);
next = executor.get();
} else {
logDebug("Warning: discarding orphan next segment with incorrect start");
}
} else {
queuePathEvent(PathEvent.NEXT_CALC_FAILED);
}
} else {
// throw new IllegalStateException("I have no idea what to do with this path");
// no point in throwing an exception here, and it gets it stuck with inProgress being not null
logDirect("Warning: PathingBehaivor illegal state! Discarding invalid path!");
}
}
if (talkAboutIt && current != null && current.getPath() != null) {
if (goal.isInGoal(current.getPath().getDest())) {
logDebug("Finished finding a path from " + start + " to " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered");
} else {
logDebug("Found path segment from " + start + " towards " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered");
}
}
synchronized (pathCalcLock) {
inProgress = null;
}
}
});
}
use of baritone.api.pathing.goals.Goal in project baritone by cabaletta.
the class BuilderProcess method assemble.
private Goal assemble(BuilderCalculationContext bcc, List<IBlockState> approxPlaceable, boolean logMissing) {
List<BetterBlockPos> placeable = new ArrayList<>();
List<BetterBlockPos> breakable = new ArrayList<>();
List<BetterBlockPos> sourceLiquids = new ArrayList<>();
List<BetterBlockPos> flowingLiquids = new ArrayList<>();
Map<IBlockState, Integer> missing = new HashMap<>();
incorrectPositions.forEach(pos -> {
IBlockState state = bcc.bsi.get0(pos);
if (state.getBlock() instanceof BlockAir) {
if (approxPlaceable.contains(bcc.getSchematic(pos.x, pos.y, pos.z, state))) {
placeable.add(pos);
} else {
IBlockState desired = bcc.getSchematic(pos.x, pos.y, pos.z, state);
missing.put(desired, 1 + missing.getOrDefault(desired, 0));
}
} else {
if (state.getBlock() instanceof BlockLiquid) {
// TODO for 1.13 make sure that this only matches pure water, not waterlogged blocks
if (!MovementHelper.possiblyFlowing(state)) {
// if it's a source block then we want to replace it with a throwaway
sourceLiquids.add(pos);
} else {
flowingLiquids.add(pos);
}
} else {
breakable.add(pos);
}
}
});
List<Goal> toBreak = new ArrayList<>();
breakable.forEach(pos -> toBreak.add(breakGoal(pos, bcc)));
List<Goal> toPlace = new ArrayList<>();
placeable.forEach(pos -> {
if (!placeable.contains(pos.down()) && !placeable.contains(pos.down(2))) {
toPlace.add(placementGoal(pos, bcc));
}
});
sourceLiquids.forEach(pos -> toPlace.add(new GoalBlock(pos.up())));
if (!toPlace.isEmpty()) {
return new JankyGoalComposite(new GoalComposite(toPlace.toArray(new Goal[0])), new GoalComposite(toBreak.toArray(new Goal[0])));
}
if (toBreak.isEmpty()) {
if (logMissing && !missing.isEmpty()) {
logDirect("Missing materials for at least:");
logDirect(missing.entrySet().stream().map(e -> String.format("%sx %s", e.getValue(), e.getKey())).collect(Collectors.joining("\n")));
}
if (logMissing && !flowingLiquids.isEmpty()) {
logDirect("Unreplaceable liquids at at least:");
logDirect(flowingLiquids.stream().map(p -> String.format("%s %s %s", p.x, p.y, p.z)).collect(Collectors.joining("\n")));
}
return null;
}
return new GoalComposite(toBreak.toArray(new Goal[0]));
}
use of baritone.api.pathing.goals.Goal in project baritone by cabaletta.
the class ExploreProcess method closestUncachedChunks.
private Goal[] closestUncachedChunks(BlockPos center, IChunkFilter filter) {
int chunkX = center.getX() >> 4;
int chunkZ = center.getZ() >> 4;
int count = Math.min(filter.countRemain(), Baritone.settings().exploreChunkSetMinimumSize.value);
List<BlockPos> centers = new ArrayList<>();
int renderDistance = Baritone.settings().worldExploringChunkOffset.value;
for (int dist = distanceCompleted; ; dist++) {
for (int dx = -dist; dx <= dist; dx++) {
int zval = dist - Math.abs(dx);
for (int mult = 0; mult < 2; mult++) {
// dz can be either -zval or zval
int dz = (mult * 2 - 1) * zval;
int trueDist = Math.abs(dx) + Math.abs(dz);
if (trueDist != dist) {
throw new IllegalStateException();
}
switch(filter.isAlreadyExplored(chunkX + dx, chunkZ + dz)) {
case UNKNOWN:
// awaiting load
return null;
case NOT_EXPLORED:
// note: this breaks the switch not the for
break;
case EXPLORED:
// note: this continues the for
continue;
default:
}
int centerX = ((chunkX + dx) << 4) + 8;
int centerZ = ((chunkZ + dz) << 4) + 8;
int offset = renderDistance << 4;
if (dx < 0) {
centerX -= offset;
} else {
centerX += offset;
}
if (dz < 0) {
centerZ -= offset;
} else {
centerZ += offset;
}
centers.add(new BlockPos(centerX, 0, centerZ));
}
}
if (dist % 10 == 0) {
count = Math.min(filter.countRemain(), Baritone.settings().exploreChunkSetMinimumSize.value);
}
if (centers.size() >= count) {
return centers.stream().map(pos -> createGoal(pos.getX(), pos.getZ())).toArray(Goal[]::new);
}
if (centers.isEmpty()) {
// we have explored everything from 0 to dist inclusive
// next time we should start our check at dist+1
distanceCompleted = dist + 1;
}
}
}
use of baritone.api.pathing.goals.Goal in project baritone by cabaletta.
the class SurfaceCommand method execute.
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
final BetterBlockPos playerPos = baritone.getPlayerContext().playerFeet();
final int surfaceLevel = baritone.getPlayerContext().world().getSeaLevel();
final int worldHeight = baritone.getPlayerContext().world().getActualHeight();
// As this would imply that your are already on the open surface
if (playerPos.getY() > surfaceLevel && mc.world.getBlockState(playerPos.up()).getBlock() instanceof BlockAir) {
logDirect("Already at surface");
return;
}
final int startingYPos = Math.max(playerPos.getY(), surfaceLevel);
for (int currentIteratedY = startingYPos; currentIteratedY < worldHeight; currentIteratedY++) {
final BetterBlockPos newPos = new BetterBlockPos(playerPos.getX(), currentIteratedY, playerPos.getZ());
if (!(mc.world.getBlockState(newPos).getBlock() instanceof BlockAir) && newPos.getY() > playerPos.getY()) {
Goal goal = new GoalBlock(newPos.up());
logDirect(String.format("Going to: %s", goal.toString()));
baritone.getCustomGoalProcess().setGoalAndPath(goal);
return;
}
}
logDirect("No higher location found");
}
Aggregations