Merge branch 'builder'
This commit is contained in:
commit
2215f170df
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -45,10 +45,6 @@ public interface IMovement {
|
||||
*/
|
||||
boolean safeToCancel();
|
||||
|
||||
double recalculateCost();
|
||||
|
||||
double calculateCostWithoutCaching();
|
||||
|
||||
boolean calculatedWhileLoaded();
|
||||
|
||||
BetterBlockPos getSrc();
|
||||
|
49
src/api/java/baritone/api/process/IBuilderProcess.java
Normal file
49
src/api/java/baritone/api/process/IBuilderProcess.java
Normal 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);
|
||||
}
|
71
src/api/java/baritone/api/utils/ISchematic.java
Normal file
71
src/api/java/baritone/api/utils/ISchematic.java
Normal 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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
661
src/main/java/baritone/process/BuilderProcess.java
Normal file
661
src/main/java/baritone/process/BuilderProcess.java
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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()) {
|
||||
|
@ -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) {
|
||||
|
@ -115,4 +115,4 @@ public final class InputOverrideHandler extends Behavior implements IInputOverri
|
||||
public BlockBreakHelper getBlockBreakHelper() {
|
||||
return blockBreakHelper;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
32
src/main/java/baritone/utils/PathingCommandContext.java
Normal file
32
src/main/java/baritone/utils/PathingCommandContext.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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:
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
55
src/main/java/baritone/utils/schematic/AirSchematic.java
Normal file
55
src/main/java/baritone/utils/schematic/AirSchematic.java
Normal 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;
|
||||
}
|
||||
}
|
66
src/main/java/baritone/utils/schematic/MapArtSchematic.java
Normal file
66
src/main/java/baritone/utils/schematic/MapArtSchematic.java
Normal 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];
|
||||
}
|
||||
}
|
89
src/main/java/baritone/utils/schematic/Schematic.java
Normal file
89
src/main/java/baritone/utils/schematic/Schematic.java
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user