the start of something big
This commit is contained in:
parent
bbb73008ac
commit
251110c4f8
@ -25,10 +25,7 @@ import baritone.api.utils.IPlayerContext;
|
||||
import baritone.behavior.*;
|
||||
import baritone.cache.WorldProvider;
|
||||
import baritone.event.GameEventHandler;
|
||||
import baritone.process.CustomGoalProcess;
|
||||
import baritone.process.FollowProcess;
|
||||
import baritone.process.GetToBlockProcess;
|
||||
import baritone.process.MineProcess;
|
||||
import baritone.process.*;
|
||||
import baritone.utils.BaritoneAutoTest;
|
||||
import baritone.utils.ExampleBaritoneControl;
|
||||
import baritone.utils.InputOverrideHandler;
|
||||
@ -83,6 +80,7 @@ public class Baritone implements IBaritone {
|
||||
private MineProcess mineProcess;
|
||||
private GetToBlockProcess getToBlockProcess;
|
||||
private CustomGoalProcess customGoalProcess;
|
||||
private BuilderProcess builderProcess;
|
||||
|
||||
private PathingControlManager pathingControlManager;
|
||||
|
||||
@ -118,6 +116,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);
|
||||
}
|
||||
|
||||
this.worldProvider = new WorldProvider();
|
||||
@ -171,6 +170,10 @@ public class Baritone implements IBaritone {
|
||||
return this.followProcess;
|
||||
}
|
||||
|
||||
public BuilderProcess getBuilderProcess() {
|
||||
return this.builderProcess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LookBehavior getLookBehavior() {
|
||||
return this.lookBehavior;
|
||||
|
@ -26,6 +26,7 @@ import baritone.api.event.events.TickEvent;
|
||||
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;
|
||||
@ -37,9 +38,9 @@ import baritone.pathing.path.CutoffPath;
|
||||
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;
|
||||
import net.minecraft.world.chunk.EmptyChunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
@ -149,7 +150,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
return;
|
||||
}
|
||||
queuePathEvent(PathEvent.CALC_STARTED);
|
||||
findPathInNewThread(pathStart(), true);
|
||||
findPathInNewThread(pathStart(), true, new CalculationContext(baritone, true));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -184,7 +185,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
// and this path has 5 seconds or less left
|
||||
logDebug("Path almost over. Planning ahead...");
|
||||
queuePathEvent(PathEvent.NEXT_SEGMENT_CALC_STARTED);
|
||||
findPathInNewThread(current.getPath().getDest(), false);
|
||||
findPathInNewThread(current.getPath().getDest(), false, new CalculationContext(baritone, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -219,9 +220,15 @@ 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);
|
||||
CalculationContext context;
|
||||
if (command instanceof PathingCommandContext) {
|
||||
context = ((PathingCommandContext) command).desiredCalcContext;
|
||||
} else {
|
||||
context = new CalculationContext(baritone, true);
|
||||
}
|
||||
return secretInternalPath(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -315,7 +322,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
*
|
||||
* @return true if this call started path calculation, false if it was already calculating or executing a path
|
||||
*/
|
||||
public boolean secretInternalPath() {
|
||||
private boolean secretInternalPath(CalculationContext context) {
|
||||
if (goal == null) {
|
||||
return false;
|
||||
}
|
||||
@ -331,7 +338,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
return false;
|
||||
}
|
||||
queuePathEvent(PathEvent.CALC_STARTED);
|
||||
findPathInNewThread(pathStart(), true);
|
||||
findPathInNewThread(pathStart(), true, context);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -394,7 +401,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)) {
|
||||
@ -404,6 +411,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
|
||||
@ -418,7 +428,6 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
primaryTimeout = Baritone.settings().planAheadPrimaryTimeoutMS.get();
|
||||
failureTimeout = Baritone.settings().planAheadFailureTimeoutMS.get();
|
||||
}
|
||||
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");
|
||||
@ -499,7 +508,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
Goal transformed = goal;
|
||||
if (Baritone.settings().simplifyUnloadedYCoord.get() && goal instanceof IGoalRenderPos) {
|
||||
BlockPos pos = ((IGoalRenderPos) goal).getGoalPos();
|
||||
if (context.world.getChunk(pos) instanceof EmptyChunk) {
|
||||
if (!context.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ())) {
|
||||
transformed = new GoalXZ(pos.getX(), pos.getZ());
|
||||
}
|
||||
}
|
||||
|
@ -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 EntityPlayerSP player;
|
||||
public final World world;
|
||||
@ -51,7 +54,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;
|
||||
@ -71,12 +74,12 @@ public class CalculationContext {
|
||||
}
|
||||
|
||||
public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) {
|
||||
this.safeForThreadedUse = forUseOnAnotherThread;
|
||||
this.baritone = baritone;
|
||||
this.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
|
||||
// new CalculationContext() needs to happen, can't add an argument (i'll beat you), can we get the world provider from currentlyTicking?
|
||||
this.bsi = new BlockStateInterface(world, worldData, forUseOnAnotherThread);
|
||||
this.toolSet = new ToolSet(player);
|
||||
this.hasThrowaway = Baritone.settings().allowPlace.get() && MovementHelper.throwaway(baritone.getPlayerContext(), false);
|
||||
this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.get() && InventoryPlayer.isHotbar(player.inventory.getSlotFor(STACK_BUCKET_WATER)) && !world.provider.isNether();
|
||||
@ -125,14 +128,18 @@ 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) {
|
||||
@ -142,6 +149,10 @@ public class CalculationContext {
|
||||
return !isPossiblyProtected(x, y, z);
|
||||
}
|
||||
|
||||
public double placeBucketCost() {
|
||||
return placeBlockCost; // shrug
|
||||
}
|
||||
|
||||
public boolean isPossiblyProtected(int x, int y, int z) {
|
||||
// TODO more protection logic here; see #220
|
||||
return false;
|
||||
|
@ -58,14 +58,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();
|
||||
@ -74,11 +76,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;
|
||||
}
|
||||
}
|
||||
@ -129,10 +131,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);
|
||||
|
@ -181,7 +181,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;
|
||||
}
|
||||
if (unprotectedFallHeight <= context.maxFallHeightNoWater + 1) {
|
||||
|
@ -125,9 +125,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);
|
||||
@ -145,7 +147,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;
|
||||
}
|
||||
}
|
||||
|
@ -73,8 +73,13 @@ 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 (from instanceof BlockLiquid || (fromDown.getBlock() instanceof BlockLiquid && context.assumeWalkOnWater)) {
|
||||
// otherwise, if we're standing in water, we cannot pillar
|
||||
@ -112,7 +117,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,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);
|
||||
@ -131,18 +132,18 @@ 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
|
||||
if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof BlockSlab && !((BlockSlab) srcDown).isDouble())) {
|
||||
return COST_INF; // can't sneak and backplace against soul sand or half slabs =/
|
||||
return COST_INF; // can't sneak and backplace against soul sand or half slabs (regardless of whether it's top half or bottom half) =/
|
||||
}
|
||||
if (srcDown == Blocks.FLOWING_WATER || srcDown == Blocks.WATER) {
|
||||
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;
|
||||
}
|
||||
|
229
src/main/java/baritone/process/BuilderProcess.java
Normal file
229
src/main/java/baritone/process/BuilderProcess.java
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.utils.BaritoneProcessHelper;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.ISchematic;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
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.math.Vec3i;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
|
||||
|
||||
public class BuilderProcess extends BaritoneProcessHelper {
|
||||
public BuilderProcess(Baritone baritone) {
|
||||
super(baritone);
|
||||
}
|
||||
|
||||
private HashSet<BetterBlockPos> incorrectPositions;
|
||||
private String name;
|
||||
private ISchematic schematic;
|
||||
private Vec3i origin;
|
||||
|
||||
public boolean build(String schematicFile) {
|
||||
File file = new File(new File(Minecraft.getMinecraft().gameDir, "schematics"), schematicFile);
|
||||
NBTTagCompound tag;
|
||||
try {
|
||||
tag = CompressedStreamTools.read(file);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
if (tag == null) {
|
||||
return false;
|
||||
}
|
||||
name = schematicFile;
|
||||
schematic = parse(tag);
|
||||
origin = ctx.playerFeet();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static ISchematic parse(NBTTagCompound schematic) {
|
||||
throw new UnsupportedOperationException("would rather die than parse " + schematic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return schematic != null;
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
// considerations:
|
||||
// shouldn't break blocks that are supporting our current path segment, maybe?
|
||||
//
|
||||
return new PathingCommandContext(new GoalComposite(assemble()), PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH, new BuilderCalculationContext(schematic, origin));
|
||||
}
|
||||
|
||||
private Goal[] assemble() {
|
||||
BlockStateInterface bsi = new CalculationContext(baritone).bsi;
|
||||
return incorrectPositions.stream().map(pos ->
|
||||
bsi.get0(pos).getBlock() == Blocks.AIR ?
|
||||
// it's air and it shouldn't be
|
||||
new GoalBlock(pos.up())
|
||||
// it's a block and it shouldn't be
|
||||
: new GoalGetToBlock(pos) // replace with GoalTwoBlocks to mine using pathfinding system only
|
||||
).toArray(Goal[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLostControl() {
|
||||
incorrectPositions = null;
|
||||
name = null;
|
||||
schematic = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String displayName() {
|
||||
return "Building " + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hotbar contents, if they were placed
|
||||
* <p>
|
||||
* Always length nine, empty slots become Blocks.AIR.getDefaultState()
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<IBlockState> placable() {
|
||||
List<IBlockState> result = new ArrayList<>();
|
||||
for (int i = 0; i < 9; 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 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(ISchematic schematic, Vec3i schematicOrigin) {
|
||||
super(BuilderProcess.this.baritone, true); // wew lad
|
||||
this.placable = placable();
|
||||
this.schematic = schematic;
|
||||
this.originX = schematicOrigin.getX();
|
||||
this.originY = schematicOrigin.getY();
|
||||
this.originZ = schematicOrigin.getZ();
|
||||
}
|
||||
|
||||
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 (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;
|
||||
}
|
||||
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
|
||||
} else {
|
||||
// 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 boolean canBreakAt(int x, int y, int z) {
|
||||
if (!allowBreak || isPossiblyProtected(x, y, z)) {
|
||||
return false;
|
||||
}
|
||||
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 true;
|
||||
}
|
||||
// it should be a real block
|
||||
// is it already that block?
|
||||
return !bsi.get0(x, y, z).equals(sch); // can break if it's wrong
|
||||
// TODO do blocks in render distace only?
|
||||
// TODO allow breaking blocks that we have a tool to harvest and immediately place back?
|
||||
} else {
|
||||
return true; // why not lol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -239,6 +239,11 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
|
||||
logDirect("Queued " + count + " chunks for repacking");
|
||||
return true;
|
||||
}
|
||||
if (msg.startsWith("build")) {
|
||||
String file = msg.substring(5) + ".schematic";
|
||||
logDirect("" + baritone.getBuilderProcess().build(file));
|
||||
return true;
|
||||
}
|
||||
if (msg.equals("axis")) {
|
||||
customGoalProcess.setGoalAndPath(new GoalAxis());
|
||||
return true;
|
||||
|
39
src/main/java/baritone/utils/ISchematic.java
Normal file
39
src/main/java/baritone/utils/ISchematic.java
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 net.minecraft.block.state.IBlockState;
|
||||
|
||||
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
|
||||
* @param y
|
||||
* @param z
|
||||
* @return
|
||||
*/
|
||||
boolean inSchematic(int x, int y, int z);
|
||||
|
||||
IBlockState desiredState(int x, int y, int z);
|
||||
}
|
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;
|
||||
}
|
||||
}
|
@ -98,18 +98,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:
|
||||
@ -132,13 +132,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.get() && (command.goal == null || revalidateGoal(command.goal))) {
|
||||
p.softCancelIfSafe();
|
||||
}
|
||||
p.secretInternalSetGoalAndPath(command.goal);
|
||||
p.secretInternalSetGoalAndPath(command);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user