Merge branch 'builder'

This commit is contained in:
Leijurv 2019-03-12 19:16:40 -07:00
commit 2215f170df
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
32 changed files with 1422 additions and 194 deletions

View File

@ -65,6 +65,12 @@ public interface IBaritone {
*/
IMineProcess getMineProcess();
/**
* @return The {@link IBuilderProcess} instance
* @see IBuilderProcess
*/
IBuilderProcess getBuilderProcess();
/**
* @return The {@link ICustomGoalProcess} instance
* @see ICustomGoalProcess

View File

@ -30,17 +30,17 @@ public class GoalBlock implements Goal, IGoalRenderPos {
/**
* The X block position of this goal
*/
private final int x;
public final int x;
/**
* The Y block position of this goal
*/
private final int y;
public final int y;
/**
* The Z block position of this goal
*/
private final int z;
public final int z;
public GoalBlock(BlockPos pos) {
this(pos.getX(), pos.getY(), pos.getZ());

View File

@ -28,9 +28,9 @@ import net.minecraft.util.math.BlockPos;
*/
public class GoalGetToBlock implements Goal, IGoalRenderPos {
private final int x;
private final int y;
private final int z;
public final int x;
public final int y;
public final int z;
public GoalGetToBlock(BlockPos pos) {
this.x = pos.getX();

View File

@ -45,10 +45,6 @@ public interface IMovement {
*/
boolean safeToCancel();
double recalculateCost();
double calculateCostWithoutCaching();
boolean calculatedWhileLoaded();
BetterBlockPos getSrc();

View File

@ -0,0 +1,49 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package baritone.api.process;
import baritone.api.utils.ISchematic;
import net.minecraft.util.math.Vec3i;
import java.io.File;
/**
* @author Brady
* @since 1/15/2019
*/
public interface IBuilderProcess extends IBaritoneProcess {
/**
* Requests a build for the specified schematic, labeled as specified, with the specified origin.
*
* @param name A user-friendly name for the schematic
* @param schematic The object representation of the schematic
* @param origin The origin position of the schematic being built
*/
void build(String name, ISchematic schematic, Vec3i origin);
/**
* Requests a build for the specified schematic, labeled as specified, with the specified origin.
*
* @param name A user-friendly name for the schematic
* @param schematic The file path of the schematic
* @param origin The origin position of the schematic being built
* @return Whether or not the schematic was able to load from file
*/
boolean build(String name, File schematic, Vec3i origin);
}

View File

@ -0,0 +1,71 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package baritone.api.utils;
import net.minecraft.block.state.IBlockState;
/**
* Basic representation of a schematic. Provides the dimensions and
* the desired statefor a given position relative to the origin.
*
* @author leijurv
*/
public interface ISchematic {
/**
* Does the block at this coordinate matter to the schematic?
* <p>
* Normally just a check for if the coordinate is in the cube.
* <p>
* However, in the case of something like a map art, anything that's below the level of the map art doesn't matter,
* so this function should return false in that case. (i.e. it doesn't really have to be air below the art blocks)
*
* @param x The x position of the block, relative to the origin
* @param y The y position of the block, relative to the origin
* @param z The z position of the block, relative to the origin
* @return Whether or not the specified position is within the bounds of this schematic
*/
default boolean inSchematic(int x, int y, int z) {
return x >= 0 && x < widthX() && y >= 0 && y < heightY() && z >= 0 && z < lengthZ();
}
/**
* Returns the desired block state at a given (X, Y, Z) position relative to the origin (0, 0, 0).
*
* @param x The x position of the block, relative to the origin
* @param y The y position of the block, relative to the origin
* @param z The z position of the block, relative to the origin
* @return The desired block state at the specified position
*/
IBlockState desiredState(int x, int y, int z);
/**
* @return The width (X axis length) of this schematic
*/
int widthX();
/**
* @return The height (Y axis length) of this schematic
*/
int heightY();
/**
* @return The length (Z axis length) of this schematic
*/
int lengthZ();
}

View File

@ -71,12 +71,14 @@ public class Baritone implements IBaritone {
private PathingBehavior pathingBehavior;
private LookBehavior lookBehavior;
private MemoryBehavior memoryBehavior;
private InventoryBehavior inventoryBehavior;
private InputOverrideHandler inputOverrideHandler;
private FollowProcess followProcess;
private MineProcess mineProcess;
private GetToBlockProcess getToBlockProcess;
private CustomGoalProcess customGoalProcess;
private BuilderProcess builderProcess;
private ExploreProcess exploreProcess;
private PathingControlManager pathingControlManager;
@ -105,7 +107,7 @@ public class Baritone implements IBaritone {
pathingBehavior = new PathingBehavior(this);
lookBehavior = new LookBehavior(this);
memoryBehavior = new MemoryBehavior(this);
new InventoryBehavior(this);
inventoryBehavior = new InventoryBehavior(this);
inputOverrideHandler = new InputOverrideHandler(this);
new ExampleBaritoneControl(this);
}
@ -116,6 +118,7 @@ public class Baritone implements IBaritone {
mineProcess = new MineProcess(this);
customGoalProcess = new CustomGoalProcess(this); // very high iq
getToBlockProcess = new GetToBlockProcess(this);
builderProcess = new BuilderProcess(this);
exploreProcess = new ExploreProcess(this);
}
@ -171,6 +174,15 @@ public class Baritone implements IBaritone {
return this.followProcess;
}
@Override
public BuilderProcess getBuilderProcess() {
return this.builderProcess;
}
public InventoryBehavior getInventoryBehavior() {
return this.inventoryBehavior;
}
@Override
public LookBehavior getLookBehavior() {
return this.lookBehavior;
@ -211,4 +223,4 @@ public class Baritone implements IBaritone {
public static Executor getExecutor() {
return threadPool;
}
}
}

View File

@ -21,13 +21,18 @@ import baritone.Baritone;
import baritone.api.event.events.TickEvent;
import baritone.utils.ToolSet;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.ClickType;
import net.minecraft.item.ItemPickaxe;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemTool;
import net.minecraft.item.*;
import net.minecraft.util.NonNullList;
import java.util.ArrayList;
import java.util.OptionalInt;
import java.util.Random;
import java.util.function.Predicate;
public class InventoryBehavior extends Behavior {
public InventoryBehavior(Baritone baritone) {
super(baritone);
@ -54,6 +59,34 @@ public class InventoryBehavior extends Behavior {
}
}
public void attemptToPutOnHotbar(int inMainInvy, Predicate<Integer> disallowedHotbar) {
OptionalInt destination = getTempHotbarSlot(disallowedHotbar);
if (destination.isPresent()) {
swapWithHotBar(inMainInvy, destination.getAsInt());
}
}
public OptionalInt getTempHotbarSlot(Predicate<Integer> disallowedHotbar) {
// we're using 0 and 8 for pickaxe and throwaway
ArrayList<Integer> candidates = new ArrayList<>();
for (int i = 1; i < 8; i++) {
if (ctx.player().inventory.mainInventory.get(i).isEmpty() && !disallowedHotbar.test(i)) {
candidates.add(i);
}
}
if (candidates.isEmpty()) {
for (int i = 1; i < 8; i++) {
if (!disallowedHotbar.test(i)) {
candidates.add(i);
}
}
}
if (candidates.isEmpty()) {
return OptionalInt.empty();
}
return OptionalInt.of(candidates.get(new Random().nextInt(candidates.size())));
}
private void swapWithHotBar(int inInventory, int inHotbar) {
ctx.playerController().windowClick(ctx.player().inventoryContainer.windowId, inInventory < 9 ? inInventory + 36 : inInventory, inHotbar, ClickType.SWAP, ctx.player());
}
@ -87,4 +120,62 @@ public class InventoryBehavior extends Behavior {
}
return bestInd;
}
public boolean hasGenericThrowaway() {
for (Item item : Baritone.settings().acceptableThrowawayItems.value) {
if (throwaway(false, item::equals)) {
return true;
}
}
return false;
}
public boolean selectThrowawayForLocation(int x, int y, int z) {
IBlockState maybe = baritone.getBuilderProcess().placeAt(x, y, z);
if (maybe != null && throwaway(true, item -> item instanceof ItemBlock && ((ItemBlock) item).getBlock().equals(maybe.getBlock()))) {
return true; // gotem
}
for (Item item : Baritone.settings().acceptableThrowawayItems.value) {
if (throwaway(true, item::equals)) {
return true;
}
}
return false;
}
private boolean throwaway(boolean select, Predicate<? super Item> desired) {
EntityPlayerSP p = ctx.player();
NonNullList<ItemStack> inv = p.inventory.mainInventory;
for (byte i = 0; i < 9; i++) {
ItemStack item = inv.get(i);
// this usage of settings() is okay because it's only called once during pathing
// (while creating the CalculationContext at the very beginning)
// and then it's called during execution
// since this function is never called during cost calculation, we don't need to migrate
// acceptableThrowawayItems to the CalculationContext
if (desired.test(item.getItem())) {
if (select) {
p.inventory.currentItem = i;
}
return true;
}
}
if (desired.test(p.inventory.offHandInventory.get(0).getItem())) {
// main hand takes precedence over off hand
// that means that if we have block A selected in main hand and block B in off hand, right clicking places block B
// we've already checked above ^ and the main hand can't possible have an acceptablethrowawayitem
// so we need to select in the main hand something that doesn't right click
// so not a shovel, not a hoe, not a block, etc
for (byte i = 0; i < 9; i++) {
ItemStack item = inv.get(i);
if (item.isEmpty() || item.getItem() instanceof ItemPickaxe) {
if (select) {
p.inventory.currentItem = i;
}
return true;
}
}
}
return false;
}
}

View File

@ -73,7 +73,7 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
float desiredPitch = this.target.getPitch();
ctx.player().rotationPitch = desiredPitch;
if (desiredPitch == oldPitch) {
nudgeToLevel();
//nudgeToLevel();
}
this.target = null;
}

View File

@ -25,7 +25,6 @@ import baritone.api.event.events.TickEvent;
import baritone.api.event.events.type.EventState;
import baritone.cache.ContainerMemory;
import baritone.cache.Waypoint;
import baritone.pathing.movement.CalculationContext;
import baritone.utils.BlockStateInterface;
import net.minecraft.block.Block;
import net.minecraft.block.BlockBed;
@ -196,7 +195,7 @@ public final class MemoryBehavior extends Behavior {
}
private BlockPos neighboringConnectedBlock(BlockPos in) {
BlockStateInterface bsi = new CalculationContext(baritone).bsi;
BlockStateInterface bsi = baritone.bsi;
Block block = bsi.get0(in).getBlock();
if (block != Blocks.TRAPPED_CHEST && block != Blocks.CHEST) {
return null; // other things that have contents, but can be placed adjacent without combining

View File

@ -23,6 +23,7 @@ import baritone.api.event.events.*;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.goals.GoalXZ;
import baritone.api.process.PathingCommand;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.PathCalculationResult;
import baritone.api.utils.interfaces.IGoalRenderPos;
@ -33,6 +34,7 @@ import baritone.pathing.movement.MovementHelper;
import baritone.pathing.path.PathExecutor;
import baritone.utils.Helper;
import baritone.utils.PathRenderer;
import baritone.utils.PathingCommandContext;
import baritone.utils.pathing.Favoring;
import net.minecraft.util.math.BlockPos;
@ -48,9 +50,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
private PathExecutor next;
private Goal goal;
private CalculationContext context;
private boolean safeToCancel;
private boolean pauseRequestedLastTick;
private boolean unpausedLastTick;
private boolean cancelRequested;
private boolean calcFailedLastTick;
@ -106,10 +110,14 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
private void tickPath() {
if (pauseRequestedLastTick && safeToCancel) {
pauseRequestedLastTick = false;
baritone.getInputOverrideHandler().clearAllKeys();
baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock();
if (unpausedLastTick) {
baritone.getInputOverrideHandler().clearAllKeys();
baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock();
}
unpausedLastTick = false;
return;
}
unpausedLastTick = true;
if (cancelRequested) {
cancelRequested = false;
baritone.getInputOverrideHandler().clearAllKeys();
@ -173,7 +181,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
}
// we aren't calculating
queuePathEvent(PathEvent.CALC_STARTED);
findPathInNewThread(expectedSegmentStart, true);
findPathInNewThread(expectedSegmentStart, true, context);
}
return;
}
@ -210,7 +218,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
// if we actually included current, it wouldn't start planning ahead until the last movement was done, if the last movement took more than 7.5 seconds on its own
logDebug("Path almost over. Planning ahead...");
queuePathEvent(PathEvent.NEXT_SEGMENT_CALC_STARTED);
findPathInNewThread(current.getPath().getDest(), false);
findPathInNewThread(current.getPath().getDest(), false, context);
}
}
}
@ -237,9 +245,32 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
this.goal = goal;
}
public boolean secretInternalSetGoalAndPath(Goal goal) {
secretInternalSetGoal(goal);
return secretInternalPath();
public boolean secretInternalSetGoalAndPath(PathingCommand command) {
secretInternalSetGoal(command.goal);
if (command instanceof PathingCommandContext) {
context = ((PathingCommandContext) command).desiredCalcContext;
} else {
context = new CalculationContext(baritone, true);
}
if (goal == null) {
return false;
}
if (goal.isInGoal(ctx.playerFeet()) || goal.isInGoal(expectedSegmentStart)) {
return false;
}
synchronized (pathPlanLock) {
if (current != null) {
return false;
}
synchronized (pathCalcLock) {
if (inProgress != null) {
return false;
}
queuePathEvent(PathEvent.CALC_STARTED);
findPathInNewThread(expectedSegmentStart, true, context);
return true;
}
}
}
@Override
@ -327,39 +358,16 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
}
}
/**
* Start calculating a path if we aren't already
*
* @return true if this call started path calculation, false if it was already calculating or executing a path
*/
public boolean secretInternalPath() {
if (goal == null) {
return false;
}
if (goal.isInGoal(ctx.playerFeet())) {
return false;
}
synchronized (pathPlanLock) {
if (current != null) {
return false;
}
synchronized (pathCalcLock) {
if (inProgress != null) {
return false;
}
queuePathEvent(PathEvent.CALC_STARTED);
findPathInNewThread(expectedSegmentStart, true);
return true;
}
}
}
public void secretCursedFunctionDoNotCall(IPath path) {
synchronized (pathPlanLock) {
current = new PathExecutor(this, path);
}
}
public CalculationContext secretInternalGetCalculationContext() {
return context;
}
/**
* See issue #209
*
@ -411,7 +419,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
* @param start
* @param talkAboutIt
*/
private void findPathInNewThread(final BlockPos start, final boolean talkAboutIt) {
private void findPathInNewThread(final BlockPos start, final boolean talkAboutIt, CalculationContext context) {
// this must be called with synchronization on pathCalcLock!
// actually, we can check this, muahaha
if (!Thread.holdsLock(pathCalcLock)) {
@ -421,6 +429,9 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
if (inProgress != null) {
throw new IllegalStateException("Already doing it"); // should have been checked by caller
}
if (!context.safeForThreadedUse) {
throw new IllegalStateException("Improper context thread safety level");
}
Goal goal = this.goal;
if (goal == null) {
logDebug("no goal"); // TODO should this be an exception too? definitely should be checked by caller
@ -435,7 +446,6 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
primaryTimeout = Baritone.settings().planAheadPrimaryTimeoutMS.value;
failureTimeout = Baritone.settings().planAheadFailureTimeoutMS.value;
}
CalculationContext context = new CalculationContext(baritone, true); // not safe to create on the other thread, it looks up a lot of stuff in minecraft
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");
@ -503,7 +513,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
transformed = new GoalXZ(pos.getX(), pos.getZ());
}
}
Favoring favoring = new Favoring(context.getBaritone().getPlayerContext(), previous);
Favoring favoring = new Favoring(context.getBaritone().getPlayerContext(), previous, context);
return new AStarPathFinder(start.getX(), start.getY(), start.getZ(), transformed, favoring, context);
}

