From 251110c4f89afaac13458471a8e036509ce52bcd Mon Sep 17 00:00:00 2001 From: Leijurv Date: Tue, 25 Dec 2018 21:07:17 -0800 Subject: [PATCH] the start of something big --- src/main/java/baritone/Baritone.java | 11 +- .../baritone/behavior/PathingBehavior.java | 31 ++- .../pathing/movement/CalculationContext.java | 25 +- .../movement/movements/MovementAscend.java | 15 +- .../movement/movements/MovementDescend.java | 2 +- .../movement/movements/MovementParkour.java | 6 +- .../movement/movements/MovementPillar.java | 11 +- .../movement/movements/MovementTraverse.java | 9 +- .../java/baritone/process/BuilderProcess.java | 229 ++++++++++++++++++ .../utils/ExampleBaritoneControl.java | 5 + src/main/java/baritone/utils/ISchematic.java | 39 +++ .../baritone/utils/PathingCommandContext.java | 32 +++ .../baritone/utils/PathingControlManager.java | 10 +- 13 files changed, 380 insertions(+), 45 deletions(-) create mode 100644 src/main/java/baritone/process/BuilderProcess.java create mode 100644 src/main/java/baritone/utils/ISchematic.java create mode 100644 src/main/java/baritone/utils/PathingCommandContext.java diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index 41fa36c5..358a4f2b 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -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; diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 6f0cf32b..a7509173 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -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()); } } diff --git a/src/main/java/baritone/pathing/movement/CalculationContext.java b/src/main/java/baritone/pathing/movement/CalculationContext.java index 725ab569..66ed3d93 100644 --- a/src/main/java/baritone/pathing/movement/CalculationContext.java +++ b/src/main/java/baritone/pathing/movement/CalculationContext.java @@ -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; diff --git a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java index 9973e94b..1faa5cf5 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java @@ -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); diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java index ba915ac6..800346a1 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java @@ -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) { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java index 5bc5b1db..09bdd73a 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java @@ -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; } } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java index fafba24a..81303be7 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java @@ -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; } } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java index 84e42358..b2fd416b 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java @@ -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; } diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java new file mode 100644 index 00000000..f01f7c04 --- /dev/null +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -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 . + */ + +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 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 + *

+ * Always length nine, empty slots become Blocks.AIR.getDefaultState() + * + * @return + */ + public List placable() { + List 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; + } + // + 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())); + // + } + return result; + } + + public class BuilderCalculationContext extends CalculationContext { + private final List 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 + } + } + } +} diff --git a/src/main/java/baritone/utils/ExampleBaritoneControl.java b/src/main/java/baritone/utils/ExampleBaritoneControl.java index 508a5e1b..53b93aab 100644 --- a/src/main/java/baritone/utils/ExampleBaritoneControl.java +++ b/src/main/java/baritone/utils/ExampleBaritoneControl.java @@ -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; diff --git a/src/main/java/baritone/utils/ISchematic.java b/src/main/java/baritone/utils/ISchematic.java new file mode 100644 index 00000000..db494c29 --- /dev/null +++ b/src/main/java/baritone/utils/ISchematic.java @@ -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 . + */ + +package baritone.utils; + +import net.minecraft.block.state.IBlockState; + +public interface ISchematic { + /** + * Does the block at this coordinate matter to the schematic? + *

+ * Normally just a check for if the coordinate is in the cube. + *

+ * 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); +} \ No newline at end of file diff --git a/src/main/java/baritone/utils/PathingCommandContext.java b/src/main/java/baritone/utils/PathingCommandContext.java new file mode 100644 index 00000000..1e8bfe6a --- /dev/null +++ b/src/main/java/baritone/utils/PathingCommandContext.java @@ -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 . + */ + +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; + } +} diff --git a/src/main/java/baritone/utils/PathingControlManager.java b/src/main/java/baritone/utils/PathingControlManager.java index f5fff546..97685ac0 100644 --- a/src/main/java/baritone/utils/PathingControlManager.java +++ b/src/main/java/baritone/utils/PathingControlManager.java @@ -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: }