View File

@ -34,6 +34,8 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
/**
* @author Brady
* @since 8/7/2018
@ -42,6 +44,7 @@ public class CalculationContext {
private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET);
public final boolean safeForThreadedUse;
public final IBaritone baritone;
public final World world;
public final WorldData worldData;
@ -50,7 +53,7 @@ public class CalculationContext {
public final boolean hasWaterBucket;
public final boolean hasThrowaway;
public final boolean canSprint;
public final double placeBlockCost;
protected final double placeBlockCost; // protected because you should call the function instead
public final boolean allowBreak;
public final boolean allowParkour;
public final boolean allowParkourPlace;
@ -61,7 +64,8 @@ public class CalculationContext {
public final int maxFallHeightBucket;
public final double waterWalkSpeed;
public final double breakBlockAdditionalCost;
public final double jumpPenalty;
public double backtrackCostFavoringCoefficient;
public double jumpPenalty;
public final double walkOnWaterOnePenalty;
public final BetterWorldBorder worldBorder;
@ -70,13 +74,14 @@ public class CalculationContext {
}
public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) {
this.safeForThreadedUse = forUseOnAnotherThread;
this.baritone = baritone;
EntityPlayerSP player = baritone.getPlayerContext().player();
this.world = baritone.getPlayerContext().world();
this.worldData = (WorldData) baritone.getWorldProvider().getCurrentWorld();
this.bsi = new BlockStateInterface(world, worldData, forUseOnAnotherThread); // TODO TODO TODO
this.bsi = new BlockStateInterface(world, worldData, forUseOnAnotherThread);
this.toolSet = new ToolSet(player);
this.hasThrowaway = Baritone.settings().allowPlace.value && MovementHelper.throwaway(baritone.getPlayerContext(), false);
this.hasThrowaway = Baritone.settings().allowPlace.value && ((Baritone) baritone).getInventoryBehavior().hasGenericThrowaway();
this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.value && InventoryPlayer.isHotbar(player.inventory.getSlotFor(STACK_BUCKET_WATER)) && !world.provider.isNether();
this.canSprint = Baritone.settings().allowSprint.value && player.getFoodStats().getFoodLevel() > 6;
this.placeBlockCost = Baritone.settings().blockPlacementPenalty.value;
@ -95,6 +100,7 @@ public class CalculationContext {
float mult = depth / 3.0F;
this.waterWalkSpeed = ActionCosts.WALK_ONE_IN_WATER_COST * (1 - mult) + ActionCosts.WALK_ONE_BLOCK_COST * mult;
this.breakBlockAdditionalCost = Baritone.settings().blockBreakAdditionalPenalty.value;
this.backtrackCostFavoringCoefficient = Baritone.settings().backtrackCostFavoringCoefficient.value;
this.jumpPenalty = Baritone.settings().jumpPenalty.value;
this.walkOnWaterOnePenalty = Baritone.settings().walkOnWaterOnePenalty.value;
// why cache these things here, why not let the movements just get directly from settings?
@ -123,21 +129,32 @@ public class CalculationContext {
return get(x, y, z).getBlock();
}
public boolean canPlaceThrowawayAt(int x, int y, int z) {
public double costOfPlacingAt(int x, int y, int z) {
if (!hasThrowaway) { // only true if allowPlace is true, see constructor
return false;
return COST_INF;
}
if (isPossiblyProtected(x, y, z)) {
return false;
return COST_INF;
}
return worldBorder.canPlaceAt(x, z); // TODO perhaps MovementHelper.canPlaceAgainst could also use this?
if (!worldBorder.canPlaceAt(x, z)) {
// TODO perhaps MovementHelper.canPlaceAgainst could also use this?
return COST_INF;
}
return placeBlockCost;
}
public boolean canBreakAt(int x, int y, int z) {
public double breakCostMultiplierAt(int x, int y, int z) {
if (!allowBreak) {
return false;
return COST_INF;
}
return !isPossiblyProtected(x, y, z);
if (isPossiblyProtected(x, y, z)) {
return COST_INF;
}
return 1;
}
public double placeBucketCost() {
return placeBlockCost; // shrug
}
public boolean isPossiblyProtected(int x, int y, int z) {

View File

@ -34,7 +34,7 @@ import java.util.Optional;
public abstract class Movement implements IMovement, MovementHelper {
protected static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN};
public static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN};
protected final IBaritone baritone;
protected final IPlayerContext ctx;
@ -76,31 +76,28 @@ public abstract class Movement implements IMovement, MovementHelper {
this(baritone, src, dest, toBreak, null);
}
@Override
public double getCost() {
public double getCost() throws NullPointerException {
return cost;
}
public double getCost(CalculationContext context) {
if (cost == null) {
cost = calculateCost(new CalculationContext(baritone));
cost = calculateCost(context);
}
return cost;
}
public abstract double calculateCost(CalculationContext context);
@Override
public double recalculateCost() {
public double recalculateCost(CalculationContext context) {
cost = null;
return getCost();
return getCost(context);
}
public void override(double cost) {
this.cost = cost;
}
@Override
public double calculateCostWithoutCaching() {
return calculateCost(new CalculationContext(baritone));
}
/**
* Handles the execution of the latest Movement
* State, and offers a Status to the calling class.

View File

@ -30,12 +30,8 @@ import baritone.utils.ToolSet;
import net.minecraft.block.*;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemPickaxe;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
@ -85,6 +81,9 @@ public interface MovementHelper extends ActionCosts, Helper {
// be opened by just interacting.
return block != Blocks.IRON_DOOR;
}
if (block == Blocks.CARPET) {
return canWalkOn(bsi, x, y - 1, z);
}
boolean snow = block instanceof BlockSnow;
boolean trapdoor = block instanceof BlockTrapDoor;
if (snow || trapdoor) {
@ -327,20 +326,22 @@ public interface MovementHelper extends ActionCosts, Helper {
}
static boolean canPlaceAgainst(BlockStateInterface bsi, int x, int y, int z) {
return canPlaceAgainst(bsi.get0(x, y, z));
return canPlaceAgainst(bsi, x, y, z, bsi.get0(x, y, z));
}
static boolean canPlaceAgainst(BlockStateInterface bsi, BlockPos pos) {
return canPlaceAgainst(bsi.get0(pos.getX(), pos.getY(), pos.getZ()));
return canPlaceAgainst(bsi, pos.getX(), pos.getY(), pos.getZ());
}
static boolean canPlaceAgainst(IPlayerContext ctx, BlockPos pos) {
return canPlaceAgainst(new BlockStateInterface(ctx), pos);
}
static boolean canPlaceAgainst(IBlockState state) {
// TODO isBlockNormalCube isn't the best check for whether or not we can place a block against it. e.g. glass isn't normalCube but we can place against it
return state.isBlockNormalCube();
static boolean canPlaceAgainst(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
// can we look at the center of a side face of this block and likely be able to place?
// (thats how this check is used)
// therefore dont include weird things that we technically could place against (like carpet) but practically can't
return state.isBlockNormalCube() || state.isFullBlock() || state.getBlock() == Blocks.GLASS || state.getBlock() == Blocks.STAINED_GLASS;
}
static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, boolean includeFalling) {
@ -350,7 +351,8 @@ public interface MovementHelper extends ActionCosts, Helper {
static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) {
Block block = state.getBlock();
if (!canWalkThrough(context.bsi, x, y, z, state)) {
if (!context.canBreakAt(x, y, z)) {
double mult = context.breakCostMultiplierAt(x, y, z);
if (mult >= COST_INF) {
return COST_INF;
}
if (avoidBreaking(context.bsi, x, y, z, state)) {
@ -367,6 +369,7 @@ public interface MovementHelper extends ActionCosts, Helper {
double result = m / strVsBlock;
result += context.breakBlockAdditionalCost;
result *= mult;
if (includeFalling) {
IBlockState above = context.get(x, y + 1, z);
if (above.getBlock() instanceof BlockFalling) {
@ -405,42 +408,6 @@ public interface MovementHelper extends ActionCosts, Helper {
ctx.player().inventory.currentItem = ts.getBestSlot(b.getBlock());
}
static boolean throwaway(IPlayerContext ctx, boolean select) {
EntityPlayerSP p = ctx.player();
NonNullList<ItemStack> inv = p.inventory.mainInventory;
for (byte i = 0; i < 9; i++) {
ItemStack item = inv.get(i);
// this usage of settings() is okay because it's only called once during pathing
// (while creating the CalculationContext at the very beginning)
// and then it's called during execution
// since this function is never called during cost calculation, we don't need to migrate
// acceptableThrowawayItems to the CalculationContext
if (Baritone.settings().acceptableThrowawayItems.value.contains(item.getItem())) {
if (select) {
p.inventory.currentItem = i;
}
return true;
}
}
if (Baritone.settings().acceptableThrowawayItems.value.contains(p.inventory.offHandInventory.get(0).getItem())) {
// main hand takes precedence over off hand
// that means that if we have block A selected in main hand and block B in off hand, right clicking places block B
// we've already checked above ^ and the main hand can't possible have an acceptablethrowawayitem
// so we need to select in the main hand something that doesn't right click
// so not a shovel, not a hoe, not a block, etc
for (byte i = 0; i < 9; i++) {
ItemStack item = inv.get(i);
if (item.isEmpty() || item.getItem() instanceof ItemPickaxe) {
if (select) {
p.inventory.currentItem = i;
}
return true;
}
}
}
return false;
}
static void moveTowards(IPlayerContext ctx, MovementState state, BlockPos pos) {
state.setTarget(new MovementTarget(
new Rotation(RotationUtils.calcRotationFromVec3d(ctx.playerHead(),
@ -519,8 +486,7 @@ public interface MovementHelper extends ActionCosts, Helper {
for (int i = 0; i < 5; i++) {
BlockPos against1 = placeAt.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]);
if (MovementHelper.canPlaceAgainst(ctx, against1)) {
//if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(placeAt.getX(), placeAt.getY(), placeAt.getZ())) { // get ready to place a throwaway block
if (!throwaway(ctx, true)) {
if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(placeAt.getX(), placeAt.getY(), placeAt.getZ())) { // get ready to place a throwaway block
Helper.HELPER.logDebug("bb pls get me some blocks. dirt or cobble");
state.setStatus(MovementStatus.UNREACHABLE);
return PlaceResult.NO_OPTION;

View File

@ -53,14 +53,16 @@ public class MovementAscend extends Movement {
public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
IBlockState toPlace = context.get(destX, y, destZ);
boolean hasToPlace = false;
double additionalPlacementCost = 0;
if (!MovementHelper.canWalkOn(context.bsi, destX, y, destZ, toPlace)) {
if (!context.canPlaceThrowawayAt(destX, y, destZ)) {
additionalPlacementCost = context.costOfPlacingAt(destX, y, destZ);
if (additionalPlacementCost >= COST_INF) {
return COST_INF;
}
if (!MovementHelper.isReplacable(destX, y, destZ, toPlace, context.bsi)) {
return COST_INF;
}
boolean foundPlaceOption = false;
for (int i = 0; i < 5; i++) {
int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset();
int againstY = y + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getYOffset();
@ -69,11 +71,11 @@ public class MovementAscend extends Movement {
continue;
}
if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) {
hasToPlace = true;
foundPlaceOption = true;
break;
}
}
if (!hasToPlace) { // didn't find a valid place =(
if (!foundPlaceOption) { // didn't find a valid place =(
return COST_INF;
}
}
@ -124,10 +126,7 @@ public class MovementAscend extends Movement {
walk += context.jumpPenalty;
}
double totalCost = walk;
if (hasToPlace) {
totalCost += context.placeBlockCost;
}
double totalCost = walk + additionalPlacementCost;
// start with srcUp2 since we already have its state
// includeFalling isn't needed because of the falling check above -- if srcUp3 is falling we will have already exited with COST_INF if we'd actually have to break it
totalCost += MovementHelper.getMiningDurationTicks(context, x, y + 2, z, srcUp2, false);
@ -222,4 +221,10 @@ public class MovementAscend extends Movement {
}
return true;
}
@Override
public boolean safeToCancel(MovementState state) {
// if we had to place, don't allow pause
return state.getStatus() != MovementStatus.RUNNING || ticksWithoutPlacement == 0;
}
}

View File

@ -186,7 +186,7 @@ public class MovementDescend extends Movement {
res.x = destX;
res.y = newY + 1;// this is the block we're falling onto, so dest is +1
res.z = destZ;
res.cost = tentativeCost + context.placeBlockCost;
res.cost = tentativeCost + context.placeBucketCost();
return true;
} else {
return false;

View File

@ -120,9 +120,11 @@ public class MovementParkour extends Movement {
if (!context.allowParkourPlace) {
return;
}
// time 2 pop off with that dank skynet parkour place
int destX = x + 4 * xDiff;
int destZ = z + 4 * zDiff;
if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) {
double placeCost = context.costOfPlacingAt(destX, y - 1, destZ);
if (placeCost >= COST_INF) {
return;
}
IBlockState toReplace = context.get(destX, y - 1, destZ);
@ -140,7 +142,7 @@ public class MovementParkour extends Movement {
res.x = destX;
res.y = y;
res.z = destZ;
res.cost = costFromJumpDistance(4) + context.placeBlockCost + context.jumpPenalty;
res.cost = costFromJumpDistance(4) + placeCost + context.jumpPenalty;
return;
}
}

View File

@ -17,6 +17,7 @@
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.api.IBaritone;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos;
@ -76,8 +77,16 @@ public class MovementPillar extends Movement {
return LADDER_UP_ONE_COST; // allow ascending pillars of water, but only if we're already in one
}
}
if (!ladder && !context.canPlaceThrowawayAt(x, y, z)) { // we need to place a block where we started to jump on it
return COST_INF;
double placeCost = 0;
if (!ladder) {
// we need to place a block where we started to jump on it
placeCost = context.costOfPlacingAt(x, y, z);
if (placeCost >= COST_INF) {
return COST_INF;
}
if (fromDown.getBlock() == Blocks.AIR) {
placeCost += 0.1; // slightly (1/200th of a second) penalize pillaring on what's currently air
}
}
if (from instanceof BlockLiquid || (fromDown.getBlock() instanceof BlockLiquid && context.assumeWalkOnWater)) {
// otherwise, if we're standing in water, we cannot pillar
@ -115,7 +124,7 @@ public class MovementPillar extends Movement {
if (ladder) {
return LADDER_UP_ONE_COST + hardness * 5;
} else {
return JUMP_ONE_BLOCK_COST + context.placeBlockCost + context.jumpPenalty + hardness;
return JUMP_ONE_BLOCK_COST + placeCost + context.jumpPenalty + hardness;
}
}
@ -199,7 +208,7 @@ public class MovementPillar extends Movement {
return state;
} else {
// Get ready to place a throwaway block
if (!MovementHelper.throwaway(ctx, true)) {
if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(src.x, src.y, src.z)) {
return state.setStatus(MovementStatus.UNREACHABLE);
}

View File

@ -113,7 +113,8 @@ public class MovementTraverse extends Movement {
// this happens when assume walk on water is true and this is a traverse in water, which isn't allowed
return COST_INF;
}
if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) {
double placeCost = context.costOfPlacingAt(destX, y - 1, destZ);
if (placeCost >= COST_INF) {
return COST_INF;
}
double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false);
@ -130,7 +131,7 @@ public class MovementTraverse extends Movement {
continue;
}
if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) { // found a side place option
return WC + context.placeBlockCost + hardness1 + hardness2;
return WC + placeCost + hardness1 + hardness2;
}
}
// now that we've checked all possible directions to side place, we actually need to backplace
@ -141,7 +142,7 @@ public class MovementTraverse extends Movement {
return COST_INF; // this is obviously impossible
}
WC = WC * (SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST);//since we are sneak backplacing, we are sneaking lol
return WC + context.placeBlockCost + hardness1 + hardness2;
return WC + placeCost + hardness1 + hardness2;
}
return COST_INF;
}

View File

@ -230,14 +230,14 @@ public class PathExecutor implements IPathExecutor, Helper {
// do this only once, when the movement starts, and deliberately get the cost as cached when this path was calculated, not the cost as it is right now
currentMovementOriginalCostEstimate = movement.getCost();
for (int i = 1; i < Baritone.settings().costVerificationLookahead.value && pathPosition + i < path.length() - 1; i++) {
if (path.movements().get(pathPosition + i).calculateCostWithoutCaching() >= ActionCosts.COST_INF && canCancel) {
if (((Movement) path.movements().get(pathPosition + i)).calculateCost(behavior.secretInternalGetCalculationContext()) >= ActionCosts.COST_INF && canCancel) {
logDebug("Something has changed in the world and a future movement has become impossible. Cancelling.");
cancel();
return true;
}
}
}
double currentCost = movement.recalculateCost();
double currentCost = ((Movement) movement).recalculateCost(behavior.secretInternalGetCalculationContext());
if (currentCost >= ActionCosts.COST_INF && canCancel) {
logDebug("Something has changed in the world and this movement has become impossible. Cancelling.");
cancel();

View File

@ -0,0 +1,661 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package baritone.process;
import baritone.Baritone;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.goals.GoalBlock;
import baritone.api.pathing.goals.GoalComposite;
import baritone.api.pathing.goals.GoalGetToBlock;
import baritone.api.process.IBuilderProcess;
import baritone.api.process.PathingCommand;
import baritone.api.process.PathingCommandType;
import baritone.api.utils.*;
import baritone.api.utils.input.Input;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.utils.BaritoneProcessHelper;
import baritone.utils.BlockStateInterface;
import baritone.utils.PathingCommandContext;
import baritone.utils.schematic.AirSchematic;
import baritone.utils.schematic.Schematic;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
public class BuilderProcess extends BaritoneProcessHelper implements IBuilderProcess {
public BuilderProcess(Baritone baritone) {
super(baritone);
}
private HashSet<BetterBlockPos> incorrectPositions;
private String name;
private ISchematic schematic;
private Vec3i origin;
private int ticks;
public boolean build(String schematicFile, BlockPos origin) {
File file = new File(new File(Minecraft.getMinecraft().gameDir, "schematics"), schematicFile);
System.out.println(file + " " + file.exists());
return build(schematicFile, file, origin);
}
@Override
public void build(String name, ISchematic schematic, Vec3i origin) {
this.name = name;
this.schematic = schematic;
this.origin = origin;
}
@Override
public boolean build(String name, File schematic, Vec3i origin) {
NBTTagCompound tag;
try (FileInputStream fileIn = new FileInputStream(schematic)) {
tag = CompressedStreamTools.readCompressed(fileIn);
} catch (IOException e) {
e.printStackTrace();
return false;
}
if (tag == null) {
return false;
}
build(name, parse(tag), origin);
return true;
}
public void clearArea(BlockPos corner1, BlockPos corner2) {
BlockPos origin = new BlockPos(Math.min(corner1.getX(), corner2.getX()), Math.min(corner1.getY(), corner2.getY()), Math.min(corner1.getZ(), corner2.getZ()));
int widthX = Math.abs(corner1.getX() - corner2.getX()) + 1;
int heightY = Math.abs(corner1.getY() - corner2.getY()) + 1;
int lengthZ = Math.abs(corner1.getZ() - corner2.getZ()) + 1;
build("clear area", new AirSchematic(widthX, heightY, lengthZ), origin);
}
private static ISchematic parse(NBTTagCompound schematic) {
return new Schematic(schematic);
}
@Override
public boolean isActive() {
return schematic != null;
}
public IBlockState placeAt(int x, int y, int z) {
if (!isActive()) {
return null;
}
if (!schematic.inSchematic(x - origin.getX(), y - origin.getY(), z - origin.getZ())) {
return null;
}
IBlockState state = schematic.desiredState(x - origin.getX(), y - origin.getY(), z - origin.getZ());
if (state.getBlock() == Blocks.AIR) {
return null;
}
return state;
}
public Optional<Tuple<BetterBlockPos, Rotation>> toBreakNearPlayer(BuilderCalculationContext bcc) {
BetterBlockPos center = ctx.playerFeet();
for (int dx = -5; dx <= 5; dx++) {
for (int dy = 0; dy <= 5; dy++) {
for (int dz = -5; dz <= 5; dz++) {
int x = center.x + dx;
int y = center.y + dy;
int z = center.z + dz;
IBlockState desired = bcc.getSchematic(x, y, z);
if (desired == null) {
continue; // irrelevant
}
IBlockState curr = bcc.bsi.get0(x, y, z);
if (curr.getBlock() != Blocks.AIR && !valid(curr, desired)) {
BetterBlockPos pos = new BetterBlockPos(x, y, z);
Optional<Rotation> rot = RotationUtils.reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
if (rot.isPresent()) {
return Optional.of(new Tuple<>(pos, rot.get()));
}
}
}
}
}
return Optional.empty();
}
public class Placement {
final int hotbarSelection;
final BlockPos placeAgainst;
final EnumFacing side;
final Rotation rot;
public Placement(int hotbarSelection, BlockPos placeAgainst, EnumFacing side, Rotation rot) {
this.hotbarSelection = hotbarSelection;
this.placeAgainst = placeAgainst;
this.side = side;
this.rot = rot;
}
}
public Optional<Placement> searchForPlacables(BuilderCalculationContext bcc, List<IBlockState> desirableOnHotbar) {
BetterBlockPos center = ctx.playerFeet();
for (int dx = -5; dx <= 5; dx++) {
for (int dy = -5; dy <= 1; dy++) {
for (int dz = -5; dz <= 5; dz++) {
int x = center.x + dx;
int y = center.y + dy;
int z = center.z + dz;
IBlockState desired = bcc.getSchematic(x, y, z);
if (desired == null) {
continue; // irrelevant
}
IBlockState curr = bcc.bsi.get0(x, y, z);
if (MovementHelper.isReplacable(x, y, z, curr, bcc.bsi) && !valid(curr, desired)) {
if (dy == 1 && bcc.bsi.get0(x, y + 1, z).getBlock() == Blocks.AIR) {
continue;
}
desirableOnHotbar.add(desired);
Optional<Placement> opt = possibleToPlace(desired, x, y, z, bcc.bsi);
if (opt.isPresent()) {
return opt;
}
}
}
}
}
return Optional.empty();
}
public Optional<Placement> possibleToPlace(IBlockState toPlace, int x, int y, int z, BlockStateInterface bsi) {
for (EnumFacing against : EnumFacing.values()) {
BetterBlockPos placeAgainstPos = new BetterBlockPos(x, y, z).offset(against);
IBlockState placeAgainstState = bsi.get0(placeAgainstPos);
if (MovementHelper.isReplacable(placeAgainstPos.x, placeAgainstPos.y, placeAgainstPos.z, placeAgainstState, bsi)) {
continue;
}
if (!ctx.world().mayPlace(toPlace.getBlock(), new BetterBlockPos(x, y, z), false, against, null)) {
continue;
}
AxisAlignedBB aabb = placeAgainstState.getBoundingBox(ctx.world(), placeAgainstPos);
for (Vec3d placementMultiplier : aabbSideMultipliers(against)) {
double placeX = placeAgainstPos.x + aabb.minX * placementMultiplier.x + aabb.maxX * (1 - placementMultiplier.x);
double placeY = placeAgainstPos.y + aabb.minY * placementMultiplier.y + aabb.maxY * (1 - placementMultiplier.y);
double placeZ = placeAgainstPos.z + aabb.minZ * placementMultiplier.z + aabb.maxZ * (1 - placementMultiplier.z);
Rotation rot = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(placeX, placeY, placeZ), ctx.playerRotations());
RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot, ctx.playerController().getBlockReachDistance());
if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK && result.getBlockPos().equals(placeAgainstPos) && result.sideHit == against.getOpposite()) {
OptionalInt hotbar = hasAnyItemThatWouldPlace(toPlace, result, rot);
if (hotbar.isPresent()) {
return Optional.of(new Placement(hotbar.getAsInt(), placeAgainstPos, against.getOpposite(), rot));
}
}
}
}
return Optional.empty();
}
public OptionalInt hasAnyItemThatWouldPlace(IBlockState desired, RayTraceResult result, Rotation rot) {
for (int i = 0; i < 9; i++) {
ItemStack stack = ctx.player().inventory.mainInventory.get(i);
if (stack.isEmpty() || !(stack.getItem() instanceof ItemBlock)) {
continue;
}
float originalYaw = ctx.player().rotationYaw;
float originalPitch = ctx.player().rotationPitch;
// the state depends on the facing of the player sometimes
ctx.player().rotationYaw = rot.getYaw();
ctx.player().rotationPitch = rot.getPitch();
IBlockState wouldBePlaced = ((ItemBlock) stack.getItem()).getBlock().getStateForPlacement(
ctx.world(),
result.getBlockPos().offset(result.sideHit),
result.sideHit,
(float) result.hitVec.x - result.getBlockPos().getX(), // as in PlayerControllerMP
(float) result.hitVec.y - result.getBlockPos().getY(),
(float) result.hitVec.z - result.getBlockPos().getZ(),
stack.getItem().getMetadata(stack.getMetadata()),
ctx.player()
);
ctx.player().rotationYaw = originalYaw;
ctx.player().rotationPitch = originalPitch;
if (valid(wouldBePlaced, desired)) {
return OptionalInt.of(i);
}
}
return OptionalInt.empty();
}
private static Vec3d[] aabbSideMultipliers(EnumFacing side) {
switch (side) {
case UP:
return new Vec3d[]{new Vec3d(0.5, 1, 0.5), new Vec3d(0.1, 1, 0.5), new Vec3d(0.9, 1, 0.5), new Vec3d(0.5, 1, 0.1), new Vec3d(0.5, 1, 0.9)};
case DOWN:
return new Vec3d[]{new Vec3d(0.5, 0, 0.5), new Vec3d(0.1, 0, 0.5), new Vec3d(0.9, 0, 0.5), new Vec3d(0.5, 0, 0.1), new Vec3d(0.5, 0, 0.9)};
case NORTH:
case SOUTH:
case EAST:
case WEST:
double x = side.getXOffset() == 0 ? 0.5 : (1 + side.getXOffset()) / 2D;
double z = side.getZOffset() == 0 ? 0.5 : (1 + side.getZOffset()) / 2D;
return new Vec3d[]{new Vec3d(x, 0.25, z), new Vec3d(x, 0.75, z)};
default: // null
throw new NullPointerException();
}
}
@Override
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
// TODO somehow tell inventorybehavior what we'd like to have on the hotbar
// perhaps take the 16 closest positions in incorrectPositions to ctx.playerFeet that aren't desired to be air, and then snag the top 4 most common block states, then request those on the hotbar
// this will work as is, but it'll be trashy
// need to iterate over incorrectPositions and see which ones we can "correct" from our current standing position
baritone.getInputOverrideHandler().clearAllKeys();
BuilderCalculationContext bcc = new BuilderCalculationContext();
if (!recalc(bcc)) {
logDirect("Done building");
onLostControl();
return null;
}
trim(bcc);
if (baritone.getInputOverrideHandler().isInputForcedDown(Input.CLICK_LEFT)) {
ticks = 5;
} else {
ticks--;
}
Optional<Tuple<BetterBlockPos, Rotation>> toBreak = toBreakNearPlayer(bcc);
baritone.getInputOverrideHandler().clearAllKeys();
if (toBreak.isPresent() && isSafeToCancel && ctx.player().onGround) {
// we'd like to pause to break this block
// only change look direction if it's safe (don't want to fuck up an in progress parkour for example
Rotation rot = toBreak.get().getSecond();
BetterBlockPos pos = toBreak.get().getFirst();
baritone.getLookBehavior().updateTarget(rot, true);
MovementHelper.switchToBestToolFor(ctx, bcc.get(pos));
if (ctx.player().isSneaking()) {
// really horrible bug where a block is visible for breaking while sneaking but not otherwise
// so you can't see it, it goes to place something else, sneaks, then the next tick it tries to break
// and is unable since it's unsneaked in the intermediary tick
baritone.getInputOverrideHandler().setInputForceState(Input.SNEAK, true);
}
if (Objects.equals(ctx.objectMouseOver().getBlockPos(), pos) || ctx.playerRotations().isReallyCloseTo(rot)) {
baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true);
}
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
}
List<IBlockState> desirableOnHotbar = new ArrayList<>();
Optional<Placement> toPlace = searchForPlacables(bcc, desirableOnHotbar);
if (toPlace.isPresent() && isSafeToCancel && ctx.player().onGround && ticks <= 0) {
Rotation rot = toPlace.get().rot;
baritone.getLookBehavior().updateTarget(rot, true);
ctx.player().inventory.currentItem = toPlace.get().hotbarSelection;
baritone.getInputOverrideHandler().setInputForceState(Input.SNEAK, true);
if ((Objects.equals(ctx.objectMouseOver().getBlockPos(), toPlace.get().placeAgainst) && ctx.objectMouseOver().sideHit.equals(toPlace.get().side)) || ctx.playerRotations().isReallyCloseTo(rot)) {
baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true);
}
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
}
List<IBlockState> approxPlacable = placable(36);
if (Baritone.settings().allowInventory.value) {
ArrayList<Integer> usefulSlots = new ArrayList<>();
List<IBlockState> noValidHotbarOption = new ArrayList<>();
outer:
for (IBlockState desired : desirableOnHotbar) {
for (int i = 0; i < 9; i++) {
if (valid(approxPlacable.get(i), desired)) {
usefulSlots.add(i);
continue outer;
}
}
noValidHotbarOption.add(desired);
}
outer:
for (int i = 9; i < 36; i++) {
for (IBlockState desired : noValidHotbarOption) {
if (valid(approxPlacable.get(i), desired)) {
baritone.getInventoryBehavior().attemptToPutOnHotbar(i, usefulSlots::contains);
break outer;
}
}
}
}
Goal goal = assemble(bcc, approxPlacable.subList(0, 9));
if (goal == null) {
goal = assemble(bcc, approxPlacable); // we're far away, so assume that we have our whole inventory to recalculate placable properly
if (goal == null) {
logDirect("Unable to do it =(");
onLostControl();
return null;
}
}
return new PathingCommandContext(goal, PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH, bcc);
}
public boolean recalc(BuilderCalculationContext bcc) {
if (incorrectPositions == null) {
incorrectPositions = new HashSet<>();
fullRecalc(bcc);
if (incorrectPositions.isEmpty()) {
return false;
}
}
recalcNearby(bcc);
if (incorrectPositions.isEmpty()) {
fullRecalc(bcc);
}
return !incorrectPositions.isEmpty();
}
public void trim(BuilderCalculationContext bcc) {
HashSet<BetterBlockPos> copy = new HashSet<>(incorrectPositions);
copy.removeIf(pos -> pos.distanceSq(ctx.player().posX, ctx.player().posY, ctx.player().posZ) > 200);
if (!copy.isEmpty()) {
incorrectPositions = copy;
}
}
public void recalcNearby(BuilderCalculationContext bcc) {
BetterBlockPos center = ctx.playerFeet();
for (int dx = -5; dx <= 5; dx++) {
for (int dy = -5; dy <= 5; dy++) {
for (int dz = -5; dz <= 5; dz++) {
int x = center.x + dx;
int y = center.y + dy;
int z = center.z + dz;
IBlockState desired = bcc.getSchematic(x, y, z);
if (desired != null) {
// we care about this position
if (valid(bcc.bsi.get0(x, y, z), desired)) {
incorrectPositions.remove(new BetterBlockPos(x, y, z));
} else {
incorrectPositions.add(new BetterBlockPos(x, y, z));
}
}
}
}
}
}
public void fullRecalc(BuilderCalculationContext bcc) {
incorrectPositions = new HashSet<>();
for (int y = 0; y < schematic.heightY(); y++) {
for (int z = 0; z < schematic.lengthZ(); z++) {
for (int x = 0; x < schematic.widthX(); x++) {
if (schematic.inSchematic(x, y, z)) {
if (!valid(bcc.bsi.get0(x + origin.getX(), y + origin.getY(), z + origin.getZ()), schematic.desiredState(x, y, z))) {
incorrectPositions.add(new BetterBlockPos(x + origin.getX(), y + origin.getY(), z + origin.getZ()));
}
}
}
}
}
}
private Goal assemble(BuilderCalculationContext bcc, List<IBlockState> approxPlacable) {
List<BetterBlockPos> placable = incorrectPositions.stream().filter(pos -> bcc.bsi.get0(pos).getBlock() == Blocks.AIR && approxPlacable.contains(bcc.getSchematic(pos.x, pos.y, pos.z))).collect(Collectors.toList());
Goal[] toBreak = incorrectPositions.stream().filter(pos -> bcc.bsi.get0(pos).getBlock() != Blocks.AIR).map(GoalBreak::new).toArray(Goal[]::new);
Goal[] toPlace = placable.stream().filter(pos -> !placable.contains(pos.down()) && !placable.contains(pos.down(2))).map(pos -> placementgoal(pos, bcc)).toArray(Goal[]::new);
if (toPlace.length != 0) {
return new JankyGoalComposite(new GoalComposite(toPlace), new GoalComposite(toBreak));
}
if (toBreak.length == 0) {
return null;
}
return new GoalComposite(toBreak);
}
public static class JankyGoalComposite implements Goal {
private final Goal primary;
private final Goal fallback;
public JankyGoalComposite(Goal primary, Goal fallback) {
this.primary = primary;
this.fallback = fallback;
}
@Override
public boolean isInGoal(int x, int y, int z) {
return primary.isInGoal(x, y, z) || fallback.isInGoal(x, y, z);
}
@Override
public double heuristic(int x, int y, int z) {
return primary.heuristic(x, y, z);
}
@Override
public String toString() {
return "JankyComposite Primary: " + primary + " Fallback: " + fallback;
}
}
public static class GoalBreak extends GoalGetToBlock {
public GoalBreak(BlockPos pos) {
super(pos);
}
@Override
public boolean isInGoal(int x, int y, int z) {
// can't stand right on top of a block, that might not work (what if it's unsupported, can't break then)
if (y > this.y) {
return false;
}
// but any other adjacent works for breaking, including inside or below
return super.isInGoal(x, y, z);
}
}
public Goal placementgoal(BlockPos pos, BuilderCalculationContext bcc) {
if (ctx.world().getBlockState(pos).getBlock() != Blocks.AIR) {
return new GoalPlace(pos);
}
boolean allowSameLevel = ctx.world().getBlockState(pos.up()).getBlock() != Blocks.AIR;
for (EnumFacing facing : Movement.HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP) {
if (MovementHelper.canPlaceAgainst(ctx, pos.offset(facing)) && ctx.world().mayPlace(bcc.getSchematic(pos.getX(), pos.getY(), pos.getZ()).getBlock(), pos, false, facing, null)) {
return new GoalAdjacent(pos, allowSameLevel);
}
}
return new GoalPlace(pos);
}
public static class GoalAdjacent extends GoalGetToBlock {
boolean allowSameLevel;
public GoalAdjacent(BlockPos pos, boolean allowSameLevel) {
super(pos);
this.allowSameLevel = allowSameLevel;
}
public boolean isInGoal(int x, int y, int z) {
if (x == this.x && y == this.y && z == this.z) {
return false;
}
if (!allowSameLevel && y == this.y - 1) {
return false;
}
if (y < this.y - 1) {
return false;
}
return super.isInGoal(x, y, z);
}
public double heuristic(int x, int y, int z) {
// prioritize lower y coordinates
return this.y * 100 + super.heuristic(x, y, z);
}
}
public static class GoalPlace extends GoalBlock {
public GoalPlace(BlockPos placeAt) {
super(placeAt.up());
}
public double heuristic(int x, int y, int z) {
// prioritize lower y coordinates
return this.y * 100 + super.heuristic(x, y, z);
}
}
@Override
public void onLostControl() {
incorrectPositions = null;
name = null;
schematic = null;
}
@Override
public String displayName() {
return "Building " + name;
}
public List<IBlockState> placable(int size) {
List<IBlockState> result = new ArrayList<>();
for (int i = 0; i < size; i++) {
ItemStack stack = ctx.player().inventory.mainInventory.get(i);
if (stack.isEmpty() || !(stack.getItem() instanceof ItemBlock)) {
result.add(Blocks.AIR.getDefaultState());
continue;
}
// <toxic cloud>
result.add(((ItemBlock) stack.getItem()).getBlock().getStateForPlacement(ctx.world(), ctx.playerFeet(), EnumFacing.UP, (float) ctx.player().posX, (float) ctx.player().posY, (float) ctx.player().posZ, stack.getItem().getMetadata(stack.getMetadata()), ctx.player()));
// </toxic cloud>
}
return result;
}
public boolean valid(IBlockState current, IBlockState desired) {
// TODO more complicated comparison logic I guess
return desired == null || current.equals(desired);
}
public class BuilderCalculationContext extends CalculationContext {
private final List<IBlockState> placable;
private final ISchematic schematic;
private final int originX;
private final int originY;
private final int originZ;
public BuilderCalculationContext() {
super(BuilderProcess.this.baritone, true); // wew lad
this.placable = placable(9);
this.schematic = BuilderProcess.this.schematic;
this.originX = origin.getX();
this.originY = origin.getY();
this.originZ = origin.getZ();
this.jumpPenalty += 10;
this.backtrackCostFavoringCoefficient = 1;
}
private IBlockState getSchematic(int x, int y, int z) {
if (schematic.inSchematic(x - originX, y - originY, z - originZ)) {
return schematic.desiredState(x - originX, y - originY, z - originZ);
} else {
return null;
}
}
@Override
public double costOfPlacingAt(int x, int y, int z) {
if (isPossiblyProtected(x, y, z) || !worldBorder.canPlaceAt(x, z)) { // make calculation fail properly if we can't build
return COST_INF;
}
IBlockState sch = getSchematic(x, y, z);
if (sch != null) {
// TODO this can return true even when allowPlace is off.... is that an issue?
if (sch.getBlock() == Blocks.AIR) {
// we want this to be air, but they're asking if they can place here
// this won't be a schematic block, this will be a throwaway
return placeBlockCost * 2; // we're going to have to break it eventually
}
if (placable.contains(sch)) {
return 0; // thats right we gonna make it FREE to place a block where it should go in a structure
// no place block penalty at all 😎
// i'm such an idiot that i just tried to copy and paste the epic gamer moment emoji too
// get added to unicode when?
}
if (!hasThrowaway) {
return COST_INF;
}
// we want it to be something that we don't have
// even more of a pain to place something wrong
return placeBlockCost * 3;
} else {
if (hasThrowaway) {
return placeBlockCost;
} else {
return COST_INF;
}
}
}
@Override
public double breakCostMultiplierAt(int x, int y, int z) {
if (!allowBreak || isPossiblyProtected(x, y, z)) {
return COST_INF;
}
IBlockState sch = getSchematic(x, y, z);
if (sch != null) {
if (sch.getBlock() == Blocks.AIR) {
// it should be air
// regardless of current contents, we can break it
return 1;
}
// it should be a real block
// is it already that block?
if (valid(bsi.get0(x, y, z), sch)) {
return 3;
} else {
// can break if it's wrong
// would be great to return less than 1 here, but that would actually make the cost calculation messed up
// since we're breaking a block, if we underestimate the cost, then it'll fail when it really takes the correct amount of time
return 1;
}
// TODO do blocks in render distace only?
// TODO allow breaking blocks that we have a tool to harvest and immediately place back?
} else {
return 1; // why not lol
}
}
}
}

View File

@ -266,6 +266,22 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
logDirect("Queued " + count + " chunks for repacking");
return true;
}
if (msg.startsWith("build")) {
String file;
BlockPos origin;
try {
String[] coords = msg.substring("build".length()).trim().split(" ");
file = coords[0] + ".schematic";
origin = new BlockPos(parseOrDefault(coords[1], ctx.playerFeet().x), parseOrDefault(coords[2], ctx.playerFeet().y), parseOrDefault(coords[3], ctx.playerFeet().z));
} catch (Exception ex) {
file = msg.substring(5).trim() + ".schematic";
origin = ctx.playerFeet();
}
logDirect("Loading '" + file + "' to build from origin " + origin);
boolean success = baritone.getBuilderProcess().build(file, origin);
logDirect(success ? "Loaded" : "Unable to load");
return true;
}
if (msg.equals("come")) {
customGoalProcess.setGoalAndPath(new GoalBlock(new BlockPos(mc.getRenderViewEntity())));
logDirect("Coming");
@ -311,6 +327,32 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
});
return true;
}
if (msg.startsWith("cleararea")) {
String suffix = msg.substring("cleararea".length());
BlockPos corner1;
BlockPos corner2;
if (suffix.isEmpty()) {
// clear the area from the current goal to here
Goal goal = baritone.getPathingBehavior().getGoal();
if (goal == null || !(goal instanceof GoalBlock)) {
logDirect("Need to specify goal of opposite corner");
return true;
}
corner1 = ((GoalBlock) goal).getGoalPos();
corner2 = ctx.playerFeet();
} else {
try {
String[] spl = suffix.split(" ");
corner1 = ctx.playerFeet();
corner2 = new BlockPos(Integer.parseInt(spl[0]), Integer.parseInt(spl[1]), Integer.parseInt(spl[2]));
} catch (NumberFormatException | ArrayIndexOutOfBoundsException | NullPointerException ex) {
logDirect("unable to parse");
return true;
}
}
baritone.getBuilderProcess().clearArea(corner1, corner2);
return true;
}
if (msg.equals("reset")) {
for (Settings.Setting setting : Baritone.settings().allSettings) {
setting.reset();
@ -573,7 +615,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
while (moves.contains(null)) {
moves.remove(null);
}
moves.sort(Comparator.comparingDouble(Movement::getCost));
moves.sort(Comparator.comparingDouble(move -> move.getCost(new CalculationContext(baritone))));
for (Movement move : moves) {
String[] parts = move.getClass().toString().split("\\.");
double cost = move.getCost();
@ -591,6 +633,10 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
return false;
}
private int parseOrDefault(String str, int i) {
return str.equals("~") ? i : Integer.parseInt(str);
}
private void log(List<ItemStack> stacks) {
for (ItemStack stack : stacks) {
if (!stack.isEmpty()) {

View File

@ -17,12 +17,15 @@
package baritone.utils;
import baritone.Baritone;
import baritone.api.BaritoneAPI;
import baritone.api.pathing.goals.GoalBlock;
import baritone.api.pathing.goals.GoalTwoBlocks;
import baritone.api.utils.BetterBlockPos;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
@ -31,7 +34,6 @@ import org.lwjgl.input.Mouse;
import org.lwjgl.util.glu.GLU;
import java.awt.*;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Collections;
@ -46,7 +48,8 @@ public class GuiClickMeme extends GuiScreen {
private final IntBuffer VIEWPORT = BufferUtils.createIntBuffer(16);
private final FloatBuffer TO_WORLD_BUFFER = BufferUtils.createFloatBuffer(3);
private BlockPos meme;
private BlockPos clickStart;
private BlockPos currentMouseOver;
@Override
public boolean doesGuiPauseGame() {
@ -63,19 +66,40 @@ public class GuiClickMeme extends GuiScreen {
Vec3d viewerPos = new Vec3d(mc.getRenderManager().viewerPosX, mc.getRenderManager().viewerPosY, mc.getRenderManager().viewerPosZ);
RayTraceResult result = mc.world.rayTraceBlocks(near.add(viewerPos), far.add(viewerPos), false, false, true);
if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) {
meme = result.getBlockPos();
currentMouseOver = result.getBlockPos();
}
}
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
super.mouseClicked(mouseX, mouseY, mouseButton);
protected void mouseReleased(int mouseX, int mouseY, int mouseButton) {
System.out.println("Mouse released");
if (mouseButton == 0) {
BaritoneAPI.getProvider().getPrimaryBaritone().getCustomGoalProcess().setGoalAndPath(new GoalTwoBlocks(meme));
if (clickStart != null && !clickStart.equals(currentMouseOver)) {
((Baritone) BaritoneAPI.getProvider().getPrimaryBaritone()).getBuilderProcess().clearArea(clickStart, currentMouseOver);
clickStart = null;
} else {
BaritoneAPI.getProvider().getPrimaryBaritone().getCustomGoalProcess().setGoalAndPath(new GoalTwoBlocks(currentMouseOver));
}
} else if (mouseButton == 1) {
BaritoneAPI.getProvider().getPrimaryBaritone().getCustomGoalProcess().setGoalAndPath(new GoalBlock(meme.up()));
BaritoneAPI.getProvider().getPrimaryBaritone().getCustomGoalProcess().setGoalAndPath(new GoalBlock(currentMouseOver.up()));
}
clickStart = null;
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
System.out.println("Mouse clicked");
clickStart = currentMouseOver;
}
@Override
protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
System.out.println("Click move");
}
public void onRender(float partialTicks) {
@ -83,11 +107,30 @@ public class GuiClickMeme extends GuiScreen {
GlStateManager.getFloat(GL_PROJECTION_MATRIX, (FloatBuffer) PROJECTION.clear());
GlStateManager.glGetInteger(GL_VIEWPORT, (IntBuffer) VIEWPORT.clear());
if (meme != null) {
if (currentMouseOver != null) {
Entity e = mc.getRenderViewEntity();
// drawSingleSelectionBox WHEN?
PathRenderer.drawManySelectionBoxes(e, Collections.singletonList(meme), Color.CYAN);
PathRenderer.drawManySelectionBoxes(e, Collections.singletonList(currentMouseOver), Color.CYAN);
if (clickStart != null && !clickStart.equals(currentMouseOver)) {
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
GlStateManager.color(Color.RED.getColorComponents(null)[0], Color.RED.getColorComponents(null)[1], Color.RED.getColorComponents(null)[2], 0.4F);
GlStateManager.glLineWidth(Baritone.settings().pathRenderLineWidthPixels.value);
GlStateManager.disableTexture2D();
GlStateManager.depthMask(false);
GlStateManager.disableDepth();
BetterBlockPos a = new BetterBlockPos(currentMouseOver);
BetterBlockPos b = new BetterBlockPos(clickStart);
PathRenderer.drawAABB(new AxisAlignedBB(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.min(a.z, b.z), Math.max(a.x, b.x) + 1, Math.max(a.y, b.y) + 1, Math.max(a.z, b.z) + 1));
GlStateManager.enableDepth();
GlStateManager.depthMask(true);
GlStateManager.enableTexture2D();
GlStateManager.disableBlend();
}
}
}
public Vec3d toWorld(double x, double y, double z) {

View File

@ -115,4 +115,4 @@ public final class InputOverrideHandler extends Behavior implements IInputOverri
public BlockBreakHelper getBlockBreakHelper() {
return blockBreakHelper;
}
}
}

View File

@ -211,7 +211,7 @@ public final class PathRenderer implements Helper {
GlStateManager.disableDepth();
}
float expand = 0.002F;
//BlockPos blockpos = movingObjectPositionIn.getBlockPos();
BlockStateInterface bsi = new BlockStateInterface(BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext()); // TODO this assumes same dimension between primary baritone and render view? is this safe?
positions.forEach(pos -> {
@ -222,31 +222,7 @@ public final class PathRenderer implements Helper {
} else {
toDraw = state.getSelectedBoundingBox(player.world, pos);
}
toDraw = toDraw.expand(expand, expand, expand).offset(-mc.getRenderManager().viewerPosX, -mc.getRenderManager().viewerPosY, -mc.getRenderManager().viewerPosZ);
BUFFER.begin(GL_LINE_STRIP, DefaultVertexFormats.POSITION);
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.minZ).endVertex();
TESSELLATOR.draw();
BUFFER.begin(GL_LINE_STRIP, DefaultVertexFormats.POSITION);
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).endVertex();
TESSELLATOR.draw();
BUFFER.begin(GL_LINES, DefaultVertexFormats.POSITION);
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).endVertex();
TESSELLATOR.draw();
drawAABB(toDraw);
});
if (Baritone.settings().renderSelectionBoxesIgnoreDepth.value) {
@ -258,6 +234,35 @@ public final class PathRenderer implements Helper {
GlStateManager.disableBlend();
}
public static void drawAABB(AxisAlignedBB aabb) {
float expand = 0.002F;
AxisAlignedBB toDraw = aabb.expand(expand, expand, expand).offset(-mc.getRenderManager().viewerPosX, -mc.getRenderManager().viewerPosY, -mc.getRenderManager().viewerPosZ);
BUFFER.begin(GL_LINE_STRIP, DefaultVertexFormats.POSITION);
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.minZ).endVertex();
TESSELLATOR.draw();
BUFFER.begin(GL_LINE_STRIP, DefaultVertexFormats.POSITION);
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).endVertex();
TESSELLATOR.draw();
BUFFER.begin(GL_LINES, DefaultVertexFormats.POSITION);
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).endVertex();
BUFFER.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).endVertex();
TESSELLATOR.draw();
}
public static void drawDankLitGoalBox(Entity player, Goal goal, float partialTicks, Color color) {
double renderPosX = mc.getRenderManager().viewerPosX;
double renderPosY = mc.getRenderManager().viewerPosY;

View File

@ -0,0 +1,32 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package baritone.utils;
import baritone.api.pathing.goals.Goal;
import baritone.api.process.PathingCommand;
import baritone.api.process.PathingCommandType;
import baritone.pathing.movement.CalculationContext;
public class PathingCommandContext extends PathingCommand {
public final CalculationContext desiredCalcContext;
public PathingCommandContext(Goal goal, PathingCommandType commandType, CalculationContext context) {
super(goal, commandType);
this.desiredCalcContext = context;
}
}

View File

@ -107,18 +107,18 @@ public class PathingControlManager implements IPathingControlManager {
break;
case FORCE_REVALIDATE_GOAL_AND_PATH:
if (!p.isPathing() && !p.getInProgress().isPresent()) {
p.secretInternalSetGoalAndPath(command.goal);
p.secretInternalSetGoalAndPath(command);
}
break;
case REVALIDATE_GOAL_AND_PATH:
if (!p.isPathing() && !p.getInProgress().isPresent()) {
p.secretInternalSetGoalAndPath(command.goal);
p.secretInternalSetGoalAndPath(command);
}
break;
case SET_GOAL_AND_PATH:
// now this i can do
if (command.goal != null) {
baritone.getPathingBehavior().secretInternalSetGoalAndPath(command.goal);
baritone.getPathingBehavior().secretInternalSetGoalAndPath(command);
}
break;
default:
@ -141,13 +141,13 @@ public class PathingControlManager implements IPathingControlManager {
// pwnage
p.softCancelIfSafe();
}
p.secretInternalSetGoalAndPath(command.goal);
p.secretInternalSetGoalAndPath(command);
break;
case REVALIDATE_GOAL_AND_PATH:
if (Baritone.settings().cancelOnGoalInvalidation.value && (command.goal == null || revalidateGoal(command.goal))) {
p.softCancelIfSafe();
}
p.secretInternalSetGoalAndPath(command.goal);
p.secretInternalSetGoalAndPath(command);
break;
default:
}

View File

@ -17,27 +17,27 @@
package baritone.utils.pathing;
import baritone.Baritone;
import baritone.api.pathing.calc.IPath;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.IPlayerContext;
import baritone.pathing.movement.CalculationContext;
import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap;
public final class Favoring {
private final Long2DoubleOpenHashMap favorings;
public Favoring(IPlayerContext ctx, IPath previous) {
this(previous);
public Favoring(IPlayerContext ctx, IPath previous, CalculationContext context) {
this(previous, context);
for (Avoidance avoid : Avoidance.create(ctx)) {
avoid.applySpherical(favorings);
}
System.out.println("Favoring size: " + favorings.size());
}
public Favoring(IPath previous) { // create one just from previous path, no mob avoidances
public Favoring(IPath previous, CalculationContext context) { // create one just from previous path, no mob avoidances
favorings = new Long2DoubleOpenHashMap();
favorings.defaultReturnValue(1.0D);
double coeff = Baritone.settings().backtrackCostFavoringCoefficient.value;
double coeff = context.backtrackCostFavoringCoefficient;
if (coeff != 1D && previous != null) {
previous.positions().forEach(pos -> favorings.put(BetterBlockPos.longHash(pos), coeff));
}

View File

@ -87,7 +87,7 @@ public class SegmentedCalculator {
private PathCalculationResult segment(Optional<IPath> previous) {
BetterBlockPos segmentStart = previous.map(IPath::getDest).orElse(start); // <-- e p i c
AbstractNodeCostSearch search = new AStarPathFinder(segmentStart.x, segmentStart.y, segmentStart.z, goal, new Favoring(previous.orElse(null)), context); // this is on another thread, so cannot include mob avoidances.
AbstractNodeCostSearch search = new AStarPathFinder(segmentStart.x, segmentStart.y, segmentStart.z, goal, new Favoring(previous.orElse(null), context), context); // this is on another thread, so cannot include mob avoidances.
return search.calculate(Baritone.settings().primaryTimeoutMS.value, Baritone.settings().failureTimeoutMS.value); // use normal time settings, not the plan ahead settings, so as to not overwhelm the computer
}

View File

@ -0,0 +1,55 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package baritone.utils.schematic;
import baritone.api.utils.ISchematic;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
public class AirSchematic implements ISchematic {
private final int widthX;
private final int heightY;
private final int lengthZ;
public AirSchematic(int widthX, int heightY, int lengthZ) {
this.widthX = widthX;
this.heightY = heightY;
this.lengthZ = lengthZ;
}
@Override
public IBlockState desiredState(int x, int y, int z) {
return Blocks.AIR.getDefaultState();
}
@Override
public int widthX() {
return widthX;
}
@Override
public int heightY() {
return heightY;
}
@Override
public int lengthZ() {
return lengthZ;
}
}

View File

@ -0,0 +1,66 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package baritone.utils.schematic;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import java.util.OptionalInt;
import java.util.function.Predicate;
public class MapArtSchematic extends Schematic {
private final int[][] heightMap;
public MapArtSchematic(NBTTagCompound schematic) {
super(schematic);
heightMap = new int[widthX][lengthZ];
for (int x = 0; x < widthX; x++) {
for (int z = 0; z < lengthZ; z++) {
IBlockState[] column = states[x][z];
OptionalInt lowestBlockY = lastIndexMatching(column, block -> block != Blocks.AIR);
if (lowestBlockY.isPresent()) {
heightMap[x][z] = lowestBlockY.getAsInt();
} else {
System.out.println("Column " + x + "," + z + " has no blocks, but it's apparently map art? wtf");
System.out.println("Letting it be whatever");
heightMap[x][z] = 256;
}
}
}
}
private static <T> OptionalInt lastIndexMatching(T[] arr, Predicate<? super T> predicate) {
for (int y = arr.length - 1; y >= 0; y--) {
if (predicate.test(arr[y])) {
return OptionalInt.of(y);
}
}
return OptionalInt.empty();
}
@Override
public boolean inSchematic(int x, int y, int z) {
// in map art, we only care about coordinates in or above the art
return super.inSchematic(x, y, z) && y >= heightMap[x][z];
}
}

View File

@ -0,0 +1,89 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package baritone.utils.schematic;
import baritone.api.utils.ISchematic;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.nbt.NBTTagCompound;
public class Schematic implements ISchematic {
public final int widthX;
public final int heightY;
public final int lengthZ;
protected final IBlockState[][][] states;
public Schematic(NBTTagCompound schematic) {
String type = schematic.getString("Materials");
if (!type.equals("Alpha")) {
throw new IllegalStateException("bad schematic " + type);
}
widthX = schematic.getInteger("Width");
heightY = schematic.getInteger("Height");
lengthZ = schematic.getInteger("Length");
byte[] blocks = schematic.getByteArray("Blocks");
byte[] metadata = schematic.getByteArray("Data");
byte[] additional = null;
if (schematic.hasKey("AddBlocks")) {
byte[] addBlocks = schematic.getByteArray("AddBlocks");
additional = new byte[addBlocks.length * 2];
for (int i = 0; i < addBlocks.length; i++) {
additional[i * 2 + 0] = (byte) ((addBlocks[i] >> 4) & 0xF); // lower nibble
additional[i * 2 + 1] = (byte) ((addBlocks[i] >> 0) & 0xF); // upper nibble
}
}
states = new IBlockState[widthX][lengthZ][heightY];
for (int y = 0; y < heightY; y++) {
for (int z = 0; z < lengthZ; z++) {
for (int x = 0; x < widthX; x++) {
int blockInd = (y * lengthZ + z) * widthX + x;
int blockID = blocks[blockInd] & 0xFF;
if (additional != null) {
// additional is 0 through 15 inclusive since it's & 0xF above
blockID |= additional[blockInd] << 8;
}
Block block = Block.REGISTRY.getObjectById(blockID);
int meta = metadata[blockInd] & 0xFF;
states[x][z][y] = block.getStateFromMeta(meta);
}
}
}
}
@Override
public IBlockState desiredState(int x, int y, int z) {
return states[x][z][y];
}
@Override
public int widthX() {
return widthX;
}
@Override
public int heightY() {
return heightY;
}
@Override
public int lengthZ() {
return lengthZ;
}
}